From 94a39662380c39860932340a2b5c4f0ca5f3b6af Mon Sep 17 00:00:00 2001 From: github-action Date: Mon, 30 Oct 2023 11:16:30 +0000 Subject: [PATCH] Update sphinx docs --- .buildinfo | 4 + .nojekyll | 0 ...6766984f34b93a9d82f4bb29530f62cfc702af.png | Bin 0 -> 14709 bytes ...984f34b93a9d82f4bb29530f62cfc702af.png.map | 2 + ...34e46f472445428ec0a3908c62f907b47614c3.png | Bin 0 -> 18160 bytes ...6f472445428ec0a3908c62f907b47614c3.png.map | 2 + ...1eacfab8eb2a42215ddeb7564c51358af44bb0.png | Bin 0 -> 20688 bytes ...fab8eb2a42215ddeb7564c51358af44bb0.png.map | 2 + ...da9712e3905cb30d4ae47e7e62c2a1e0fece65.png | Bin 0 -> 45619 bytes ...12e3905cb30d4ae47e7e62c2a1e0fece65.png.map | 2 + _sources/developer/build.rst.txt | 48 + .../developer/contributing_guidelines.rst.txt | 145 +++ .../developer/contribution_workflow.rst.txt | 40 + _sources/developer/dev_environment.rst.txt | 35 + _sources/developer/index.rst.txt | 36 + _sources/developer/style.rst.txt | 157 +++ _sources/developer/tooling.rst.txt | 80 ++ _sources/developer/writing_docs.rst.txt | 47 + _sources/index.rst.txt | 21 + _sources/internals/allocator.rst.txt | 110 +++ _sources/internals/index.rst.txt | 13 + .../momentum_rhs_calculation.rst.txt | 88 ++ _sources/report_a_bug.rst.txt | 11 + _static/alabaster.css | 703 +++++++++++++ _static/basic.css | 925 ++++++++++++++++++ _static/custom.css | 1 + _static/doctools.js | 156 +++ _static/documentation_options.js | 13 + _static/file.png | Bin 0 -> 286 bytes _static/graphviz.css | 19 + _static/language_data.js | 199 ++++ _static/minus.png | Bin 0 -> 90 bytes _static/plus.png | Bin 0 -> 90 bytes _static/pygments.css | 84 ++ _static/searchtools.js | 574 +++++++++++ _static/sphinx_highlight.js | 154 +++ developer/build.html | 155 +++ developer/contributing_guidelines.html | 254 +++++ developer/contribution_workflow.html | 150 +++ developer/dev_environment.html | 156 +++ developer/index.html | 151 +++ developer/style.html | 267 +++++ developer/tooling.html | 182 ++++ developer/writing_docs.html | 152 +++ genindex.html | 105 ++ index.html | 134 +++ internals/allocator.html | 200 ++++ internals/index.html | 124 +++ internals/momentum_rhs_calculation.html | 193 ++++ objects.inv | Bin 0 -> 622 bytes report_a_bug.html | 118 +++ search.html | 124 +++ searchindex.js | 1 + 53 files changed, 6137 insertions(+) create mode 100644 .buildinfo create mode 100644 .nojekyll create mode 100644 _images/graphviz-076766984f34b93a9d82f4bb29530f62cfc702af.png create mode 100644 _images/graphviz-076766984f34b93a9d82f4bb29530f62cfc702af.png.map create mode 100644 _images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png create mode 100644 _images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png.map create mode 100644 _images/graphviz-981eacfab8eb2a42215ddeb7564c51358af44bb0.png create mode 100644 _images/graphviz-981eacfab8eb2a42215ddeb7564c51358af44bb0.png.map create mode 100644 _images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png create mode 100644 _images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png.map create mode 100644 _sources/developer/build.rst.txt create mode 100644 _sources/developer/contributing_guidelines.rst.txt create mode 100644 _sources/developer/contribution_workflow.rst.txt create mode 100644 _sources/developer/dev_environment.rst.txt create mode 100644 _sources/developer/index.rst.txt create mode 100644 _sources/developer/style.rst.txt create mode 100644 _sources/developer/tooling.rst.txt create mode 100644 _sources/developer/writing_docs.rst.txt create mode 100644 _sources/index.rst.txt create mode 100644 _sources/internals/allocator.rst.txt create mode 100644 _sources/internals/index.rst.txt create mode 100644 _sources/internals/momentum_rhs_calculation.rst.txt create mode 100644 _sources/report_a_bug.rst.txt create mode 100644 _static/alabaster.css create mode 100644 _static/basic.css create mode 100644 _static/custom.css create mode 100644 _static/doctools.js create mode 100644 _static/documentation_options.js create mode 100644 _static/file.png create mode 100644 _static/graphviz.css create mode 100644 _static/language_data.js create mode 100644 _static/minus.png create mode 100644 _static/plus.png create mode 100644 _static/pygments.css create mode 100644 _static/searchtools.js create mode 100644 _static/sphinx_highlight.js create mode 100644 developer/build.html create mode 100644 developer/contributing_guidelines.html create mode 100644 developer/contribution_workflow.html create mode 100644 developer/dev_environment.html create mode 100644 developer/index.html create mode 100644 developer/style.html create mode 100644 developer/tooling.html create mode 100644 developer/writing_docs.html create mode 100644 genindex.html create mode 100644 index.html create mode 100644 internals/allocator.html create mode 100644 internals/index.html create mode 100644 internals/momentum_rhs_calculation.html create mode 100644 objects.inv create mode 100644 report_a_bug.html create mode 100644 search.html create mode 100644 searchindex.js diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..984c8ac6 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: b34c3921138289cba751d4fc001b112f +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/_images/graphviz-076766984f34b93a9d82f4bb29530f62cfc702af.png b/_images/graphviz-076766984f34b93a9d82f4bb29530f62cfc702af.png new file mode 100644 index 0000000000000000000000000000000000000000..97f4dbbfa1f8589a9a24f8f9eff98a5742d75cea GIT binary patch literal 14709 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 + diff --git a/_images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png b/_images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png new file mode 100644 index 0000000000000000000000000000000000000000..3b6c8883a7eb2aeae8e481805ffb661b10f71544 GIT binary patch literal 18160 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 q8kT5kDGGqY1c7hgsYivwxl0t>1BVj5d&8#de zKBKAX>Fay?`}?~edE78$F!#4LB`xifJiD7W5Ej7dtDjlt_wVqb`He2BeEmAPhlfYU zj~@%m%j;=37YccKc`57midwR0yDu5#i-aj`-L`ETg^vu2lq=J}(9C66PsBpk(lR8$ zeR(^2ZwKzBz3<_f@m4jR&wCbA~yYUA{d&s*4CHlc7fO4tQhwE{%xE;@9$56;+G-dp`bvq zlVYo_1yGbZ79`k5@XHr3GMAT~udAq35L8t*gi1jh^qan-6>*fVZmhc{d;6&WLene0s(T<)oQoqaFLnsKYqM>@nU~l zM@RLAix)f5(;Lh!EHr>MGu((uN|d_GPmc$@&&io}am$|s0usPxxPx7tF1vR+Pl8vC zgFX{Tk#=$Juv)rdgTzdbjEkk^(JiF_A#4XEDw*PP(k|yo+*(pTof;&VYgn@**Jj{c zTTjnd)Ua@OHK_;gIxpuEHdg&m!)P8{G)2YVOUkcewkj+GQP}le)UvDkYrJIYxAplS zR&|kTczi6ZDv+gUQ15rSxyGnYqbR_)N8SNRyw&;`nO{&KBr7X>kTFmL1@9CZM~2(H zQbsMH*WscYX`(TrR*^@3l$G6I11RM`ems1;kBqUtemR<<`i&b;o0c|KwP#Jbou9V% z^u$ZfwWy?}r1%R~cA#YMUS3A`2rm}J5V>iaq#qX*72dOF&wQ6%gAHr#L(yoe_@3zK zXaPydBKh^c3uK}5OrvBCMJ@}59%g6Db}}+nK2J(g-M6)|aH4qSO5auI=UP%LqrwMw zQEJG_ZfQ@XzEz+;39?Oo4=_t|Iy`>Ej`;0kOcX2t@t{3J9Zm2&sHKpk%_~NxK-MNJ&E7VeBY*vrq zB`dm>*450$)(GBX$4qi_bIn`dsD>6w1vRpgv6z8O7y_r`KLIURr>f)4w zf`atTn?LTQM{m71H_~pfJo`uB#EH)+Szv;jKo)(LZr{Ew;4*K1DM5<$<_Al+7FAC1 zkh+F9uXuM!0JyEOE%=!Fsit1PFX#)!L$lD40p(WHPj0!ir>D663`LpLhf;n0?`n7ZcvdwvT|IT>D3`7K z@}EPUH9F`md^eBoNz&Tkgj>zb&HXJ-{agkbjBXHb&SB=4nw?`e$@>BN&w{7Tk9QxA zY8W3M&$I6Hys*qs;1}4yr?!idjgF2EWFy5@PVcz_S6FF9g>0Yk%UTJnaNQt1tPs9G zG0lxf17fk2@uJs=fIlU6K2O)*7s<-CmoHx)oS$@Za?<;eYq9osf_-Cg8>qhZ@HfuM zrB!*Vcxv9K>uI*<6MLVCJMit_u^sI{&)-A=vP){}#c|)~Pp5y!Sn1b>^H$f^{+*#Y z74X*qZ2QO&8kOWLgW|iM%jjn@Wt6OoH#IkNMqCJc@+9Ep#i;V?Y6_Iz*Ik8}3?4o{ znOnDb@dGvkl{Bc;3;7wWr|$H|-R&u}Dp?~BQ+Q!LFfh`dk?K6>Puuv*B*KicN)VGn z2Hl2$ZiEuCN04SOSD631;KmO>-Klo&+<9gB;0D@}C#a~Lyu2MNr7|ZNUc>1PmSZKW zLSGY3hlYgEUWyjjlzb)bDv#v{^G?sjMaRX(MO`qI#o1=XzJUQR6jt5oUp3iF1v7JH z6?7{L6KWfj3~?`O8u&>24;e}6mTjhgbgKLN}b=1(pYMSgdCoVG>*foO&5G`uO_DNrG z>*h_KUS459lFB)9tXHpIwf@_}Te$Q)25(5gDXw^{jC&X5)YnrJy=ZaI-mSD6f;)lq zA3S)jFaPxV;udV~bH>I8=O=!KK6pUsx-=N&I8n6VEU}enYbc^k8|@qfP9iv!qQulz zPfyQ0T0cmv@lBrFNc{r?f@W>}{8|OO=H}*}2HmQ5S(|HD*3mh3s*7_MWglSPM9D^R z)fsTZf>Nddb2ZLCrz)A^UB*v#eY{HtuEp2VJ zabo9knoms>dabQ23{my@TD7&8= z*BN(rsmP;RZ)OGdNUPntl?q+d+sB8KlXDZn$EV7vj#>W$rq8<_btIKGH}6DElh)Pc zc%_&S@}b8$a6JEnboam{i?}^S>Dqk~cnT$n;KA6(Qym7OeKm&?yrKMFPgB27fd1m* zV$2pN3W z(+MLFiBbN$a3uT7moGLbP5&&-xmL9>Y;cPoxttsv(yUW|(#CBZo%{d%34lVulOuob z9ABJH=WtX}pKZ=XEj0~|0Q6K&K|uy$hejT`>D(nO4~bWJ`MqBTssRCV?AXtTy{B}FZ$$5!<>1m`Cwi_fj(Bjadpl{r$bj_OTD-6%ygX6UtC(^Ja&wZ-D6d7tQDrl zk(p{TMN!l<^u&Sh@6G&!gFiz64pvS&*N4AfX1VxZ(F-E<;OLWf2g}RLbV`J0wBOZKv#BPah7!X-Tb&R_h8THXy7e{n99x!m9>xEoJh-0eVtepF}BQ9h? z9U$aNJv}|t3y8w!&!3-MSQrwQKw&9Ta>6KdcJBS@zH;Qkg$t9lhckMy*Sw*-0~Zm> zj)TKR|61sUeMEbK*qL=_>;{BsE>Y1vD8Dk+)&dX%Whnk^d5>E%H#g68Uvt(hac6~a zC}(7J01rTD=!6m{*|Qcye-!Ei-N(BV=b+VqLQFy@>bLS(VYd8P91L-ziH%i;Vz1${ zByEEDqqG2agqWLY@k69=W&EQf)(#ldgSJOpy=ANZeDr}k&_U%H2o4Ij_MS5 z4cJLk_6^&?V*#Hzr?1b2Li{W_*$-+Yzee^};94M!bQVWIM2bzwTgdgqI%E)2(ki<&QB2X1Ole^6M0{w6?bXBS5m8^dvM!W)bsy zF)_@>U!MA;r0~ee$(2Id8F^U4VT-;`)K07_g7y+pHUOE#OuevwNXR*9X%eb_yB<6^ z<(+SN9oOq?YbjCQK9&1Wftd!(&f23F6N|kg*Mb>Murh@8@Q*FWVQ2ufTeFHZa)EA? z2JAfaAAF+_Q4q`nO>ATXt35sTQLxVi*5?fo_hwz}fx-?-rc64-b;QB=4Ae@$=p>06+>9Pl3 z{2XRs6H@JACo$V!6t~UH5|fj+fwU726(tOS z)9M-;HihIb4#CC*U8%0AIdlCwBi_{-Iyd@m>8DRyA?Z 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 literal 0 HcmV?d00001 diff --git a/_images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png.map b/_images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png.map new file mode 100644 index 00000000..807658bd --- /dev/null +++ b/_images/graphviz-8034e46f472445428ec0a3908c62f907b47614c3.png.map @@ -0,0 +1,2 @@ + + diff --git a/_images/graphviz-981eacfab8eb2a42215ddeb7564c51358af44bb0.png b/_images/graphviz-981eacfab8eb2a42215ddeb7564c51358af44bb0.png new file mode 100644 index 0000000000000000000000000000000000000000..459403b574ac58356631dab19de914f574b5a283 GIT binary patch literal 20688 zcmd_Sc{G=M|2O(olFAqfWvnD+R%A-XLP(N%tSFJ0jFovxl8_-ol7xgzN#>+Xl_9ed zG9@#`d0l(o&-47wIe(mU);epQ-&$wi-__pt-dx{n_LklDXpuy-#yus7JS>lP+#$EsM*;kS9j&GWot~h8N|*ki8rf1(in{&SD%vTa4n;H zm6TsJos^}^w6x2}fXRVu+j(U<{hEj5l>S~mzRP!o_j8`&Bx{+tF|9D&IGQ|nJa$cX zsW;l`M390aIfb9OgZ;-Tl3$e&4Z}e{^Hd=R5oV^)m{K;g`Q#rzEYP7+QXp1AAU6HU6AIOgoqRFd z&zw19ef8>X)eL;(EiLykZV#}lOieX^>&37=fNpyL4i=Q2o<2R7z9yea#~nqvPdWUi z4qt#G_bvRX!&etfzmMXBIK^A@^de1VV`DZ|HMO$_2BDry)2W4pj9V z+J4Q?*N(NN4^2%`U$}6=zI1ZivpgXOSA}!u7(zosIinlxXZmIC$HWk)c;LVR-b06O zsb;iyOG-)AeEP(Yo106q`)B%^c9xE&kwV0)SI7GLDxW>ue)QjH8tID+^E6 zE9QTeXMZg%1yxp_*tBVrkn5ygS65eDDbJ5@S@c$FYCG(DOK#b8=5mRP?=CGZ<>lpV zb&<-@&YB)}pO>GVoh6HG5G`1$i4G0jUO|yR=XB-Dp+W=x=g*%HPE3RyI`@Qg|9-_{ z8UB{C8tp{B7*$Pw9Hhj1?U)!Vb*+Ukk7jcC-Me(;Tekdj8gp}=SJ#IWZasLw)VEK` z$LGzoZ&!E1?BZevgN?N{Z(>r?$H}5`7N%hxUdH92AP)Q0`70MMU*d z^@>SfU;o{Q54Ck+yQ5-a01A>Do!#Pfvi2sz)Vct1BIW{I|V#2Pit$p|5 z!_eMdBl}XL<+Zg5gQllXc~9-%=~Vt+NR%~#qBGC5b0JMcRJ5(Nm6W9uI{L_$eFxK# zx36!^1=e1q3fq-wB+xMXts&~cgFuFZ8Y#G_Z}kxhMn-!rEG=hyom$2}`j`uar?y$! zPklX_D1Bq+l`B`4XB#-GzReQnUs57bTUTe^TjKD;^%F1Cf#&z`RrgA}(*@D6RnwmM zlOh!|H`=1&<@LHQS+Tw~wOsjxurU4U)2Au7Zx<;Jll&mi{NxGGURf_@?7X_}0xR?D z*CPXV>>du-ZSuCa)X6iEtj26U2us%JjTZ~PTEhJo=X76rPzb|8?n8&RH9g?RB8=7l zD;g%z)6+v-h4*wLNnf+I-P&`Y{u~Yc(C?9^uHx$)G;EUo zU%wiBNIcHa6f4-!o}u<}?%W<~?(^r*7rIR7vdVafIg}bbJnqEfjn$xIY%CLJC&Vn1 z)@D8SIqO`ZhrXhy|skn`XU#|aJG$b$m0YO=Dj^Hp0psKyqgIftd4eo)C^{nQTGkKvZ3 zh*~vMDGE~s>htpPrHS{u`}xarMX(+Xy%!ywm6P-F`$(KlqPSge3KkawDfG^rCzF%c z&RuR{CVyqyqfDYCm6n$$^!f;S??H9FN}T^i8ymI${{BLzQH^L+$!^0K^uib?m zB=$ZOwxmdsa%*Pn7Wr_>-roKZdFzF>b)mRR3xUKBl{y|E?x4t}?MX789s5@nZ752V z)2r}BLJq@&cp#0R_>a35df=c55B zSy*uY{{5Tc`3Ee)YyGcTEbGH>p&}|*#tou}sB0W~4V@24u}Rf^pP zym!B?X^2$$Wa>3rXYy#Ex>_FReewuX4SLhrvu8`3$F=h!XU_D6cmH1TLdoEilw>va zUWhrFQmBHB6?w7`-Ntk3o7~{w;7#Ll*P+2GzphH(6Wsguxd?_WJ?xiFJSHZlb@Af< z5JhfDujLn~+1<~amY3f|mQq`*_`bQBCqw&mx!Vj6iE+;!wQbwBIinzG^D^E~OjIXX ze|mDp;|4lFG+IJwNr{$$0qY^g?PV?#OiIei_i}Rhjo)~6f4`)wqjNVhl9u=hRn_fB zj~%lU&N9r* z$<98U@%XV8`sjIG-FA+RWtB~GQm&I@uZ~10Dm+ocB{a?%hR^?Ua<9 z;^N}(o0=vT94dCAL}q54%e+@!F4c#+8IrX3l%(L-!a}i%`E3k5bfhx-q1z^9xU3Zv z;EWuDqEHgE(c4|ScGZr~9TF4!{Qc6K-|r8T-&~v-$cyd&`c*YuIfDC^oLo#y48^4< znVEZJXb);6a*_&t{(4l*fB2y8=;k)FFyl~FRYiU?*Qhit*5_M2^(Hy|e~Lxpy6)IA zm#^&7?yYZQQO(~NI&^e)o>Nz+vh8|tON{kQ-p|W4tgNioi<8~ozkgS}kY_UWML2So z6)rx&-~VoLadBHmm-g6e>+EOG=G#Y`lhjD3GPK7tf&v1fPVH}3V+gCO9dXRc&u`=0 zK>yq%cj?k49zg~YUUmOL;)SG4s4?v#`)mkt^{Q`OG;vIm%l@pFMjkK ze(E_@kIp$P|1y`5kT6^MJyQ0zr+!Q~@x-5Bo7d+vPnh?-vW=5;`FT^~>XrRGJo4#n z%xn=}8-JIEfCD3xE!#zQ^Ba(pPN}JVQoE4-MFP!*d=r_4g~jUqgO6GoRu?AD8XHGU z^%Psq^jCDfFjsiweU2}t#OH6B$=8nw;%5Oau_a4NOBdX|On-JG=kbTNXQin2&E&_q6EX*jVu9tu&lKS~Ha!K1+f1t7T|;$v1wm zJe2W#)n-Mb_IOVJc}9kkpbQFuyL9p`Z&aym0rC}v&z|wIie9E#SzXok@Q^%;`ekd& zf8gN3=%l2iDzkt??WSDDyhWu>KOuU_TDvOlY@&r-3zI`MsYIBh93HUDMvqZ687EMk`R zR99_nr<}Y$R(0eUHa0ik!8*7;@0mXQXS#eQxM^hZN>`_mQK_SnI7^w6=R{61DpV8a z--@OF^zd*hzj?R*8!EA;IAz=Z*YRH7-i=?sK76cw2=_8lBT4e8*`@a*j$cb0_N^>0 z-z_RS8d7Hw8WPgxnb4pY-&dF;*^z5(6!hzG_c3ZinAHz&0b<}^c__Z ziXg$tKRd&i_-|`xDLOie{G6D`zt{-mS~o^^@Zdr9gk#h!EG!fQEYGib|6O$H0cX%QA{D2e`~aQX6+lVw%Dxlf)1@?Vxz)GxS9-SJ%C z(oUS&yY}P9k7NEces;FlgwJzww$>e@@SC;2^#d%)&v~;0j`?!ny1l4+%dO2@ozHDM z!{RI@Bg5w7K7ZW3=01wM|A@DusH@7{ z6?MuV&G=!)B!O<|D9JA$N|-fm|McnXg$qGjb}%t}Sve1{W#_#KmGN9mdG*TmZIWf& zRvz`H!SqPkY9MQ2ura@x@X)#4mCIW|;shwDYv!FJwtYTI(lIyZViGW-%-5qz)d~hf zNv{kL4ip$4AD8f4JOcb=`;DUS%zL!sgWxJG{#j;mOqSQ<|IB~V{602zYI=Iw`S-tm1|s3PJkyHX({Tfq@jiXJ=C%{hhSx`|7+V zI||H2&&C$9>#%ML2>s2kG=aiCYdr&Lsi`MBNAin{RkXC|T&KQ%nOY0Q-CL5EsCmi7 z{d)1MjYk__ndsyLutoIGOycRsyL}I2t)EWhjtVB-l}{CVK?~O5F*->**?hd@^<1+Q zil)**&E(0p+yS;8 zm5H!=)!IyDB=w$SgQx-oz~rzQ$PS*Nr>B>2`N=3?`sUBYsB9K*?qkQ8NcMl09V(nl zjcDT4FVn;_|4pf=V9Tpqm-LxS7#PF`-1F*McYFEfwe|}S8ZUmInbAbAO$!eX_gN@s zp%q^IaAUNYjaAsfzu(%{$49oVw)Sp8f#{wbHhFB^o4|dI{r$;r)~3s4*?LA7j!#TX zT&cRfrS{wG*i`Yrlf}iwH9Y-W;qK^q&JuZ34WF%0l?WDE>XDuSb-ke@!n z6s^OT0W9+}WJkDp3$UN{&(B%lSk|+{b!E)uPu^Y}o_t(Z_VC!XE;%pRN2uK6O@ftP z*PIAees(@JuwN&R~yk;YHIv|f9o0=CirdNn(0Z>vP-9+ zcLafYoW}R-<{BO6Rg0l2k&rr@{iV>Vh5ezdwmL}#WtcRN| z>GMY-$Efrk7!P)R+n<%W@zzv@%kkGNow?Gh(u#_9fu47jy9uHQRgF02n^kQ(V)%** zjYL$Bh|sW06YV~wtPGv|!&~t2d{CEkuESe*6ok&5W!dmPrF|EvxI)9ih=YJU8kN|S;UuFE zYAQoBU^=3A6ZjX+%BegnNC~GVDJf|`@_rYv-SGVQClv8pTD-O28>3y^I^spGURpa+ z$>3lP{|ZOL!*yYVK&QxkQb&hz_}jPH>K%e_+uGWC?G}UU!U_)8)zwMd_`M&}3;`H> zD}6bD6hCEZswgUwSJ%`K+DpD%qb5CoFgD1$ckkYUv^$KqANc&`3zz^Iq$WyQ+J?#Q z0%4b*I`*ZSVoAM6sE#|hj$pM%PCvRA6?H2ujayG&pG!!H?%Wgglc!Em%FD|O-T3|e z;G>%#UNECApViX3iM?f1?n({u>|IlnA0$;2iR$WVLfwJpr2bHBn>2e%ufPdm1(QVM ztmn@am6a&~_@fdM!tkp&n_EpI)h#WwfWne(8u;;@A+@~%qGcyDv{O@3NS(RHL|X%f z2m~e|*2$(@q-dTq)xd>xtgNB9br#SGf4Fu(rjl}CO@IA*FRs_a&?@*ex;&m4fb{NL zw{FD=nQy{I6NY&3YsE{{bKP0X)HL$XA1_8m#*~s0y`>dwFzjt;vMToWLOkkmH{ZUM z^A8NPz!tAr-2DoPLvtT z`mTqr*e=Z+iE@Qht(2!vDFH7DWfCebm~m)(yLQFRW^j{Vzkj!feECq{9A9mPS_r8DsehM^TFtew5d7W(EfS}vbRce}= zb^x*bM{%u>+o>v$&|}OTyE((i!m1a?h|j zi(p0WSL77|Z)=aM<9A;a71c%UQ@MNhu9=-1Gtc1oo=uiQft2crRDl82wT)(ay#Iaw z@mkDhuJ;QQosf2&*OIbz2P!;w6C3XpiYy!yzn>iG8!zgdf_NdLO8ER)ww#)roYXph zev7B)+R0y`=Bj$duE8&_b&J?bB(mGOOS7ZK#R~=DiWTlFg)voq{aU87Cr397K#uC3 z3e~xq+T)7!A&S9~kuzsg04`92Srqe_pZJG3QAXdt|5%)No)@IbeLN%9%+gZy9iY;d zJ#?(q@QI*j^Tw#A4?L1`qba!jk<}=Zna8j1c#se(rr?|9w6^keh-&WcB`mKk;#}j;lM*?Zp~aYkqrvk z+V@O4JDQrpwmC85DO2gax)z^nV}k=himZE0Bdop&N7)=qX<}jmHn*7sI#4|@Fz~@d zcy&j)6U}Ccy)@{@+emRhgbY7~ZdJrsaG~|$gKH2I6C0CtTMz8+@6TQG7GAN7-fAvs1mTkH0~}eEJS{ctr=ntRzAYy*Yx-LXeR0^Y^)bASFb1ZeE#eYNxkol zYKF-2cpWpIhGf3v@#92WK{>d4YX4o;4E$;D>Kce*w0~!ao#$r`N@;M%86^5sI0gpI?97zzQyy-6CJF7#pe8W&?n2 zRcsbjVaxyY^4gCw5&MxZ#v?)nQWXl_0xNT=QEn_pY!hMI1qE%DmXR6yw=`FL{PLx! zb6sW%?pP{JLHI9$>O6kxJPK#e(ys&7q&$C4g~LgfV|QBo>#X?~7mMQvE^bV_ckfQ3 zgQ@dTFX2{3db)zgxg*>}_c6}7}|h8^Dy6h|hV_~rAV&)|4f0|Ok`7DQ!*zF9se zTYc`326uH|xtjy1T@t0#mhSF4#t_9{b8~($yS%)-<_&xW1qGS(Q)ml|iiS{gu~t4U zNWx~E{iJzfXmP3sUr6!m7faW`fNAj-a&k^I4;V0BdU``2GONwiPM zfC*>6egE!{UZWl-ME2&*o3a+v(dWB3_CxNoUz#>%+`W6>i4z=Kwrt@Q5KumOlFY!s z!0ghcEhkQ#z$*Xw3TOr;J-%mw>{3@qK}iWS==HniW@Rv*T+>RL7}YI%_UwUQ#zpvQ zXA&hGx;FfRM1Vg|{GDfTbaHa(fuh~o)kO*Q32Yqp8#&f*96S`y*B}|RGT|G)FK*_N6>ucg{2uq(e?#X5O3l;kY^;vWmzxtq2#BYs zXogNbIJfe{btQzwaTro74^)tVu-$^(qM{5%MMYp!#J2$*1=XDhXcG^n#0~O@aK3Tl zIPo3ctIohC+t=McptTjNl!oKTXXjch6AKCLyIXt+3pA&*WR#p~)DGdw_>38nD z{U7rS+~C@az_x<`e=gL2;9j+MbOeGl{LIZlXJ}9s-Fxkbaw1yUa%bgw02a+Rlqc+N z_vzA6Iu4FVg8M>V6e6!f_Q47*~{nuKe7ND>wf`Bs~(?@ zzI*?^f2@heHsG5dPT>?Rpi7w=Nog5svG*X3VHv1G%*C&3!-O&`uQ3}VNE4o_$5c_L z_4jvCP>2t4bKhQHY4O!oQ)^0D6SW@J$QB{i-IDn(yQ_Yy~8CZV+x$K0sEO-ltw7cBQ>p7Z;y~pn@d&%;fyp97Mk!-CK zVdhDH_AK<3U7spDJ3H~Uva-p9Ha0jy6DP4_$Brw2{h+Mx`udUxiSw+B%Yxjl1~V!N zeB+yyAA24ivt=bqx$@~r8`N8h=hD$(1<#*{Ll;tjRWAmU_A5LPtgZMmW{R5Ua2ewP z{N+g2_zCBg-aQAFf>)xPde671eE$0N>h=NV%ljoHN;Ef( zWqbQFe|YJkhBbO7Svnrg6y)>H&!0b6ldLMAbblWiF|QA2S^kpe6JWajJGR7gNub|r z?#!{gnAy+7I)%_b2(70YAdnD>V8FgGy&)SVQDndmzb()z`340VN{Q7!+{KBM?W2O=zo2KfuJy`!o(uxH+&W6y=fIS`0bFr zvmxN~0|DdhP_BroJn}vUxUQkXbLj=BB5)OSWAmx6MFbRE`SSVm;79QRqGn&ab`9cN zR9svzpgGy$0-PFnM17pFC1Ap4oJ(ze{V=v}--AQZjV~Y|hVMPDE%>)>s?Tj;%dcM< zBmd7WGlBU`Vb~{@T1$ZYCTkK}wY9Z_^$~ke{|R=6;@w$H<*{b(0pjLpZ=Zr{685J; zgp2DINekBAB`d3F?X1Vx=C2bxDIezNozq8$YC{;vZ+7IF=EWw*$DfAASh4;QZc!Ym72fN7`}N+ElO$dV ziLSSAvL)8Ei#2*sy;zrj|CwuXJKVgw>H*(Zz1lb9(|LHUAygE$ zA?ObrU47>fDZ#G*RTcAC**i&y(s+!cnE(OJwbsD;OJN{@Tu+J6Atn-MV#aGON- zfL-w`az~wf1Bgd5n_tPwY)#xFZl~zvBuYq`BsuKb=46>Lmx&G+&v0SMM^@$SEGJV$ zA7==!Y8N+jv!=u0-mzN%U%&MZn^Yi#<@uiyPIEuA^M(m6^U0Y6WKq7R+ZGRhzFMSL zbafYKl>Jz1D%UR0k<;kw_Rh}!F)_O!JDjBT+(luiqjUds6JuB%6w;%TTF|<-ki75Q zOTK@f90<+pcjG}YtgbiS<*(mr=iIwI3_m3>I-0@6bE;@M zB7DIGO6+OwsMb86g~JSsueLsDw#v^HtgElBr9&d>MPzvR{#31}u>k!_2o7+WnwqL= zYGy*u z&=q+~PiG691T2DmsK?Lp@;J0c)vK^CougBwii`U_!d||7N!32!IV1D_-8-REzN1NQ z&MRNgReyX;Xzc8ag(GvCFQy%cZ(buMtLc8zNTI_wW%vSIP-qE@pMgQasyT5y|AXCE zT{c9wsIoM!#OO&wizl5N_zS~fBw+z-W`P8(u+Jdo4_skHk|@qtK*rP zVp0LZ5|1-8_sPn#BMS!u`O{kSV7w^Mw%c@XRp_q66dzC4zrCB77!L0)p@&+T7A*s* zzCqvxSUAC=0I(2I;zTaJPmyR4Vl(wwIRH>c4hsnnjIfv+?;ZHz8rHU1nw=H}2LUj# zsddg9t^2EkJl&hYmHGwUb#6LjLpD;X8UtoNg4tCj_+Q|3T6>Q> zJ|4Iv&Cnp^bHCxPPgL|Lv%ma26UcEyH_s#j)%)$2FS}e_ zT?yUujrUq>TiY$uzdtYdO}BgsH4;#9bv=g1O!Y>z?Cx1)36KXsnL5TxBjTay>?}rP z;J$v9)=x5h77tfb-$R1N$--Mlhs1x}eWxMB846R3bv^u5m@cs|x*$JJ5 zd)F)fGLe3D7+$BgJ{}(Q2k9jxOH0e8(emZno$M*5g=QHiYDHr=@Wyu7 zL_Ga4(hpGQi0H<$9Zrcj+ne=M$=zjoyhC<`bnmop=}PYiucG7MGucv%bFJH zW88&uoJ2wc>TLkbzkK>$vOp~P{X0`3IU^=JxK>ss86C3_X8LCnz5xNn_5{uoa6yeK zJic5U5n^xFj|>T^!v1w20w)|N*7F6gWuj_+08MJ89&2J5n z6B$h-j))9J-=9VFj0l7-udmH?SD)Mb0T5mYl$22RM_V2>V83{}nVGIOu|@x*i_Ih4W9as28x_@KkSj9dJXbj!AEv>TzpD!uuV2@Mr|h%RWcsqSES&2k zitpbML0_)x*RKydmNIg1Xu?$%yRuXyMWK|K1hu>!nYKfmoN}G3*ZRs9@)>TjgjYRA z=7QkF&^LI%iFbx57TWbm^6~OA>zoJ=Jj7y+0!E}Nz>tQ24b?ygkCSo}cpzwc2S9}- z>DNays{L$iY=j=MINcXE^Ja|(Y8o6Sy*FORcQP=1bUgD=DKQd&<~G!X$-eU44Urr{ z0APf(g?jt}DU&TFm#LVs8(=vqBJ6@^?3)Uq5FD=IUt_LaR?y(uRm5~vva+*liU)kc zh*E|h_t(v?Ln@2tmn(ClfIeNl0wRGDa3fILC7Q0qYY*e> zKav!_^0q-vU|yc!kCsP~&~QFHJeoalc5bU57guvGdhtFqYvP8$=W=v(Olh+gy8MBe zIHZWkPTU!*>vbHni;=Aqou$_~-QLj=Imyi^&t_IuTT`_t3CpdgM}e2|=VE|77pO5rO)ff0 z=Ns@lD{_rH|1K`NR=jxFH)T^~Ksa!zT5@pUu*jhHqdE{Dz8Gt3>zkN~@%FB$3LWK+ zI+Z7U4?@0+OF(&fxkfO~8!Sw$`-bmBGZcMzAym_1_;tj+<F8iWiu$Cy{O!^{^SGOtZoJ`DFYMzaSg3Xc zghW@p(E9KDkIz3$k-jx9BNKibXrj*tIEZA1)Hh_m(B!F&^_dNMz8IQkzTxXNOf76_ zL@cQbF{x#*Hv$pCgb22Vn`-amqyX)}MAFjwZCR1R{Yy;`$lOcPTt*@NJSlGZHv0l8 zTb>VG+hHf2MH7Hp5P*;<`xMCLozu}g)b}n>ovWTsRA3Z{CG54g_4Q8-699cg%xTQy zB!YyH+gC6&OlX?{ubKt+^SUcz5x27=hiy2VO^ONew4` z!4wmWs2SoE6T837DHx7jt^U99y@hsE3lpD}OQJVwg?2qRl%k@fp{WN}YFo+s?pR8w z{KVMMBun~<7gD1_gCnt~6p;;^fBnh@u59!_PKDJ*LBv52*($EY<%xRK{Bs<2R85u3 zmw9le$d*!L3pkb6jvYimOMUFMA%d2VwmHSUolf*q$BMQ)_g_|dD=|s+uMtfkJk%mA z;`XLYtlh}<30NY?6H{4PS(TKRPkhYW6`~01Yi7qOgbx4&2C@C@?QdfHLHNN3+76@< zyMeYgdaP_hs8Hl?lj#wmVCQM}!O#aWHwB{$3INn-VxsDQlm%no#j#ra7Q8tS6OY^U zFzseMcftW*AR`k2yN-sJQ)tNVb99Kr`q|s(^uprh_Xg zqsV;uQoHjPEX4|^A(*5@r~v5%qS|3ls>clsD;H7-EF*B)`I#d zDFyaVq$XgE{#zY0r!D5-@D~&m^!H6(L1Ky(_@LG1Eir8e>+s&aojSU@Kc|OLT40?i zVE7CjX%K;mn>R^Vs;?Th{ngx|nM6!b5pfeVy&=S*klDTss}D{I2{(=ik3g91w8dZy z2I%}x?H4InQs6-5Vd9o^@)~+xIszCF_lRuB%a^wyDHFqJkjd5KMYbTcLNM2o-b^bh zC%v!&+)=b_4?`qcNoF77gfXYozU{@iyC`~>7gxtKii*y6+Ke+!0SOX~3>6v5wR*BN z3l3Dq&&g@lwWu2yAps4O7~cAibp@#UG$&_EY*QVYH8L;H)`B$RMFRfz3i(6gD!DQD z#AKf*vXZd6DakhxM{AK;+6yt5;FpLqRQC!b_;VfBfLefIrG5MMZHAyKr>n~ZA8KfN z`VRDG^+&R7L>688hRDPn8ioHA?Lowm3%>wjGH5SBWN2_$dN^P}Nf6xQd-@JqybCS> zf;q9iybpmYho7Gh5pf{ce#9Uc02w$n9XmS>APF&4M)+_9q7g7Exe3p#!sa5Bav}l` ztg<;(%i8XOXMj>z0aOIcG|0iwz~~YUB8(XAfl$v42nE`q@ap_UD(T3@T#ZDDTL5kt z0x$z^4-N|>CeL7>eweyktd}UUf#NlYB$yJ8gJ>ibiE_sd!keQ9>Vyv}>iLfO8FWJ~ zICDfg6#+`b#|Q_cwxPkYElmj~L7MK2Mh(o)riqANVS_n6mNHR=@ElJpw!oX z1)4kJjzz`Chd^wG$|c7W4Ir|cm<)S)sp-ftkJ&N8O60^`8R$bj^a1#)0gz&!8|gb@;xRl~MRz-M+KZBOQ)HsVg8CeRl zai0!8@{)Hf^%4rT5=sunpdhApgiwY@iTV>^BRNlaWGZu6o?IYDK#G-A8V_~Rz*x!{^P!3i$VprhD)KN zr6okCB+TrmilK|C-qL7nCxYMMQpYixw^{qa>AEc4?D1$#SuTvRg4fK08vC@Ck*Ges zz$t8!Bf+if`@ZNm-Xn+FYTc47BL;*G8KTgUn?y)N@JoJRd;Elxd_lXHLWE?@6 ztsPZZ{M7#Iq?ybegppQ}J8t~=F#@!>0-0XKjV|7Mz4mwg4D{@@^mO9(!~VvY3JKbu zSy+)s@^*9^LeM1)-|H0%OzVrql>}tQvz>P9*F2&Tq3lOYnGqwONHf9uc0geCSaHm( zj)j#~5Ns_X(?$5ihx1ZGyvF^4_IF)Ru-g7FwZT^|v4^C0hXmBZLf@eW7^X`ntNDRQJhWwv~tinQ5 z)vd>KX*tiHwW}e^B|s(=SH1^H0nik|Ge?-PCXTN5TtiHi4CG5BI(FOJv0rOAjcp`v z=&}@-7R45X|BIMqmdb9#ds+~>^T<}ye4ag;i>=QHxb|?hKZyxQ=b*@jCy0ZVJpo?c>jxaI#0y_vg$Y58#WmkcfX5JmqgNTxr z*bi+2RwBk?Dwr$l$Id1arhA_6UmLGqRa^C5yXT)~D-r`!+{?yBB&7jIT5C)Ks+e}| zy3{UGXCVxL5JAHTbVnxlD0WUwRrPjQ*bX9k52$f%;0;^0Zq84qi&gdY%IV`tX_JR| zo&OzrLuz;k!4g8tBvb|TBn-l5Uubw34bH%Q;J_BZ`mUFk)FNN?g%$wTf$k}5Ywv_D zX6AU1KME6_&}`GwqcG4V3-yAd=j%eu|9yLHhT$)5%>T(-Th8aQfUBd?gC6bY^+Y}X zHlE;k2BuX3@oSJTgEACQQ6YoTm0$#I-<)r!B4&slc`vd++Pj5Vx9jyTV_&z0pI^R@ zj~~DIquy0Etf;VXETiGSo3ln0wss&@>cJ6xdDt<1t2X}(ZF90mTD5JKOZtC%o-7qZ zAYF)8`nMcZ@xC&~#2RT8AsC4XDxG(-Vyn0*v_{rqtDqu~JyDWd$xyPU%Px zonE@y0oR`T{nvcUpf)E2IX_QGCWL`2!D#f@*A{6ZrrwAt7l(zP=kbz&nzT*q!mIWF zhk-J4v{DIRm+Afr8=?4y!T17*2wQ3PzQz1-oKTPi{HU(iHwsGo%;t%IrKPQX8{3JM z7$?KRlh4wz7^)8N8{S*vOpJgKQ7AaG08wWV5I>;yAg+gBnbujL!x_51-wc)R%@vIB z2z$(1gR6LGC0fQk*r#&mZDZp$>^KSg!M87rzgtNV`TL=tU$QC2DcqWW|8~TL0d1fr z6$A384>tz-D;f&Vzi}XKY^osH9%AJE^8S*zl$dDhV9Jh5&9>Y+yIbk3?A5|!k95z| zUZ0~CeHqWYA)pqXpd9;jhsM1Fms7~n^$kCWk!zrE-!t2Y;Mi6GMU6* zeAa+@<{;OQt!B#&+QiYs*c#8|t&09;LX^>s#tL z%!g0$#V9BJqNh)s2ky-gUnG-yy!x!_S`3p?x!elMyL-$6n&lwxs{UA7G)I`{hRe<^!Q@_4X$2h z6x0&;S?*+ypNB9>VL?24-*stt)}_Zw)xDS_l&!@c26yhejVX9S9hQd!Y$W+A3X?oW zl|C{*z1qJNdat>X`&9*}-k0N)!(bCA{S(Y&e9eq_e^I3BYLNv@8u}R}@=PsWML^Uy zt3MB`Yic%R_@T4po~JU}72T{9mXWbY)y_)!a&=#S*s9L^@|ibbRaGaw z)~1TH`%5FP+G(VeUU;^??t?jplVIulcfyjawie4(HSM(%FDomCIFurM1*2T-TmPxjdDsb+=|H_;0vrAj8xlhU_n@#I(8&UlvRgxV-@8ZB8vR zDoBm(XWYK811p>TUgJgjD@sfZ&25`+5_7O<5Qej|!eKiCeNH#VT&o8McE1%+JRHkl566qY$Zi+i!W`JK_JeEMb zY~udCd-9Or4c6}nH92BuVCJVF`B%J6mDQbj51Co_*ZPs-!uh-SB@XP|M#dT0z>xn3 zc4``h)pJPX3^(;7-wEe0AhApo2h>)9lHS`_RH0VASsvbzDCx2tk1uTDZbAq*9p&3^ zvjlar$d?%Y8=&o1TMcAMIq2hK!Lz8&!(ieuegKF32EL$g->qb&RJqV$$jrt@B#*qjdQslf}4ZzCRWejg2%p1&LD|jia8>ut||I%{1wN9W{PgM16%~9=zPIL=RF~> z5TO=g$WOvym^`7s=skXh#K|2|`Dxt0&O(27^~CbvWWkV6Br3EDmg;n zL@$V+#v2wu!t?E3CJC#*{)0FLuI36hCGGqSf7&jcS2O|g&Tw+z>^;`b8iP^q-g;j6 zgF?;af+&s5bX>0oINF8#2Cj9NMzP?=a4QjUyFMWMb85&Jrp9M_oJf~Ft;1V^T*^_ z+?IoFe^c#H)!=GJU<47)eYmo+vPJ2(Kz)WkJ|~i7y&uBEJe{FU@WJ%vF@ume3M)M! z=EvAj_q4P2<6SM()YR7`ndh{yxQJ-W`^H8tyoLcMUeaOSqfw{?4J2|`y%m*iF2RZ z$EXT)!y_XWx=$qsvOuDQc!QTX?85v+i|pDF zXGu0p>|hq`?wEiGElY7v1dN%&;^Op*3btaqK6zLt#8}?@!+A#xm?hXd6z!XxF*LCd}Vh-Oh)gPphso>&r^rDD)rcsbkZ!cU|@*I?>aAxGai8<5N~%ZeC-Qw|SL&sk_*_FMh>?6%rhn!E#L zDoHt?r9+J7;*}n=U6zrzT1F4L({>1QS9f(WW5MG?K|#@q!=shz9btl-K)Q*E4G7^5 z4#JR1nzsxaytz@pdd$eaxnW|VS<)t`vRLnkQC$x5QM`=X5%S{tceVlZd!t{G55WMz zp2hc`SckoDy!U`@zUY}^W@W7&9OMiP3@pj})gl6(0w&rUe87wQ2qq$s&AYvH(blZ0 zG&tUB?bk^+NUqb9C&a|agKC5)L?OMr`}k1_(-3fdOH!zd@n*VGR$d5;|4zf$@H~aS zjiGKt8HqLoZs=G_jP^rrlStB#*n1~<5p}u51yTu-b$apQu2fV&55_TohORNbq-07I zCdM=XgEwPfdXqoS&EogM0LN1J!>9-E24pG=8V r1 + diff --git a/_images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png b/_images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png new file mode 100644 index 0000000000000000000000000000000000000000..ffba694c1874ca7f1bfa10601f12d818f6c7d936 GIT binary patch literal 45619 zcmdqJhdzuxET9M9+RJdWdehG=Q1tzqJ3qEIMnj;O0@Qz+B{ z6be-}13i8s6MN+`{y}eYOih*Ym;CQRWqJ&S!cRG(s&v}@-ekX<4u@sA!t6}@`IjQ* z;}3n;t3FxJk!Px8GAVTTqQsR`!eVLh_u}KFLYlVmY8sq4{#Lc2{-R0LgTrCUs)rO6 zqqn$v%m@#~epyuWkqN%NMM(74ij%(Q)bymNQ=9n8q}%;V)Qwy;0s(Bw4C9$wB$l#$ z@oxeFv!T=iLCJ zg@xc{C#REoddz{!Z>KNay?eK|r-$2r73-+o>({Rx+}whbk_>hT(~*&s$x!i__j$kT z>KdsHTz&n<4P_e};g2IDC-wE$*xK42IB>vd>`gM4th?ys)Rgh1ON_gB?^fT&e!anD zYV}2}ArXD4i69e zolH4w{A=l3ytK=%5e9*xKo~2(f*C`uH(JQv{ESsw(ZnhY$I09~Cou!4|f0 zUr>2zNr|GaZuzOvHmn1{UsJM5u*2x9jTo_UPr;>ld2eZpSMgMyo}LC1nU5bUnwf3;^J`A? zp6nI&pFe-j{`k@O%)BMnd0ZPWYA~^ttXJ?u#qQfTZrsSd`q#(n=jS*fAtB%A&lO_# z8b(~18?AZsCTiyU-PF^&9LL+YZKGZziGWjA9N1qBAu4Vt@1W7}8!{j-844md7Y_ab^LUZlqDJXzaI zTbTlQKE1lLk4w%&LUqepjPAyVe9Jj~?Kme#$C`#v&Tp^wwegFJvh^0*e<|NaCcc15 zzbu<3AUN2x<{F(&iGx7Z?;pBjU%!6WXSbi9pU<@)lrJeSH?0d=^Ee};rpUH;NhFk< z(5wfFOSk?kjj+nDOy;})`S~T!vW@rRMXmJRl!_lc)}rF#wX645Q1Gs-3csReZjz~K zr)CP!6xg$8O-)S=10!S2IYVzcKgDXdBmFO(+T>O>a-GdF2sf?^GH$-P-78L&%!S39 zkc|6UE-w3J<>YY8LY%(5R#H<7p1E0;bs|C180%BwJkFk2e-~pK_Zh2yr}?$tZSc^c zLv%jB7rN3}{DXpm*cfQ7ireH@o;G~D`sb&mT}6_ELEThuab0ikro9!j)QRaN=8Ojk zvB~=d1kg?nRBn=So%Bsj{d`I@CoPTs$dMxy-%_V9*TjPGorMSfd~67<;i~)89CP1e zKws(9sdb)<(+vv~U1SQXT1fbKv6VcGRep(*q88bBWBu+Wk<=zGNgJ;BIfju}|E>&P zym)b_d^1@931z?BM7zPN@R%K%CUc{$&TL0yvJ9W|e*XM<>F1aGKSct`bcbv4+ob@L`i5lONu^dpG&)iiMdOzmO0E zLJ>VZJ(q%ytci)qh0V`PO1N?=e{jv!tmFxH*nw(c3odSqot?cA}P7y%$YNZ;@*J?SRZUE`2%fn6&U~)I zdquJ_f+rNyxLL-PIWRD=JKvHOyCz7+ZCYZZ0uK0AwTSw?&wpK$^ZfDP=~L#DCr=9P z-d)$7XX^O#ySZIoN4lozw~r0+5|`N9J368h6T|mgzc(6b40oSvm69>P^6U5SWGx{F z{1uHm@?@%eBJtXN&#&?^1ya`qv(7xbQZ@Hl=JDgl)!F*xqAp)gb8&Omc6P2`S)5Vx z@$rfIHt4frE9*W>G4%RIXYu+Tql$`3NlD4jm-|=gO__75mY?)2t=pkd-)sMT&AN5# z;u8`^I?ow4w5J}+v+l~)7;nhW&GiioJd|%7OBUuA4l4`x8|4q&YnH%fOFWHc`iC8hK3R^=PCL6zQUjxx1F6`RI{1- zi4#+g8?;P~js0qCYc=jj{`Yz!`duuAg@qKvuI}w~))y}-;yB=F8eP2D{mEtZ>eXfz z7Ei(r&!1zkX8_lb)u zpEz+M{dfX-gDEw+fGHz8I~I!2o;_1He~y3sTKnP!!@|NsEB)hV&z=d6gf^I5ymU!P zFvd^p{bcLlARk54^7Uq$-l8?+_=xY@mwb8`4#ew387fMm%bB{5A5GM^-Tc2Vfc1GS zxt^1Q!})_O4K+38*I=6I?VC5*`zo&FH!oq!`|F9=|9B8ij^w}q@8!~aGP!jxUow$R zx{aOD&7h&ItV~1a=2g)~EghZi)P#OU5=^9-0;Yz>#u!XZP3s#QT|dYw{8=)MzkAo@ z_wvH^urSpVC)TvLx98e?cxEBB_3HQL9S)Z-*Uq&mL}Gg<14Njcn|GJH?UnyEtK#+J zgXNp{_G@Wrf`S_Nu3x)GJ=vW{vwi#a$C;URh}GW~x(wZVzCTJ!d-&uD6E81sq9p6T z1Hg&{Kt6c?KHs0^i5!;1?Brwt&L}J&KO4jB2h00ZlzaE?IbdgpZ9d43^BRmOel}Y# z1fg$zc6K(xfUhEd_1Df!s$U(U8#y_HA3Wf%`2KP?@C=uR3(*y+1b9U(UHn%1+hQRr2_W6F)`Ln>Hd%(6em5{^pHV)v&vE=Ezayuy3Sa7LB>(nX# zV{szi^qI)R{;)2v$%pLGEmGuX8%lH=7%soXJ2E?5w=|LSd=`;y?!UjrtK>J!cwKc1 zSp%{jTefb+*m_%}-~Gg2#PN?`rtm5@&2<^UCcA35h2;@$j9GYc;SJusc^-TU%Eh`+C+)eB*{a7Xrq{ zF4i|R)HFAT{7-t~m{M7iK-62iVFP_57ugB-?rp{gBmr4wC-d7rPJYN|SiL$$R2_qH zHsxTre-rBfRQ4bx#sAw#)7FCr@66nEKc}Y`=Icw*D{-K*e0|R^Cui^A_O)1vN9#El zWPA}=@rj|KAz#Ol#$kjAuekbzr6qSP-^iceD}b7{@nWV+A|d2#Mk@K``p4h7GmNC} z4t$ko(!eCFTf~g5=@r*$ju#=Z6<=NV;loBoMn(rGr;&2ue_NA^u9oFdYHA>lj4MA7 z#M`%T9b8=xU%V*fvEnFmE?dv9xL8X5_xvfZU*DRpU%&pKWtogoj)AULL)7}cF!s91 zpI<*ontpsTWwy)k>Nowf!R1%x1UCrl_~w~5)%Nvm?#eN2!XhOnD`l?7^0ddik#gH1 zCMnsNBlQ77)A2jvbTNV_YMWzrczQ(|YiqMBD=Uk7EjbWSv^aRR$?)p$Lu%~n z$aiz#yCqHP8B|qO`K6_~rKP1whzwe@DX72PEv2B~*39>wrv$r3@c08|0un^uyB9X| z{4Z};w!Vsy5&z(4@(!PN0yLECT)4pPI@J@1&Hchm{P=x&9-xl+gHD2BVPQ)mn&ALX zgIE8CBV~*f5BjJerULx>A&Z-S|I`e~;1x$!IVxT4+^*qc*grmhf4c<)1#J-*XGi5Q z`|X>Oq9P?tBa!LcxpNn-tX!|?yUh$V046wmeYf+ToF~bXv-9(+4i2Il_8Ks6+LR!Y z^KVTPZ%`Y%XxQpa*99b*N+ zkBW}=!vP+8d3*Qu&`_0=C)Wlj3;g=^i;a!V7yGSDV;@UdaCy6vuCL(yLRoW=JJn@URzL5z|X;CjCu~6MMp=c z8n^~|QZI4@M?-*v>573e+0L`qsg3RPugqDf9y%l-A`&s9P2xfOKGipuEXltqFCSnE zAV*%ndo$g?PejQ_{C|qd6h*S8Z0$`a`L~h3JU$}CMq*^Zydwt#32y&?eaxP!)%=9MivJ5QxKn_u}iBLcKxVvTNVKQ*IpHmbkA7DzH6 zs8J!Y^2yb7MgF0rmd}?-q38bj_Br>=+hoG~&(hM>^4fLh8ozk);-brDAd63rnl)>dR#r}NktI+M6~eEOGy;JET<#%yyPe$s zZy+J$7uajTsL+brhEgQ=%oW&DC)|W0B1N8#_$euog z<%~+YMs2(|*ZrG`gquy2a&k2aSNF%)|L+GCw?tRBwdEYyi%M9Ynwr}E$$t-}!$VDe ze*bJ$8PLxeN0JaMS$54k@3W!(Y^;5ht zY-8Pj$!q-2*oDSKrDQE~D%Y=H|M5`C;FtV{> z#)?f3)YsECHa4PeyM}nMSn|z5U%#KlV+Z3nkCl}bXor(X?k`^+efR#o@~+#2gh7oP zbu{&HR+eo$3#b`PWs>!3ii54Px3}EauU|{9NZ9S>-5%2nRM27KefaRZRS@a| zl#R;=&w+GER$MxOFoo&@6}-}sBa8@BTH4yz+S|45bV$?!Wpv>Je#nH;O3Li5|SfGe(Mop>U)Xu-WNd zbd*BH3nx!fQH1vHT}3Gz#`j`UNzrrW%z88N^ZA7+mX$HkSFe~yM@L1aqzJ@&)!Nz_ zbYvSliYw$H?d#k64X`X^m}k!hJ$oj8D=tpqM^#zb-Ie2o^>{^$0g?EVeA5$GMa&C% zV;M|kZOW7%IH^p_^`c^8mt5Vg6@;i1G5g8Mex3%WPSM;s-dHFQ-n*vLnw3vp72ojb z^1(%aon5yt+iFpS zi`TD%{QXtZ+cL?@Px4Kz$$I>Fh}!AWrJYQxS9dDUr^qFOnah3l>{?i6$AAjBtD9e-q>fr&IQ;3WwHc?Q5}1D^u71ueBwzF+FMO6)|?7|d(dAQ6IzKD~Mb^w*2l)|1J zjq6I9@aPdoMs>?wLPFIjyd1y0=9&Hjj9lWmD01}Z(UNb7e8%?ntTHk(7)w*t9D^?rX6`pki3-Yni{{=!A}wp4%*Hv>f=TA;-6!X+NVwd`L7|A1tPSE zhX*P2=+|&R`Vlz!=@Ts`x#zaOGdJk#$w`|+gE4S*BPi(srRo7zlQS|HckI}~%qPDY z^U(JjD5;c&hH<>HOq2f=YNo)|oFGRI{rbH)2tFZDJ0l75G6V8rdfNr{+ouTDD{~25p-L%x?(~JFSiZchtQN!?Xr2I674+NEaDw1h@{b{*@jEsyDkA+?A?CdB|0`Oe0-!=XHJbw`|*jY54LwQN_+q#M#+- z=<8P|@Wk#{uGF-&tOnPb;(KD5`Aqrcg|BC(V^K(DoMyrSJ{~VhB`+^OyRZSV;*7e-kl~qJ}EaarN9e^ zBQ}Se&$k!`M?nI@l1Q}F;>_R|`7bCG2``S2?{RjA#ytiQ>^+~3z1WIc6O+caetjV7 zX1xmcwKy2LMMaJEA?w5(KdQb;lG}um!Yl5mM{xve0K(q^pI--9_~gUzw#tTvd>v^g zR8TQtU`E!~z0vtw12_?8LDbY|oJx22{^`i4FJJ09I@SRTHh^ID{O$3YOGR0kTI1dU zKk#uwpv!^p;zf-eb`Laq%N{Y!hpdbcF$jeKXlg-q`1TbZIYAU?CS`l2O3DB!o z+!2ra5sU$0V!yyRbU(kUP+M0AASP@L1C5ZVB#n&ITXyYY0?*!<^Zd^Z zs7*^he+mF!9*Y$o-@l{OJWK$;R*TrIBUIxHW?CKvc=^4K9 z7^Dj_5v0mQ#g4p9O8#%{$M!CCI}LyS^l2!V&!-w3f#c$|KK6dD0K$D|@-y%;76n4#tY;-&nIr zQcFrwARN;_qVV@8>yPRF)fuO6L`AXL3{-54h=}lt`=NtCg=a2Jm(R?CC#`+=j-w@Z zPu-I`m-|gtwU2G8Iyr=)!f~0O?WA3{=kBBE7Zx_8TD1(E4k(^ z8(w_AT(R^ql++Mo>c^BX2;4sUZ6s2`1P9{9%a^r;_5n(^yE0{d=Xem`)n98t$CD%_ zX4@n2^g$610cko+c8hsIrC9>gIy^cWR6O9Zdi4h32PsQObPxF!p2Y3| zp)cIg-fm+3{;4r^INRSH8f*FZ+Ri@JsX_2-b9QmLqrS}qF<{c4Ro)2Hd&T?1>Q315 zy9L;3DwUp#?it&$-4QT}owC-Iejh%yX!QWgq$~7<lhlgfd+g5=pf^q z|EiE3AU&}3ZN%8r)E~&auhO$P^vTvo zzlHbgal}j!Hhj9T6fE=D&7UB!7Q0Ivx4KSt`ys}asU_`>-Y?A?5%GB2BXg8zZb2<( z|LX-fwSFc`0#>i`y0M7r`W1VAM?MsCd?5Db=rsB$6 z)V+JJ!sl>!ojNu!(3V{ND-U*-Hcy8cFqxzkRQ*?MDmA4Oi{5c@a6FQnYD@?N+rF29 zmb#Fhu>DpeEuX(jcIsiZD&N0(K zG<3DA)j^ByqXpq`q`P>bSzC@>`(!paOsr zM-@yMwyVFs1@}D5GN>$TSd8q6jo1NcVes$oLBh>KH(l&@iJw<$UD$*T5_jURL`JCR zZoamjp1V{=pn0!MmLOD{Qo0enUafI*axz7&X#;s<5{lN-w6vgxrl$P0TMvsu3f!=M zeM5LcTwD{0iP%Et;W^06&bE-U>obCMc3e|4Qoqdkh^-F^6_U0YX*>uIs1rUwh3>5g zo4TXnX@xB)MN_S;qSBd`clq;Cdfz=43e;_}MVmfgKlGk)LbW7iv+%X^_%`;ueU`69 zGfux`Vq)q}JCVReaRuY-8rh`Nl2BezQ2_w;Vcm17{swG~Hk5Vo#|0opwk~rzC`Z zzI?D3XCOh^#VUb?V%1g_hs_622bphEW=4i_*zf%E*JE!}K4>cZerMLBId|T4@>@b! zLW0l8ul`-)xMg{BRILvKR#+_=s&EBK|%Kf=&3Q zB9n$27Br_(M|5;{nj07xSk;|bbI#qpq-Pd-)IN%>{0U9Zw2mZhz`{Eb5iAK}ru0(B zcik38@hIsqq?neI(?%$vuB0oY8-F0V7G;h$h8Ow!(||$Ni*a1V%KP*^SFww1V^7z` z;>EvRJOss4jlJ8;k*eK{iu=RWKXdmr64cbR>1rFLpwhp3^-2f9D&JPgX(Huoa2rC= z-7p2y#;^@E#()wDaF6H~+wsJ-e71d3S~)QQm{Ci~g$qOs4TC0S@IdM=bPT<5BVJ3$>#L%=ZA*veOyy#HO3Kzj^Qh_6OZ>0e+AJwL2+4eO zg)duLLaB^^VLc{G;QwIuz3}+t0-I!0V`C7N(UmJ#z+8eZ=y>zS2o%kU#)bKLGl~x6 zE~(?44(mBM9*373*U{7aLeS1S(bAnXUQpbKgO-+&(foaGZlh_~@A(eRzBmEOk2+Qb z(Z)ZFk$_-Np*`yFm$EA`^cdex?^`)ryL$5b=axM_cZ&XZ@+!w!IGE@<-o3MtEO5Ss zI^V)my)5%R%dSgDFjc@6ly^S!1*+>Apu2V>HJn#eR4ljhx#?n$lgUiMf^1HJ&T&eJ z!`7fEVu`s>@^@ohZ@UPxpctjKh!5FDlZPS0_KF9w&yeqNl-ug9-Qj-}TalKU>gCIq zJw>ghtHDxGDJJ~rC~=+QrWk#!53#CiFmcQu(bdtRP{2LCL1+Yn2bg$W^`YPj>vlmw zY6^CAr4EQTRQ- z&Y~@84de;e&c1Hsb4N&#IQyJ%F$96OAzI2vQ>4OM_o;6Ze--3`EAYJP`uay5qXHX3 zQN@OU?7{wWOS!;D#B4LOcWKXe?%k`VrNxGDN<@^+($0_d=d5PRifwx(i7pZ+qHnd> zxm|i>-@BVd1;>DQpgdR?{T{pSlF$>Ie(v;X+Eb@amEB-G*{Mg&GO`#znN+6v`RR*(DVb{@P$2uc4PM`Evx}c*&_&1Y0E>M#wBaOoL zd(JH`&XfdNr|-yc1hOJH1i~j=WMQZ|Y3b-{+S}Pt+tfk%AyNr}t6;h{&)kQui;d#= zWAeORx_cuRFk-svkg9GI4dFawy_RyDE1-fTEo1w@sRRj;#@>ELBOw^48Gyjy(~IbT z)03IG8ej&6=;?FkipTBAOW=_Zg@LNp6a5{ov|fpv9p@J@p;~YOpg8|EVfgo>&zqt{ zp7JV*-V#MfQBb|K3=JbemkZ{&)w8a((oGt`5iau%e>AawWzGl@`2gZZLPW&WQ7m{P zVs0e(fyw^z;t!6nUI9X}A|L;1`}<2XrfXtiB0*vjco7Nkfn4qB$jTsaNFccs5E$klcr#b~U zgqE)JN1<#AP}LXh4`v-aUNk%EiB|0=5a=)SFvoaM#a^sF{Z)bI~pk-+iXT6I>J*PIFyLK!~FsSaG;Q= zBWcrJZP!;)^L1k4JVNMdR#r<4^%W?*?c26V{FFh3E65(wjl9X{dCL)XzSHH)CaB0J z@sp(G`-KHWCYQ#(?SZ1Bzl^PxhG~Pd!Q5f>Ip`{%LcC;PLoss25A!=GJYN z7a@iam;f@x6$Zkz)YJxWffo{etm_i2Gy3`>EUqioUOP4q@uOzmwDZ-Q8Tn(N6PI>vHEFg)6nZf(xV`F4zj809p$}f*? zJ$v%x+sVPl+{*<85|ZA_&TvuH1LWMff8Q{_OI~Ep9&?^o1-^Rs?p8Q>8*kVztmbSd+{1o5t?7knXdfn) z-E!Zi82>mjkdU2rde?_d_7ydt?7BnN?I^RULWB|K=l9*XX;VHhdu7XLFE3!z94ICWxP{r?Af4}9hrzkHQ}%i1Ei?C;)#2R8zw z2WMsNiQtuE+OZ=&_VCo&zW)A`(0Ts3G6ZO`adav@_T$?l;2Na@aWvKbvkQ*h22R6z z5VN4Q=)IPPgZo5i1Du2KgNGm{2uELjOFjhxR)VB$E#glk7!aeCA5(pd&5W0}J?vBo z!`BeQD#aHJB4ouBS3!5!OMk*UG(0{Y0{RQZVp&Ta|7;tT87YN8nS|Ou|Gfc*o+Z=^ zUPSC0KVHxsI$ni}l&EeLEf4kJ-7oI&6>f1(!{mPU$zzff|M+5{M*MK2z1= zcK#7-b8Bk@;twPIu)vb5E!&bB-lnLPru6)@u(l3`4Ff&|rEToSNTRdfzt`eK-j(xa z5ZIIV?Ab?+1##nA+W7c*!kK|tQP$Jj4A%aqNZz?!d-pa0Uyum{Z(<79wfd1GHKYK> zd4^|KPBC+Zt!NtvGgPJ`L|Zr#BWMgtfOtI;Ki!N{+a@STs3qdpMI_FHiJ$^B0i?*$ z@`AJAV}|qF582EX|cTcZi<7y@K4V)%ENlN7MWj^$cBT( zweL2M#|?;q;QLGltGr2u#FowV`g!?Pq6{ab2(LIb_4~KtsT`MPjemih12^0R zMmX25UmAZgaOS%-ac&}A2ZK&|2%kCZRP}wOPHVZi7(hqE)$(0`i$G;NWQVojeK897 zgtyAbY(mXl_wZ2YzkwjL!YboY1(tOesHp>vA885ei^Hn|XDr!Q*tM9n!z*G@2B|oK zhys0Uy}-h8?XzGe4CJBE4N6<0XZ20ewRYVG>ED1D=J2te@lkp@5ynv@)+6D8WUd#C z3)>b@(3YiJOn7KA@i1IM7r$0sE<;U21Al;?ySuydaw@}-`|Wvtx!79bo8>$>2ygp8 zw0Agn;GKPzTR<`aRu_oJ@P5JOI^gn^gIKGNkLA&y!|Dj4Qrc$2&% z)GfbOD0b^WHzsRBTtd<=Ouz-X1qJo*GENOoOss~ka6m@pl;XC2NN6mCRl$}cwzCo# zuZX_@ECVeqEpeb16%~2KeXzxNw!)MP8}0Roh*9c~zEm_rBP0HRc0`2%oM2-L^ol#i zuou-}6t)tax%Ev=M1{dOi$XGujASKx%9k&}XhLvVp?Ra8^LD>qu2>@%=(ZquC5M5q zh%*5;03!@0qpoF5diJx0I6=4{n>K~QdJ1zvHAEk%T`+Rh1Te0H9b!qOxXXRs`#D|}1wnFZ zDjkXgtVUf!Ltwd^qa&1f-a+$q?YlrqLzzR|-2yB7|L93}0~L&c%2e>8mXwt}@xG7V zj9Gn2fnC2=)sDjFx{fqu96hRx<90J9=6{<=@N5Vk*lm#98o^h+%`sGf^3<>M|LDA6 z1h$HattI|8$ol|JVzADUnZ*Z*#D)q-e;{MESYs6AwMUP(K_R1oiGhSj(4!AvIe|41 zNxvGpDUNXygjO-Y`~wFM*3{Pr%zQt>cM1s==4{e`0EzKa?I2DUe_RXRKTye^-ci8< z5*`v!=Z?j_f^tU}nFAuVcikpLC?^}Z2FKsaF0c~OP*7ipI*(~#zDyAj`bMZ|=(QF- z`D(aSu#wTsP%;|_UJEi*;ezUdKN&vuCi*|79KX;{?gj#mj*Sfh;vz4AIaSxxY(g1= zflyH_EG)pYX|E1JcnSbB0D{NefVzDhLNl@~8Mxl8wU;3=X@FF$!3iiCn1tl#l*sWe zEsFQCC2egi3>PCf=vMmkm>ohfBK=WNj?x0hwGO}vkFsxE31R}N;ZO-kmiAX%i7BtY z`}OLdu{5>itBWj8PB^t@twK=_%M0CX8)wm-I~#3mY={LJJ99ekYbo3ZJg?q2;k&l( z-5Y6rjMv)>eI*FXl)q0^K#E!oZhG>g9#F7oThzcK%T=|p@7}%RhlUS^lPp(BFVIu; z?b~#Bj?+`%h*A6d=eIFz6GVfDZKAP}9)}*9+u`Rvzm3ez4^@UGhKU71-bb(zkdopA zlk}pkO%03(7_}%^=RwP3FfYLmY>w!d-#ov171h|~NHCA!uj@v%*S4p6 zSn}J1D<=XkdB(9t)Uo z*g_k;|9lnJ&fowKL@Yu$Ps9_1njIFQTeogG)PZs;q1RjAPDMOMD7aRSJ;}{x@};3? zevopqd0ouWR47r(m<%^-5%pWQZ)f~Y)Dl9`O^1rZ80F4K?-9^WjZh@t?dzw9{0l7; z7JEgMaiC+g3=9Uonx0wFK6fr%a!-hAyG?F!Vc{XNY?hY6fXQ!bjt2a?U&YDL`w<%z zT~kBUCXj+T%|O$XD5jLzZ?-s%Mli4kh*VnKdmfUo2!HpX468+juvN z^wgXjR*?G9>a@^O&=^nyoD0STrX^3j-n4UP7`5 zc+l4;G7m-uO{uArJmJYJDjHShw|%+&QNIwIYXG<{Y`5fs0{s7atKy-f+u{1PZW2v zhy3SktqwH7qW$M*bBYWP3*+Aq+Ifvn;L$NS1MN;5(mq+~>A3(#hz&$xh*a9wx7HC) z(uYrmd-8(hAVxidfcGBjc)x%}cOMSq#D-_%=4R5=Y};{{MWFHo9B+iTApJuiqPmN0 zb<2Nfo?UpC(L;MiCb|8ByO&<>X}Z!;E^h88of+KcG&Nb5mzVWclo-a}3bEacIENL! zz5CopAV2pniEguoe-{kjsi-d(0C^dGetDY&Rrq5>fzToH1w=J&8PmP%d;rWl0Wd_H z-ErUR+NF*(9Ms5}XAI+)A$RG33wCR+LrP-u4~Vi0p%xhDfHVZEp$;&f1Uax9_YOE- zBOee)#3wy#K1;)^HXm@HJpc85wf^})wsu<>brW9#$ehbDXn<5i=%avu0EZpk+aF1p zgc&0*qL#Sk=SOw(=1sJEh*z~>fM?04USlhgzARYP0o|zV?d`Yi*fFQSL4YSaHagqJtYkiZbsHAC3KALxw;70<; z%X67H`wt#(KnEQoopO6B+CUwr`wrUlm#qhZ%}e-C=n)vsrx5H9p=e0B6bGnAyJ}SmaJixP!g`p<|8+Hd z-!@jTFF+yXaCj{^0WlC1L~Vu0m`bCe9{E7p0q|}W0qEhIq=cB+l|3ZB3T*4IMJYyl zDG+c!g4E>_GoeLOLOW8aFy?azT9ETc7iD#OCAok{o}`upOhKHxhL4$Ik{=B2dQ^VU zb&^X~R#pq$xPWm+SV|6hMuAG|LbFG`V}s8X(90AF(PJGbDQO}*AkfZYzJbqcQ7z`7 z=kwKl1wI%BAhHgTE`@Q?g64SVW57lXEG&nCZ+^@SM#9OCUFQ7`JCZEu=`&}BQDN5I zJLvSUCqkOrR$Q>Z1N0F=v*;=?MLkJ28(5go)r zELrsR^+_`%CIpJ8M;;zWEYfg>Hj&YytRj2eAQF3hExL1v52!UkY6LN*2_xneMD<%fp1!*|Ku_8<4&Az~PlXnW( zZ>j6~A3DHoQgVWpB5wf)4l}mdRyjGI`(ED}@#!YwKd$A(i_7Wa#R0(q!-$Q_zUpTX z=8KiI9RZ1x`VMV_|Gt42XJBLvk2D96J?Yyat`%c+lwxkalnb}7SQI_4d)kqY2WlW44;JUnDo+;P7f3(_&aH&PbcyLuX4LJ4}uD5CDzl|UyINQ107~n z9}*{NMJ1L;B8sEYa8{okYp#aP;*kRf431I?`b|(N9&jFG8{8f(Qp;6`El$cSWrR_f z)X3YD#-1ZNqhKgdAQH(O0st|OgWgBCtTS@h7IH?Rh=~ulkF3GVYt4wF=b0W`*}D!nc5raO3H%;F znnX5l4nq|1TIf7Stk0xXNnJBZDDmk3dI41Mh?%tvwB(SHj$(M`P-G9K-}m{5mDLCn zo9roE4eJadCddi;KqX~{E6SLV`=2q&l9B@uY^nci_*Ft14V)E{z?qGYj>OD1Zn7Vm zDjqzH1{mPMe~rZ+!r0jiz921mGSB4@B?)?ynCqkt)@u(T*GLdUn+U&z1P7J{`vkoJ zJeWsX3gPnM1Vphze0kkvF1vy8@pXrvWM&d3j0B&2i&nHBQIj!_^JA6Ow?3iKkhC9Q zM&V5o&%dI&^9#rcfddD)fF6nEiH(cv1vwJ!30kZI0^u1f2TIX%4EHpgfDyU5xo7_h z%F9=UKAG@Fm3d(*EG97PEWnf}b#_6)M zwoV9hn|QwmEfJ=``?9A$D3Eg-7O zPjchB?_AG+|JY>UK1_#cA%Y#ED`i&m!N&bo9H`*wVTC0@0(Fk;xn3u9L()N_5`&C{ z?x3d1910|{lY{}pt23-w6Nqyad7E8XJx47ejPc4ns5%0mVqskVpKQp2ieYiUlNH(z zaGOY+DTplR&oPoWLPBb=C0@!IV&g+E+O>Ok9+)iQ3k3|IFjc|l{hM@ZGU=Okaxi(J zA(M3F4}nodqAUD82wX_evcO0azsVNmy-w>io7UU1&@)eU3NP4ab@aMe*i2*k)bRNxs3KaAQ)&jOM1|%`c0=&+qYx`BFvG46pc9e!q54_TbOa zZBd#@bFyF1O8(-oUsRMlxrX3dtJI+Lri;E4<+rV^tl*@JRm!#*%Y6E@9_C2&bd*&l ziUk!FNy^T@QF*|_8Neo9g30;#02QK5U&*&L;|4SFVHn&LJv^5A&q&VSX|?FP`uDde z7jvcE^VhF6h<~LU9j5$e$^8@Po?_`Kw&&B+%l_L8#n_;iiI!US`-`ox6LE#L2UWma zwg$ZFM4n~m(QWKCCV58C1b~XTAAQBg-#lVhUamG1CuVrqVQRtHh66Szf)uln>`io3 z5#k^XhU9>G^qr7q|McmT(enIwe?%z<11*Swz-BXLfFeQ=;zftE%crlwlbU=%nPFq} z#aJs0yYh?chcMB84?D)mkpR6zfD+0ZDhF?=F|gGjQ%Vd} z3ooo`* zl`H%(MbX-Nw-hg4_s37>J@2Kn+K!0CVd)@-l9oZdPBA*dU`9nKaN zc)E_@c&TwPG|#4MXT0g_3yY22Fm0*%+**QLXz)smBHViA%hq zLe%P=5Fib?5(3~s?$2~s4(@@Or=n99pC4QBApK2fGYAh4$1NC2KpNmONVjui<6#LY zDJOxM#{S1!q8~T0`UEN)cho)762faV=*P8uM$ITI=k$@m+V`DRA*Qi!M&HxD)5;~% zkfW!!cj|ox{wnxdaIZDsia{%51CVxd_@vR-Nx>__%8c2boqftE@TusbqB^}MwlH$q z$unmHzkk0BfSg=b#*Ok6)-x4T)2;Z`l*crj?`!dSdG%1l>MTZ@4=J+h6pY3F9qjG%M7YyC;)w{GI7lCF+}4jdA;9oYtPI?!e|5AW&5xi zL(VG;atBPwUSUk9t6VpH{kD1`422O;9)pVgvrgqMhYm|EIwCrrSpY zLEz|>IWxl9h1&`af!INNz^m3MItua<9FWgq1_ZE%#va${Qh1`h#uxS^#f zOKu3P3E&SfZ$UX&?4%$OHf4H3r;%O< zhp^+XB}Z}-#h14G!3`!#&_meQtt)NeaqFW(6;su+J)qA5JRs~Ob+|qQ*JJpDmIROE z_?Htl9e;o*;siydNVJS$+&eP-xU_WR4$Y)`lz_xMz6Do{P@!y!Mykg5 z>f}-o570)yuu%|^5jQuL%B=OTb=okq)%|tpWmm zGv65mXm%&QPLNO~UFmSZE8!9V0wvM@A%Lr~K-Q3Z7huTIFn)6+H7!kk-QB6^P=_xvOv()qnq0TqK3mg z7_R()(|cI+>hd~RumZ7zh+nn@vkTPx+U?R-Z6p>!&7?4L3j*pM|K)D-_9*z0yC%jL zX2>(qdtA?>=Ja?hBRlzm{Z$>|4gcBv2meN(P82{VKJh>Cdd(_H@7*U*w`qaxdn&G! zLHVqPdj?>RBbpw}Aj8SQybndIw>EMKZ#Y&gM+|lG`z%>l&#V=fz|}AO0J!i&s-mGD z`gbt&+b(kb3~`R3wINCuw9qO(uURTMfk^wNX;Z{7+Jp$5Gibh+B7TRN!~oE^xT+^g zz!vh<609^)=y!+aO|~L@9lmcbekzwxR#(6VQMJh52o9(T=Fbo)!TgY`P(}ZvgMLfm z&_YZbAtrfX(!7grw;;a|*6LBD5F5)wAZ%_@rB^L~-A%3u0n_aj_s+7lwY3{pNg?on zS_DsU4d;abZ0yqhqIDsv&{auoN9eWe*6^5}#2bJ*3cXw8=BeRezM!M2A6;`=%*2sw zK7MQB3)V<4pPITVXE*^wSWA!;jA6tT zJ57*9bi<$^a+)9py{;-m zD9jcKI|K<#OoX1vJWKdF$%*~k;e`7X_4(zFrdpx{qEGwZ4Pf~nCg1#UHj`PLPnyWK z)yxS==`GodWZOz0@hogiPLW+MKfM?GyZ(mP_y_ZPFc1v~pjmFQPbDUWVWS<_Mh-Oo zSWx@<{wBt`@>@QcSy|?ApAipDYHF%j*4Y+FL)}oCHd2aAn^+QDksiSwgkO^2KC7qq z3iN9O&|7c5Wn`W=6#78O|CNot(4sK zB#)QbRelDM206v&MQ$JcfGWqnMRH=fWcS&pMtAPqd0JR_I}t1?h0O6`tnhMOWgsqgRk9Z9hCqZTj-grJppXKwER2sDhF?_x-yG62&BD^muwl9-?+E z49_S{@8}2@T{1j%stzqncfcN@xA9BQj_upUUN?E-o>#E6(3Kb5PANrpj()`s>$AKj9I%12k5C`ST6^6|fP{+7$lw zCEJQ|pzTr|)$b3O7s$;o^^U>V&^HmSVRdGzYAM+sDffemrW)bS-c9%DQKm&DE89gF zVY&;%xR`~7gsxw4chAM%vn$>I6i1}DATm7MoYIZ(ZyT$os+x;9@}X1o&BVs*ieqDB z1|jrGPW_ov_!~oIg!I_=jQF|GUQzBMkNOBEB=PXW9aBzaj{U&e_xsCmim@WN0P1C$ zEiUkjQQzk3H;axHbIPRhagdYiLK}p|#G-XK;J!7K59a6GoSo3 zz2Yt(gNc}?y5NHC^IkbrVzA(Wi!3#NpQ~+XXy4%q4<$1NLSz1Ud0f6E7}GrYUhe<( zw)%DAreSh(ul6xhT3TBx$E640Qlzg=JC|MTqOkDpl+wRNE4C~PHfznOb*a;KpWF-}!>Xy9o*hD=OT-kmX+OjS?C-jdso?^ccIrF~o zZ1`b+P6Kx;U@SzlzLI>>-a~maFfje5ENhiaadz)T3FY(-(#nbO?z(tx*X@3Jwa^A? z0CFk$={Q3lDhe!m8!5TgT_SL`a^hSQjt&kPkYI$-Y?9QFTK=9i(PG^`Xgm2BSG^@y zR`L*25#<3&O;A#DN$wv*bT7!ew44sg2RezRowa~Z}x>iuA_}3Wi zTbq(I1s#iu0-I=Y*85&u95|m*nbQ08-|dKKR~kW_Rm0^4sOz{)kx*9o{<+GJtF{o8 zxtQq-ii&#r2LQ*r2G9};j{pifTGOY!Ex1XEacEhR7~2S_dfaIRq=BpHNTjsCx}y8s z+I3#8E3WI4tF37!@)jFH)l!qfAF7nM*KyI!rbzka$NFQu5hR7+t8jJJzr|AGU|7`* z29e0{@T<+~AAQ~rD?a7Tl-M#!(3evTo!Ep2p&_%nu8s!gl&aQF7TFNhYbd;@ zmx(#4W){?ujiy?8#l7F)qH3fxbGV~7$gfx;1?F8q;XX2{HT0CDz;|1+ahdiS6(H4ht zV)jR`{RpvPfqY(N*6&67+Hp}<7&0twO!%(PB2a&_Vlsm_8EoGxRK6duBbwcI{x(TW zgmv)+>9;~T4KBq@Q~u{Rc)l&s1t>Z7bf0|Tg{;=FHr(Y`ZBZ!~{z13GUChbFr7&|V zy5^3gYL|a5_LKt~c05@t7dK9j*omr22aP|hx)aiv2m8ns&;hpB=L?>Q3m^ zCg8dzK~12*%^w}LDDqsiLldBlpgnH?K(BB;FzTHeBO}1N|9W4DanrLu_H4u}@#!hK zFJsp2UABE)V(5u|-`)KJ1$ew7Ki7|#*IcHP2;RaH61Q6K>`PEpNxHu>meuMcXDk3!P!8i+XiiMGFAa(pk5_zT(E&mfJT;Q08d3w zwWvN=$aS`HXLw-|%*H9?tRhO}$R9#TJjP*O@NAF50~ibV|k4z^|aM0WY4atExIAXz86;RcGw z2f=9Dz<+FmD<)r=qsq zJG)Wb?WjJunH@;~>Z)F3%uN6iI2r4ISTrQb|<@uQ2hyK><-Rj*2n{*Q5zd z5Dh9F$`IhO5dc`c>=kkOpPyoM9QC6z{H3e6j3?)@Cu&%56B|Nqur>-Vg^ ztNXgI>%7kMIKI=t_fe(wcPoogr7*ukwc*W^y*^2+iq;D6XeD~rg{Ui=9B=L4kLDhF zye)PMo*rSNG9%1lH>`)G$uR;DO5#&%HSwbqZHV%ZU1` zBmC9Njnx8r(NFHA=ofAQ)~%LA;_LLMmy%wZ2Pw_>nQ6zj-?TD92`K@+psEs@v~h$< zQ|-m3CyflW=>3J!7fG{pP6&XINMY}%X!>7E4XpF0rRF%6&WeWQ7Tu{ASh*%AJX=$4 zjSsywz|H>h8TGY2eCq@ac=}DY>OM7?$H#(Rq16OdxMu-apx^t6_GGmW{uvo_ zBrp%1Pc9-0H9Bxy-qNK(cgfaIyg`LUUv1CLU<&)jo*IS7N%Cu0I8@p5iSALLiP$AT z1#&rvTu{NAl&*FMJ8CD*V&lZ&MZ(OJUyqO{CoQ@{{FAVExi5c`TWI@4N&ED$mTKd6 zfl>PJJ?!U~6yRX2vrl-W|3WCL{kH08n~dWRNwbX}rpyL!9#R*D-~;-FPLOUKTCZc4 zao0y}Sx7**qDe*O@zoQu0 zih?%?bVEVNg+ujQ2PE^K2TxFofo0rj=rh*3h5GK@yI0b5$=BwlE8tM>Z!;-g^6;=O zNq$B^PyyF>?RBJI2DdDPd%q^t_*XcCItt{8Iy{>naUa_#?6mr8ztKNoH2(WoKq>O| z;!IsEEO1vZi#)pg%&ea1fW5%&B!gH_@7X(7!Z-Jh9Hy+jF?hx~K|fKgfd6Ixv?Oc^ ze7#I7m8e;`&)k>eGE+oUxo`ZsP5Qhla0!|QurlIIgBbeT%xot|r68AJRh+XRmmXR6 zDvE0{G1|OFIF8A<7(?+)qXLR4>2?ywfHs_BM$`k}j_lhP8WGWgy$ezEII8nDZQGJi zWgUTEuMJovoJQ_1$;SJ?xaH~_1T!r}DUa45#QJA5V4(({iz_gd{wFh{1eS;`*!k+9 zY^-wh8vcP}6_l(0L9+18qKxL1rE7liOA9oHl6~5fy^T~s-EAEm$4;8m@Tk9kDrNDn ze2`VpVfouI$Xutbz5Ugg858* zZ8T8cIgEIEF|Ht#io&&#H~9c@lx!II%BsUg-hY~&pWh^4s_Ml#4fzLRf;P1e1^!dp zf%@h9!bZkby;34w^zwS&&(CL;BJkx|B1Q}h9HQ-+t6z)Er+v7V->x`#x$iVC9f(vX zv@odK#NcOLJF~|F!Sg^Qk%Y&J2#bICAHpOw*v4JqIk=;{#$L}+41}(5k87$x9`Ulu zqELMI?bj7-$@#8fvDVpH&H;thz&5E|aKZOc{~%~24#GGP*i*9mh#$f+P2`a^brpi~K zAYe_5gWOGfZy&8w7`26z9qt6Ql9(&VbFm^OPM|LJwrx|kja5?DGoqk>Q^zlIZX-qO&RdENk7Zc);{i^IzoK$EY*x?NmwX)>pQj!`II3TE?R68N z_nfO&R4(POX?;0XWfqR&c30=0n^i}FKKELsKOF+kMDcrb0rWEu=vQ_Zr-5y*kjoyA zSgm`{p0|KeuHc9vKGeJGQh3FSq#=3@*yZaxjspr2jmO3xRh1Tx-Q|eJEFb|5^x4)W zjV2{I{Z9+<;)*HdHf>P-qdrsBw0}ulzl|T#V}Mmuw-+)AM~E)Y(v+=SWKa?&LQa7| zYN&#h11=mQVzF<))LE0f{J#BoS@YP(1f)hvo|uz4)}-YK&G|PV8;Y{#9X5V$hEl%r zUMJs{Oc3$?8vvOmnFg8oZDGJ08rL%tZFj4x$=!u;Ub$c%DJ zz1u>)BeIpic=*3X#zt|?4)yk&-fyA~Uy(R|2icek>YUe&kb}6%uh^`tC>SMPi+))4wYFQEm}eIzre5p8?)pUWuK2hi@faQ>ul%+8$7@Q^l&1dqpX36-m*6itEqX zzJEXT@e0aN31v|4&|#W<#+#ZTi)2p&f})M7qpCFQc>y8WaviL+c4}CQ3BzT0lCE`f zLCw$OH6FO}euk))cJ);6HagC`{z?_xe;>a*cUTtL20*^U?OogT32LW)AX7}>wrgNY zmEtmCyAIPQW|o>gT(`H*S`1svgD% zRams)VS7@r@fX-sS+!JHR>15V4!xcw4JP&ZYnpG7vtno8BH<8whLsfn>vA*?OgXG> zb1HqA5_qt8(ZpjpQQni3+np>Vq_gXA`9=XR`EVQQmI!Sb4tIl05{3RV2Z3;D{NQ?F!h!b&xs$FWBB zj5m>y+zJ){Xfrd-z|FtcZvc=H=878Hw-%0R51C12&)*%o9cQ#((ZsP`;RgLzZl~o! zOsC>AptENqJ9em*dP4)60Mpd63wkGaj@A**pJ=O-j|@z>_c__wghij!H-u^q6~bzSN+zo+WY)bTkE@{ zmW}EB`IBW)$HQ)V`K2z4Y^k=Rez5@}jrmfK(n@obsM;RW)?WOS?f&-t=}ikO27-c# z&)FE*e(>X`uER~**o;?;K?&Ua)nb6B3Xyt9&=UOOx(~sJDiBYsxI5tCg9mc!y!>iE zim>B8pawl-=%AH8kkcTxH+M}Lvx7N6X*kw*qt%xqIiI#yo zowSG$C0BwAyw`s;duz8ePRyO7Z@FkLRyVz?X$j$o6HQoN5ikg;0(RK{$mCicsB7(4 zhgGJ2x+%Y5c2{%hk|l-o+QL;iZTi&K@mSEji|^t_8{boxt-G6be~q&{R@5zKg8@z# z)e^1Wm6fl@au+_)jV<<)+tdOC7LE_;&b5`>GhS=9M=3?6FB2{ZfB)9kS6%P6+^L-~ z9HIQX$B_7UXA50?L$_eIAM`|d(ZUlw~0Mp$@~#{ZdXj?a*Pc< zZ#T4GG`*|$JU->+C%$| zbL}1{8@$92s;pJr6WMQayUkoK~B+wJ`p^P2R`b*(T%R()ZJ})*jU8 zC6hJBjv2F%=OHGTk-saO(#zLTz&`S5rIn|ZJ67}nS?4JE^plyz1S%B1GTxlM*or4^ zNmIbx5nX#0Yrgu{B#Nrb!xOByQZymc6pgkCA=e> zdXT1ORc5_9N*sc*2^KvM7j75^1r3iuP`k%Er0iO%=he}A!rveyYgX97h8H%q-HQlc+HWBoC536=Kw^XZO5 zZ`Hm<=v636uBUWN+M8@j$I3(l~_M5De6Gmj<;KFYXz%R26lR$<-X>{AqE*aT1SUa~ab zB|3E2o~oysK4Z%+PfPfa?Pj;6aq=9Criw7WzC$(}(5Y10>U9}!Gu%VdK2WqzpFO)C z>mzdBqhIm5p4G{*Qw~h*a(c!&3o9(co?H`O6%VAUWb<4%JwXddb8=ub? zH+e#e7_o`*+Da&esA%-{v$w^!-CW-HA*n|^SNfbdb#+ZmyVea{WBcwKe=WbKO_x@? z+x^yiS6uAoe_`dZ$hjG9K9jZ;H0OeoYeHDq9`len7kFfJ7S}4W4}6(qGHuJ>=Vplo z6IqS;mnF3vFsH#k9uL>o46U!Zh2EgM`p_Wh(-8QO+tbjEE>(0iGiUluQN*vTzBs<~ zEq?7LK-==69>=jJ$>hYbH+xpd7?3*QApV}Iwf(?L9o3Jd2Tf5kcB z0T80TQtHc>FUwq!B7k72g#O;=EpPp4TzSr#O*{QjsGuqOP-!z}%(lF`YG7IN%;KjU zGe~{s3f$si2npF_)>IV|>pdoSH9_Thy!=9Dv3$+y>w}EuUBc?q3H5_0fI>sxJl?B3 zzdYzmRn@!vA9=s7ZmO@7*W&W^$t{4R>>#>2Ac2;y;QA!ZN|*=ar&4YMCkDmGYr)bo zjKzd(U;rq4=QJXJ#ckTTv*!;*v1@(N1GU$#JO9!;YBc#x6i9T*(#O-|O8-oQG6j+WLFw0IM-N z`yTChDh6cm-Fk_%{n~@Vy!RF+#ugjs>qp(y_twSkibMBtR|DDRke+-6_Qy{7s5H!( zi5L3a_h=4K!Cp#+GE2k7WxC;h_9`6!S^@fN)NN?2Vx|^RToh9 zch^>X?!5_d{9ma4Wb(A`I`=&A;9Yqv#v)<*IdxYMpkAhND5El(-venH#c;6dA1g+_ zXj51y_^0=r~hghpgi}f&GEdpNRmkR4FpsHbZ&!iU4YTEi7H8JkC z3HU2%y*dCg(K93eF+w~|-poF9Hi&k?WGXGb``GeXkJ;=?Bd=a9pyd+h9A})^LEtA8 zMl1w==L)j_vJPK3KF>z`s=uPV+=@{@t8|b4k;$BzQQuz0aG4k)8Cgeo>H2>cQ!6U7 zo!!Rct$irv+qwo?wJQiwzBP6MDOO$vSKL~3?wWGnxez2#ZJmHD2EF8p-PJf4itNPBtM7%#y)!(_5$=v z|0D7g*o(Vh;&gxI&(BQg)+nB70JKB`hPonkL`rV14Mi)8U-tmfR>8-+Eeda^)H}u zl+*+n3D&YzD{|i#(H#n~A%=x}i^I(~9$wRC$P}*@SK7C~qe+?airBncNJ5azd%?UV z;x-TzT^1g3gfbWm*-ZZ4h8_f@tt+{5S3qtcqa-jU$xxcqFQG2Sip%;Y!!~{&$Z@&p zXXQA{_M5@)QLplk0A;}{EdVFJ*CMfTQL+|!tnbu<$mcSW8$?qaXm5Br( z5B5MB4>L0l1&r8uv|O*k&4}O@Dm34o4J9P1jadl?4(UO~kY=Ar(Im5DWm?VK+ zN-_#!j=12vgfLs7;%L&ZeA30Sr}hPm+#L7_$(fSXli{Bp_DP@UcteOlrjLofp{u%@ zDX*Lx>8hrm^6d;^$}owy$+ArS@a1w#Op&FfT8lUfsHviG6(%N~(H!`1i%M z7sTZyxVc0}V_ChzCItIux^Q7($GMpPzGov z{Ln6X5j|Q>ssC^nO_UYl#Jr2TS5P^5W?Z=}k2N_q>5WhG#0&au{?;&L@{z4;i!;{d zj0LRcRzWlXGbMGL`(m(Uw{yJIj$XUdBbV$sg*&)<<8KRA6cI)|&yD_?3vbm6o3eSqYK17UeBiX@O&5Pt z^d8bSS2(bH-Re{BdhG7+5od5e36F(G8UPv2=nle|xQkB~>n+6YVtUoK8QXn9Vc{0= zI@#DLHj@b5NuWfoo`}Gkqwg-a*(t2(VQTgL z6*>ndULjx(j!lL4LZ)DH;<{ZYQPzKonx=j8ot_&Rk(3Z+#z{Tcx%+?tevwg8;gF5G zh}>#LSy4Qw-a0y4CA1fjQAnz-OrbE3T=rKBwYowe|2iMR$cB0&dQ_t8dTtg=VS*ylWxNp*@I(bL3}z z{m@G}5#929QqpV(CQR-5;fa2Ng|*r+5cUaOboO~MVJ!3Ah>clO^AZ9P8uw-#);FSd zhjqQ$FXv>xNH*GoIDedRS7hYpKNdwDiEtXVaf=4Cl2!m7-(rm5ZOS1t>Ux(cwh)Mq zNB3@(^Q*;;eS@?BC$oCr;5^Y#h;pHi8wUu#U8@lr^#5waVn<|ti+lNN&o)obM*c^V z_FPuE1wZ*M#NpzWipWgM*AlOW2m?KazC%C0z2Y*(jAIsQat{=jMXweDpYxyID|PAm z1(vImHH6ZZG+%UZ`YAtJSZZyY3L(5y@d8X?Nm>-6Ja*oB<)|!SDW&Z{Avj%xA0Bz& zj%7BX<=nK4z3E?c)YT3Xw-Sf1FLt9-MLV^)xLhsmUWAxiywq>7ZL7n}>j`oGc5-h{_p??zGsS=DYD4UBifewC zl<|0~DimyVk#@aW?H121n9K(1{*7Uu2xq!U_K?aetMevf=`8ROy>Lp-PIm3ki@IJ&@oLU*lTn%T z$ZNffCKU~_0}D?Rqqmbf^#=$o}845!bXn|bE@ zA1}i8^hS%u5vir*Zesm7biiPzpZ&4&eT+)Lh@m(k(^f1f+*>x-mbYcwX2PNsnNKP= zobpe2m-uC-a{G~+HY6@>J?#52{3j@j$Oy}_&IzMh6jPprUY(n@>PZcGgoS}SIyo+J z8|qK$o5*toq2;0MguyP0;_Lb+1WpY8_u$8p;^jzR{{JeqYyILoO&|j{ueDJx0n?go zFMlD+Zx0FygZnvy=nHXWYnj22)l zwg`j(j;(k3`}@Zk4jYZ?(Y^TQcoH%GujK5FtBYg2Y17ru=5oB^CMwrgkG*z{P?;ph z^-eqfUioX*W!fSf=at{p6as=%PoT zZT$16vSY2I0%dR{va^`CY#W2!3@={#<)f9?YU9R7oRIA|eO)NJ1!xM^qLueTvev)m zy!^d1qO7pL^3ORxzrOZm5?XPUe(l|$0^6}?@Y}PzQmqwx0|Ol+azVWiFu+v4&s;cx zz1ovPSslA^yS+nqY^86K7qDj>XEazfDi5em1Jcl7s<8#Os)&ItKjTq7W8B&Y@Q z22Fy(o$CMQV!gG)W>$j_8kw4EOzt}KM&Mnf>!QLy^pu^~iuxCJ(SM1IQagM0{mPBJ zB2?FkuQhRPE(+{1f4+UhLwkL42W6D8kYjM&F-=z`SiW>h=RP$^AD9iPb)U#OGB49c8IRsWB`pxROM4CxA2kQVUcvy#nBQc~qw@^49TN0YS%wehKX5@Uo&ZjNbyF#Sp z04moVHY=L6W{Vt-1a8SR!!IpU$mdn@*n)Hfk7zPV!H0O;&77U1@_x}&95xQJqRfr| z;GGL~Ci&73dRfp~N9J8zO3h+Vq#60imr)$%gyy7X=GyBI;Ekt{4skr5Bh-wF`>$W+ zn{6O2Zozg!Z5G{`AaA5jjt02E~>n4XMfuEhLd;?`^mJK-2KiQO|2jxU6r(3-G z)}c;0=i)L45O5KE`t)TMlw-F8pO=__4sHbz%l$Vcy=8z#Bc>AuI^;z8C|Su{_Q=(Z zJ8vV}a;k`5Rna#}&((jV*Y)-h(5)&8X=k?_B+?~ITl}u{-MrXaH|{Mv_uH~e1Oz;% z+vt>}2Vl?dV;O%K8ThM%%N(4XY$#xCIBpZZWSGYv@8{AHB4Ll=_xGoyGJvmAz*^hdfhE)Pl4Fh*w zzEs|C-0~PA$Rvr{A73Zx>W4Ww{*MmpdX#2G>}VJ_XE0A>FbnpV+;K`9YKZpMUH#6T z3E5HCd+mU09_o6%X-#B0Ibz>#U;EzC1{sDz7vY$2!_3pPLSnVy(4E~JnFJZ1n-*cF znk@kjNNZ(muJS6Q{Gf_s_n!JOof60yEklLHuCztog{Zq;gfD4GU9$z)pQF; zhOio~;@YUNl+H~e^$3q@O1CHKWWKEjNW06hW?OPCIV*2NH5-OLd2DoV{8D}YN_MVA z)8xNxlw#mHx>w99dR7tMsx#?t{+GuG(Z#8ZM>bhb9Z=8fDQ#s~nsBz2 z7Akm5fc+{C-S}CL(lGhbrZ2su6GA9^lU#hfvFbY-Zm-_+KP^B;E&ZUE>#F87(5=cI zt$$m731ce|bv+vV}sWA`rNe(k_! z&zu(|%J%|N4uAGVFDRNx6qzyzMG%Dcn0$c0tY{gWRXuNLwh{OQnb%DYHy^agyTCO> zj3`7JI)*}|UmSm9P-C*x1=?UmRo3$PM0JFS^#M)g zWZX*<*u#gD$u}0Rk{v@PI{-yV5)X#9_XnTUlqlr*_2X?=NUniQb@|$N+gyycM2h7` zmr$xf=fFQm2q}+DN^NTREzDk6y!iB#@!sfL zMvwMPJN`aUUGFmGoUD0Wj0aB%qN^?0BgRIC4&LoWXUR-AbRXRTazv*WIS33 zo_}vDfD=eXIcdaWhxU*hoVw5;gmd#|{AczQI2cTin#0asN4wK8Rtcyxae|U33z&KW z44HGtmV*?+5w5ivPl)ym_K?x)&fPbso|e^N#;Y%5)QN-pWbxo~x)47e{d)8$?0cx+ zg6*lcbrpDN7ZK~gyFB&}Y`Yr^p=6|^MjSp;+4!E3=;HpQk*#?9;4guWkyY~RB2ugM zq1UL=Xz7BJiYO65zet##JUKBni@R3d!59^E+kLK&?Uy7r6ci-EwKUqEX|< z?amu++9>3lO*lXznzRkSzZG$lPeOgonlkt(py2R@09jM7!vv(|xo!+r^Z+o-et>Cpz(&oSik(yvcfsG|Z zyh&y0|x`Y&@dQt ze|#Ne@X(0o?AFs6AHsJgp-!xv;=X>-r5A;8UkxI@Bz}{MC|9p|Ei)J_-h21;bo%3e zkAp|ase3&v^Ww<3vZn+th_zJojcnV9Ehh&I{fln|ixc_5;mqYCjqHhZ8w|=TRnbn` z&8?#7#T4%9V54`$euTkALmi7t3*y(MhCK4=52$sc$$%+@<+0GVB(!$C1uaP=tpGPM_dnEU>`cFALgRs#y2W=@40lTywt$_t``9q z>fLl&?Y28~#g7RlGU*uwal2(s`l7XbUaI=VCxygA`-9aPIrfdcfSJ&uQ;szBwz$MJ zA})YoDqMpg&8($ALcl*E3~1({XFZIAPBi_l^oR0Ahqx0pGE0%v0Fz6Z9N#jjj{OjL z5v|4abF=0rE=Q7xk|L~l&Cs}FLsA}`7xWjKe1{G%iw`wz^F487ZA$`SF?iM5wQrN# zR~^W*f44O#a@<+8kV6B)GK*0s=x0XG>m&CgE9*mrb*}>xL9{{q6UmD&KES{b4vc6! zn=Z9d#RiJ`1$DzV|NRfXG+z`Rm}W=8uevs-&#%|U=UqtgmF-vB0!^*T30dBD`QhR+ zU2gW^zwdvKn;5+6TB}~g&aqciP5JBOgYoORU)nmAyXLhi>HfU&f?6E}STs7_{uVB; zzX*C(fqF_3_9a}G^nYJKZW_(i+T$;zli&f->7l!{#j@JCh<2<;d8P{e8|H2|Lu1?j zzMK82-e;}bp}txEVZNDdmp8R>a%>ba$HL=WWVgQ*t-WfT+^XBRn*F7`>CZ<~`syTg zY~4&rX{Pp=8-J^xU9X(#{j|Zx3frS}7@Bc8iX%jWgG#%z3HMsFrqj<7RbHgg+ zO{T1=nb|^E6{*L_yfr34GE&($hNNTu_kGUEdCODR<=zif2s7 ziwK*hY*ukeT8`d!!)yP#mU{T(Im9p0c?$W0?lD>B43XRiOFj4fdEMk}cV*+`t7@vA zp%DO}R%iiVFuI0KL*7iGXGrZbp6jEV(L_sKFJugV*{Y z?{J=oh0U;G3p=EXVQ|34A6LRW3cW zVS)Qz-9ERJw3o|eT0eNzYKv~4MGQ(NONs4Q&El`FC(temtR{_n`{C;nzisipV)IIV zjYHJ~Om~&hiz$O1H+`O#Ced}`cj1H7ECwZ;wys?{$wWsg-*OCDxd||(Q<17(a<;cT z`bMgrc_sieQbme89Fv(`L%UlSRjlX9FR31|)wSDXMP?R>cU}}-0y$E~w2EEkt=l+R zzU+24waA$S%HY*{z=i2X)_$KPL(lAByG;eCu5>Z$XSFo()(vS8YdqIoH)LL}$=PoN zJR?|cC`0I(Iz_cE%r=4{XtUclJ6cbED~~H>h0)m<3L1$~XSXUC`TO-qB5=Lv@;kz# zqt!!R*dlh9w{D+1(cYSAdRpqs+ViP2a)e+iONxW&dWlP{z19AIE=?)u-T29qZ_{e* zBnKmj+$Ttm!k&X6jXM&jcHPrk60y0bO``*#o(_c_$z z8nnvi;>>BXd=B$KyzMlp@^Cw#bhybI|Ni3|bDvMj7W3!JM`i@CY{E?++qt=tqNrJe z6Tv?dX=zq(>S!H0>2-S^srSH+c*VDYrzb{!Xy5X!>LxT$2!2}16ANi6*P!R4Y#d@q zFDZ~9;YGwQHhtW5vA13C+W)GhettpP&qOw5yc;c@~d1v37v)R)9(<8 zd%fnjTcdVEXC3UY?#;bsS)aBI(crJ>)!q~m=1%e&@W;keUJI!!X<(G2!g=7kZi;j% z=t8oFb?}A`mMB95A(?#uNuaZ}9+gH0Tr6!}P=o9f_i5<0( zMt^r%uX%OkwrMv}6Kam3gvz2DXV%a*MvWEFeXT2v%#?+{=8J~)OKimOmfb@H2Nm$%PXgyl#JG&A!JS3<&c_$Z-E%)BPhB9QGKM ztWo>Wn!nUjX>aK2iBY!`f#sM~#O5pQrMAg-d5<-USJhs&ow<<)7fHSd%KDNcOM<^` z5i1@aAcApP*pp5#uLn$@nXHjEx%T?6_UM?4+n3TAhIl98_d$p_9zBqGyEJC2zHI>? zdCk|+nAyBYE*0)a3cZ;#JFS^L^bMfSXgX6bHQx>+lL7nR{Jv4iQ)V3|XZy+qLJ+v7 z!uE6GKM70$xh>Q(VRwUeOEJVHc7lH|F95gpQbATa9YhjUW@m3cA`jbL8| z;X2zWP!c2U+Unebw`3q^tC+XgSVUU@+JXW^fxcN>$m`e!2RU}ov<|&c$OhP0U|4!S zvHp@Ni4a1=VjgH<<%4H>fbT+Vqg6Paa)Ui6KtN-(ol#DvTX zErs>=?c3`-|3`NYHM6v#Ha4A@YfWRh?&sIqIq$P(b^c*Sr7v+c)B1fp9rK7_?cla^nlBJ4c0)j<#gp3nhe}( z%nvS@daku~o*B$5x$xr4lYtm0M6NM~2Iu9HC1g8GZaDOOjMdaOZw58~>3+tg4siM6 z6#gB8rarAF(`p5wY~i~?x%_jWH0?}Nv|E@~Y9kIS3U12W=$Ad-AAZfU%BUv@HMa(s z_mL$WUigJ&8#ivGbO~blg)71;Q|{lNaPH?2WH;bQ-E%FMEjwSbE1%i(Nb?&+zbz^0 zy*zi=N19+_pKhbsU2@Z55`*!?RmV7k1NQ#9RkQF$N%ApWN+E0F8WvTu!j%*tzw2n= zxU>c&cYQ8@*`Z03CYPh5F8!p{nwLDbyFb(~&hG zi#|AN5b-JVZ)|D@A3HJq2?4-NdwIXVpHA}CznT?NTR;|=0B`_{aEpCLZ2T^?HI0CT z^q?CcQ@zWYwdVW%{dY_5evcmYrP~KXlHq9)Hq(G&R1iTWVr}~xW?U?<|7=Po8BW#T zE0$*)IDCB_1o4;k_)4$oti@GHWx>1H3@;oZ zlM8F>+AF;%2d*T~i<^D)z=1BscfjYC>H0dc*57AEoJn+hww4^(PPkt2uNd=oalf|` zLnNb%`G|>mLlKU6@;npWZkcA1+r15c?;;c}j9%CZ-XhRJ%a+eCIvp4FAg{q_tgtB9 zC0|rxCuLMOOWrdqa5~R6Z_;v)!KBdl^1l~TY1LrNkW~+w@=9;$j-mA7G3b4xeS6Vmpuwb8ep#ipnHc^jAO~ug88XvASCBM_Y@!}_t zsV=GF(?2XjgLUY8rslN+wH_6v34HF=aIr z&=S;Og~46n&N7f$A>fq)4fnbfzm=UfoA>s2svabj6nTc4_OSRTuXAT5u$Z#Wu7xDt;AI6)wn3*VFdszQ`op8mQ!pa=Z)`K*qu$9Px(U@f$< zIaA^E5dy@|u-j3)zEn>C%}|gdMqvdgPf0!&;4$=AOw16GaL%8fTe7;kq9T#%Ks?J7 zm`!QJUm#$G{%{tGbXnF^7w7Mv?bxSf+j6Taxw*f` zOwX`?Vrkx-ZxY%cmd*uQDvgv!=`S$_=L_4lU@ zh3O+GhF>tJ7wysRxt8n4EIc9_Ez5*9>;z-6o6-kYl2Fo+7TM#{rAwi?Qf{*pq=kn# z@Z7hrnMxBafnZr`Yu4q@pr}ATEATi9WTN0V@5s2DU5@5PM(b4Y0EKYL{`c2irJ$&^ ztLt;fZ1m;<;HGLNQ;78S$D;7mwS6iPk&7_hi|mAL@@?}--ny$7e*~`8m5HP5-%7(v z|GE?wR<^%%)w1p1H!vcPj_IE%?a~equ+fx!Kv~SJT+gtn(K4XhnlYMRS?CgX7IfiM z1G>?n4(r3o308*qkiDw6WxNKev~7NVE!fdlyiRT$y5L58zK0^P%6{UFTo{$Dh+A0b zLw$gEsU3#(VMfXM!1y!^)j0U}g&;4hRyT4UGxGP>PWg;>l!;S*U8gjU9a>T&NkirF zpPImhOD1H{g|xr9ggUc7tFQTDb0dt*KN{VetW);>?2;NB-{N-%jpy^~rXQ$t%ck&V z-+x7|D?$j4GTzyr?zqZyh75_BR2|46w~*se^6Cii&|b6Fv;`|xTrAZ5v7cY=Yrbds zn$pNINM#~AuU?|!#2tRHse{3a6Ukkp^RI7gOS8e4)E&31)D^flMAyquhLe8F?;d{F zeD@vkc<s{OPAh84K^c1^GtnK%cp#A^66&z$Y5E8CCThb*xpg@AmXtS??>-Le4sgkRIXZ@a zsx-nnQP9L8c@~3ZPNe7D>C@O*KKsSE(T{n|P(Q_=OQ}P2h7N6mCRO%anXJIa^E?bc zB}ga+4e8w{oytziN<|mkkbf7Dtm@e@q&d>iHBcf$$=LwY+yiWT4~g!vfPe`MxK^ku z_}*-`V;QW1=y@zR=oIhyGtQOw9L~n&+dI-asVRP8@p9PY1QxAy0w3B@x@G%x|7*_6M;ewUF_Al^XNGv@IRw!Fe1f!v6Yn(Uwt4E|FN!L&gZ&bxNyM^0Bazx z55L^?is|G_2~};{4O!($T^zXHdw*Ve&9~z<`_j`MKi-27Ycy47CvZ>sB;MNTixw@4 zOBrk!7VY#hgtL!tu(waI?%g};oMexgN7@mtI6o$AfSF1i@qs3F^ypa}($RetpP?^P zs-i3Z1>T8xbT|G(k=>$2#=I`4d8JYjAKicYwBpEJi=4=ecOOVFiCj-I9XQNr_?)X4 z%!eXBrvUbaFxr;yGgVL;J?tXwT6`$q`2BMb-SacXu?AOcME5aR=>#0=xnRpFPwta6 zn8t>A4?GM=))tzaQ)M)j>}O^->^pa^$CnRjJ6HkZaI`$iIP>sZ`ax$S3y1UP<+cE< z_vqGb+{K)~BdoR5d!9qP2jnsiaPTxu=L~3F1mgP$NahroR5seh*?Epe1#*%432iO@ zVK|HuCXCbiH|Dlchx~blpWqyP7%w z8&5xvofbH}$MVB%;ut%?J@sQ65;1Il!_~>iDO5oBA3Qj3rl6~sB#+zL+5}+v(18xj zN8t;m@_9>^6!FzifWV=i#b=9FjVzxLI*K(^f;R0>MU_?4&71}6c~e^2C#RgE+Yb=` z%llLhIRS(IefD}NV$Y$JZiegs^+W(Vo-qTnrcXC&+F=9{GTp+jTnVCHngMs27qfbY zcwL{RrUvn(QZfc%%zl=hK3n5v@6=+2qFLyK(W7RaU{qQf9m#+Bq;u!-l<#7Kk zGDcphaKQM^|Fp`Pv~PUp<^AaN?@JTyekCYq)O(A+cZMh}d_C8$@e5>byF}YxHIp{Y2;8dxM!s=u6QV((v7~&NIm%J zLZ!a>GS%l-dYbYn-id+ccX5Q=XQ&lO=Ye_Eq@bqT=Yeh3btfpS^IUyiM_Tx! zgDf#ucU4@)PZjf4?j7gKzZDgG`!J|ir$dM1OTS>1J@HIwp?Q@XNO9d0S+l>eck^Z2 z>W7-V4Za&0+`bUOw7P=${C(z@78X+wFLbfCwx(k2q;vA?*L8J_C=ypKp}oC-^X8~9 z)$@Js#s@$7gxGAct?fOfg{qMm8B`J}+4DMeI@PM*<&>0^ZTXFZBU`EKZ<d&er?(+oeEzvFX;&7`@Pr(`Cqt9-Sz_+VA@Uf=(5CDD_c$V%p&^si_A z>|aIqVZ;2ryd+1XjuEP$H7LywSgg5v_2sknBgcHNDxIY0K6r3+p4_|3m!}uHoi-f5 z%W(qIpxuN4Cb%t0LG`tHpG5n7haT=a(5;LX7w-@Y|-U;1IPY;2YZuJ`*a zPx+R<&c9Ej@<;ob=_I7=CZ_&;)EAen)_JR@?__Gle`vX0V6T>6!m3rnQJ0Z2!WY z(?S#ZEvANjZoX>@Ql2d~=PK#BKPSPH#8pg+%-30MwsDaz9g4($B= zLPJxtht{BeQ$nAlr1=KU&4tR0suN&i@6=iuN2 z9@Q%I=Ki@5)HHmpatf$171N&Buv5fDWr6_GlQ7H9(Rt6>K}@jl&wXh<3Ham0nKL^$ z9ZA?p1iYgn52%{;Psp^mQ~;8|K+A~o!H_U9QIQuN=2`!D|Dgb`rPQ<=F)6x{T3b>& z0s15=w&m{|C)dXV$gM1Sp}T3K`!30_Vm$Lr@MI=Jr7ntL!_uII#kY0P%{@LGAA*=5 za7k$b4GPA={%fyizpO}YDKGZtkLe91tLW@m+YI-&MMZ;qIXOD+`IBR0_{qrx`G8o- z(8dTUFFss4WZAwL^X*QRe|E!-4kI@;(pgq@tY6PprEML2mKpgcI=;y{2)=;PW^EhoeXjY{JN4KMq zdn56y_ufW=AM9h$Ja5mLtk}#@GZV#ofa215gPWytRI4fOBqu*OaNymgfe8uH?bdl} zpIEP1Dun61{CvxUHB34Ob{Z2l84!+%+)v4pJeqLhN>xepz;2g6bUbeJR=ubB_2Ab% z(+_GHpQC52W5f~Am6B=OsbATv9-4n2-mpP~mhbwlwaINV!vCa}@rN6Xvg?j7gTR2i zl8vagIx)a0GXG=eW#5i{uCDH8Xqd3{Ejw3U?2gmNw$|_lRwTmql zLM^2ebWAg0o{(xi13|fW^JY+z(n2UXGgH%hK3+cnCu~tBzj^=uMQEk#=l9K+7rHkh zVt^Etvu4aN2HX!pXt-DQG221=#*b!Qgn&uTA>6^{QW&_(TnLlSv*TE0g!OuR*pE+j^OpF(A*n39q%(<2yrL}s@@gfS~ zd+0J5{vBswbZ_RvH4kaiCjjBMsyoljER~4655Nc)uV2C(O{I18ZPNLpJ?q?xI=0}V z!_0}Spz~smc~epn`r*{8Ast&ze0|&Q!|X4-1dDy_U-!D7(IzYT(>*&6Dz{YrC677~ zgzYS_`e&l^(kRg;=2f5O7IVJYLDz@JR59JmmTvM7s_hwk0FwbgRdw$WC$Uf>}s(txcTHsdIGmmT;{hlMv4&sJI+dG7oyOUtPY>IpAbYwYZOd`a$@$j|%TF#-i2 zZ!RX%L6e#<4G_3g?9O21PiO!AfTU2F#mQ2Q+;0lg~e&(q^Xvh#v-l^N9G7L1-sH<4fG^iEA zsZmp>?zz=(J7n%j0Mf)XnTzmQ|d_GR219wwPgw2SKCHS0~FEux>u zJ6Ym0BrwtFB(VMwDAh*H|4mBaXUH!0{*tKN$D_~6%LAq zQpU?Myh~@zm%tvJ4gf5E=8}KSi`=?rk0*f_BUjJN3fv5wPiA!e_->Qaxl|dEgsVVi zgy+2)P z|GL=Evu&F;x0r@f7&D0JzuWwr2b3Pd!wuct4y581=+;6Ytu+T?1Ni=u0Z+6CLQkia zO{^QEpIF{@b|Yua{#Hg8BJK|eIXACuyx1}+Zp_TCpIB5o_)x@x!G|nwQEywJ#pF-P z^jY~+l&W6=UUg~z!K5Za@ubhV)2Cnil3THQOH`e_?!0QXdiDAWm0~ZsRmA_%i=aH% z;_K`CboMh>u{R@E0kYb{NjTej)vX*fG8yaVwJl-nc~`eq!SE)$>GK{gShH%?vMR5E z$+O1%th%;x;3H}_kFk~_@e+HW|(BK6aO zNCmo^;^}v+4uQVe72kg_>ultWNSgbsPXTg)54_Z9-fxL_5bV_&WB>}LMeMwJuNhz< z0sB<#SAdidIheoid9DS|WB|mD_Q;V77V3@IyfY%Cjp~Lesw-)+PN64MG|jilF67>u z(qxN9dvN|bWzzk3M!k(*dmcfB=u#w_RX`;Hr7|)yjOR|u18vL>ioDsEslgH{plDxm zvd_FpBd@uXw-*L+iFuq+!Dr==DJZJ9ptgA}I2=v8jG$=LVZ{9R%j~=bOBeq#4Wvw; z;k2@5kfHJ13lZQ>u{)v~)wQ)VUcjJ0L_`hayXB2@8xaxWVF0l9b%1qVgJv=SL4sRF zTFU!ug)JO;WybdVezT{-_lsm)Fs%+9nzB7hsu7@+@!X3MptXm?JuDPu4l{x?RGhl! zTqu6^st()XmTJ!{VLQAkKtdN{QI!BQ&LpW5#Kq6PWIT7;3IPFRhJk=;^y5O;0Ojk_ z$_8ENDmn_cg9lyDqa>!N3z{`zo(tTE$6$>XmP?m*#h&XUs%#j+M8-d=LpuR>umv@+ zNSL~sJO`m-L}8DRsDQzBfSV5khRrn()PL4YSjoThhP*GdI->iC5jpP2vt{VI%-g{C zA*Fm#kt+5HYHQ02U1R&Q;;4d}Au2}D-57!gGW0HwK*%lx5ET{yHNw?DpYWH5g=c)9 z2V7*@)Mo`10G4+_k5+P56^XR)GQHqGmQ;gAa_q4E&UwwK=pE6~ zgS$>XtU!~>^RT`BTTO&yp3n1d_VrPnhMju!IF;P-#W&@X?139Zge}9!|M^FzH$cmy zGZlFxXFUi1{l_98lmII0IBF zK1YT5`T6C#wXGS*dGYUx{>elCMhhj9Z3>7&cJFXS2}WK;U{q`R)9^zmNFX7}KVo~( z{$a-+7MDakPp2ONUW;8cPT!!AIfXz7#4r3fpbmn&v8)A7`pSZv%5*3Sg-q~%_fCZ$ zL^dNM1tnr&-0`TUqF*@=@)E7_9uSG?PjkZJr62gNHRh%@Tk*F!4Xi_F1L|`}M#&!y z50^Ar&RNmQqqXKk8FJAse-D)evq(e%!M=_P?B3RCU@QzDHNEg}yEug?e8y6*hv(ja zFED#@oYgDhB)b?gRn3|%;0Ewo8;xF-uvM}6$&U=~Axss@KXQlo=0oZQf8w>$K+Tl# xs9ok?u_^@lBdRfF)$;$n*RKA*|D&eqrYXJs$IaM2P{IFA7&CQrn6cH?{{#A6GUxyR literal 0 HcmV?d00001 diff --git a/_images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png.map b/_images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png.map new file mode 100644 index 00000000..8be6a309 --- /dev/null +++ b/_images/graphviz-f3da9712e3905cb30d4ae47e7e62c2a1e0fece65.png.map @@ -0,0 +1,2 @@ + + diff --git a/_sources/developer/build.rst.txt b/_sources/developer/build.rst.txt new file mode 100644 index 00000000..1bb4e1ad --- /dev/null +++ b/_sources/developer/build.rst.txt @@ -0,0 +1,48 @@ +Building and running the unit tests +=================================== + +x3d2 is in early development phase, and there is no main executable +yet to be built. However, currently implemented functionality is +covered by unit tests, which you can build and run on you development +machine. + +To build x3d2, you will need git, a fortran compiler and CMake, see +:ref:`tooling`. + +Start by configuring the build directory: + +.. code-block:: console + + $ cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug + +To configure the build with the NVIDIA Fortran compiler, you can set +the `FC` environment variable to the compiler executable. If you +specify an relative path, it must be present in your current `PATH`. + +.. code-block:: console + + $ FC=nvfortran cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug + +Setting the Fortran compiler to the NVIDIA Fortran compiler will +automatically include the CUDA Fortran source files into the build +tree, which are ignored by default. + +Once the build directory is configured, the tests can be built and run +as follows: + +.. code-block:: console + + $ cd build + $ make + $ make test + +Note that ``make test`` is only a launcher for the ``ctest`` +executable. By default ``ctest`` does not show the output of test +executables on failure. If one of more tests fail, you probably want +to run the tests with: + +.. code-block:: console + + $ ctest --output-on-failure + +instead of ``make test``. diff --git a/_sources/developer/contributing_guidelines.rst.txt b/_sources/developer/contributing_guidelines.rst.txt new file mode 100644 index 00000000..73c62a3f --- /dev/null +++ b/_sources/developer/contributing_guidelines.rst.txt @@ -0,0 +1,145 @@ +Contributing guidelines +======================= + +x3d2 is a collaborative project, open to all. In order to enable +effective collaboration, however, we ask that your contribution(s) +comply with a set of ground rules. + +In a nutshell +------------- + +- For any contribution not covered by an existing issue, **open an issue + first**. +- Respect the commit format. (:ref:`Install the git hook! `). +- Only commit changes formatted with `fprettify`, using the project's + configuration. (:ref:`Install the git hook! `). +- Strive to contribute **small and focused Pull Requests with detailed + descriptions**. +- Add (a) unit test(s) covering a new feature, or (a) regression + test(s) for a bug fix. + +Issues first +------------ + +Issues are opened as soon as possible, particularly before any +significant implementation work is carried out or any pull request is +opened. Starting with issues greatly facilitates collaboration: + +- It encourages developers to write (and therefore think) about the + work they plan to achieve. +- It helps maintaining a shared and up to date record of current work + (known bugs, current developments). +- It helps coordination between developers by sign-posting who is + working on what, as well as what is not being worked on. +- It allows discussions between developers on how to best fix the + issue or implement the described improvement(s). + +This doesn't mean that you should forbid yourself from exploratory +prototyping until an issue has been opened. In fact, prototyping is +often helpful to write the content of the issue. On the other hand, +do open an issue before commiting to a particular design or +implementation. + +.. _commit-formatting: + +Format commits accordingly +-------------------------- + +Commits messages are formatted according to the conventional commits +specification (v1.0.0). Commit messages must respect the following +structure:: + + [optional scope]: + + [optional body] + +where `` is one of `fix`, `feat`, `build`, `chore`, `ci`, +`docs`, `style`, `refactor`, `perf` or `test`. + +Breaking changes are specified by adding an `!` before the colon `:`. Example:: + + fix(allocator)!: Return 1D arrays as data blocks + + This is a breaking change because e.g. the allocator used to + return 3D data blocks. + +In addition, commit message header lines must not contain more than 68 +characters. Lines in the commit message body cannot exceed 72 +characters. + +.. note:: + + Commit messages in x3d2 do not use footers as specified in the + conventional commit specs. You are welcome to use footers in your + commit messages, but know that they hold no special place in the + commit format policy. + +A Git hook is provided to prevent you from registering non-conformant +commit messages. See setting up your development environment. + +Fortran code formatting +----------------------- + +Code formatting dictates things like indentation levels, number of +whitespace between operators or use upper/lowercase characters for +keywords. + +Because having to learn such project specific rules isn't terribily +interesting, all Fortran code in x3d2 is formatted automatically using +`fprettify `_. Some non-default +configuraiton options are specified in the project's `.fprettify.ini` +file. + +Note that a a GitHub pull request will not be merged until all the +associated code addtions conform to the formatting. + +The best way to deal with code formatting is to **automate it and +forget about it**. To do so, make sure you install the pre-commit +hook into your local git repository, see . This way, `fprettify` will +run automatically each time you commit new changes. + +Pull requests and code review +------------------------------- + +Code review is a fondamental part of x3d2's collaborative development. +Particularly, GitHub pull requests must be approved by at least two +maintainers before the associated commits are merged. Code review allows for + +- Gatekeeping, by preventing the integration of changes that are not + up to standards, introducing bugs or potentially disruptive to + ongoing and/or future developments. +- Knowledge transfer, by making sure that at least a couple of project + developers have an opportunity to study and understand the code to + be integrated. +- Training, by giving new contributors opportunities to get feedback + and help, as well as chances to review contributions from more + experienced developers. + +Poor quality pull requests can however turn the code review process +into a bottleneck or worse, lead to poor quality reviews. In order to +facilitate the code review process, pull request must be both +**focused and small** and have a **detailed description**. + +1. Pull requests should aim to merge a be coherent body of changes, + targeting a single aspect of an issue. It is much prefereable to + fix an issue through multiple pull requests than one big + contribution. +2. Pull requests should aim to merge a limited number of changes. As + a rule of thumb, pull requests usually become much harder to review + beyond 10 changes. +3. Pull requests should come with a detailed description containing: + + - One or two sentences summing up the motivation for the changes. + - A link to the addressed issue(s). + - A summary of the changes. + - A technical description of the changes. + + The description is important for archiving purposes, but most + importlantl in order to guide the work of reviewers. + +Note that the points above are guidelines as opposed to hard and fast +rules. For a given pull request, the amount of work required to +review the changes will vary across reviewers. Generally, however, +please **empathise with your fellow contributors who are going to spend +time reviewing your code**. Aim to make their work easier, and they +will do the same for you. diff --git a/_sources/developer/contribution_workflow.rst.txt b/_sources/developer/contribution_workflow.rst.txt new file mode 100644 index 00000000..f65ea4cc --- /dev/null +++ b/_sources/developer/contribution_workflow.rst.txt @@ -0,0 +1,40 @@ +Overview of the contribution process +==================================== + +The graph below illustrates the general process for contributing code +changes to x3d2: + +.. graphviz:: + + digraph G { + review[shape="diamond", label="Changes approved"] + commit[label="commit changes locally"] + + PR[label="Open/update Pull Request"]; + + Idea -> "Open new issue" -> commit -> PR + PR -> review + review -> merge [label="yes"] + review -> commit [label=" no"] + "Pick existing issue" -> commit + + { + rank=sink; + review; merge + } + } + +Contributions are accepeted in the form of pull requests targeting the +`main` branch on the x3d2 GitHub repository. See `(GitHub docs) +Creating a pull request +`_. + +By default your GitHub account will not be able to push changes to the +x3d2 repo, and you will have to open the pull request from a fork. See +`(GitHub docs) Creating a pull request from a fork +`_. + +Note that the whole process is **driven by issues**. If you found a +bug not currently referenced by an existing issue, or have an idea on +how to improve a part of x3d2, please open a new item on the issue +tracker before opening a pull request. diff --git a/_sources/developer/dev_environment.rst.txt b/_sources/developer/dev_environment.rst.txt new file mode 100644 index 00000000..a2f1034a --- /dev/null +++ b/_sources/developer/dev_environment.rst.txt @@ -0,0 +1,35 @@ +.. _devenv-setup: + +Setting up for development +========================== + +0. To begin with, make sure you have the right tools installed by going + through the :ref:`required tooling `. + +1. Download the x3d2 repository from GitHub:: + + $ git clone git@github.com:xcompact3d/x3d2.git + $ cd x3d2/ + + The following commands assume that your shell's current directory is + the root of the `x3d2` repository. + +2. Install the `pre-commit` Git hook into your project-local + configuration:: + + $ cp githooks/pre-commit .git/hooks/ + $ chmod +x .git/hooks/pre-commit + + This Git hook will cause the automatic formatting of all fortran + files staged in your commit, using `fprettify`. + +3. Install the `commit-msg` Git hook into your project-local + configuration:: + + $ cp githooks/commit-msg .git/hooks/ + $ chmod +x .git/hooks/commit-msg + + This Git hook will automatically check your commit message against + the commit message format, based on the conventional commits + specification. See :ref:`the contribution guidelines + `. diff --git a/_sources/developer/index.rst.txt b/_sources/developer/index.rst.txt new file mode 100644 index 00000000..b2599675 --- /dev/null +++ b/_sources/developer/index.rst.txt @@ -0,0 +1,36 @@ +Contributing to x3d2 +==================== + +Fixed a bug? Have an idea for improving x3d2? x3d2 is developed in +the open with a license that allows anyone to: + +- Run the program as they wish, for any purpose. +- Access and study its source code, and making changes to it. +- Redistribute copies (source or binary). +- Distribute copies of your modified versions (source or binary). + +Particularly, we encourage developers to contribute their changes back +to the x3d2 project. The following sections describe the process for +doing so. + +.. toctree:: + :maxdepth: 1 + + contribution_workflow + tooling + dev_environment + build + contributing_guidelines + style + writing_docs + +If you are looking to take part in the project but don't have anything +specific in mind, you could consider: + +- Reporting (a) bug(s), suggest improvement(s) or share a user experience. +- Adding documentation or improving the current one. +- Working on fixing issues or implementing new features. + +In any of the cases above, your entry point should be the `issue +tracker `_ -- either to +pick an existing issue to work on or to create a new one. diff --git a/_sources/developer/style.rst.txt b/_sources/developer/style.rst.txt new file mode 100644 index 00000000..17fbdb44 --- /dev/null +++ b/_sources/developer/style.rst.txt @@ -0,0 +1,157 @@ +Fortran style guide +=================== + +Basic formatting +---------------- + +Identation, whitespaces and line length are enforced by `fprettify`. +Project settings are defined in the `.fprettify.ini` located at the +root of the repository. + +In most cases, developers are expected to install the associated +pre-commit git hook. Additionally, it is recommended to configure +your text editor to run fprettify for you (for instance on saving a +file). + +If you want to preview changes without overwriting a file, you can do +so using the `--stdout` option: + +.. code:: console + + $ fprettify --config .fprettify.ini --stdout + +Naming conventions +------------------ + +In the following "symbol" is a catch all phrase for variables, +procedures, derived types, type components and interfaces. + +- Symbols are name using the `snake_case` convention. +- Variable declared with the `parameter` are named using UPPER CASE + letters. +- Symbols should, as much as possible, be named after they meaning + rather than their mathematical notation (.e.g `velocity_field` + instead of `u`). + +Procedure definitions +--------------------- + +- Procedure prototypes spanning more than 79 characters should be split + before the first dummy argument is defined, after the opening + parenthese. If the list of dummy arguments spans more than 79 + characters each argument is defined on it own line. + + .. code:: fortran + + subroutine my_long_subroutine( & + argument1, argument3, argument4, argument5, argument5, argument6 & + ) + + subroutine my_very_long_subroutine( & + argument1, & + argument2, & + argument3, & + argument4, & + argument5, & + argument6, & + argument7, & + ) +- Function prototypes indicate the return object type unless the + return object is an array. +- Functions are always defined with the `pure` prefix. A procedure + with side effects must be a `subroutine`. + +Modules +------- + +- Module names end with the `_m` suffix. Examples: + `module allocator_m`, `use allocator_m, only: ...`. +- All module components are `private` by default. +- The module components are always acessed through the `only` keyword: + + .. code:: fortran + + module a_module_m + ! Non compliant + use stencil_m + ! Compliant + use stencil_m, only: stencil_t + +Derived type definitions +------------------------ + +- Derived type names end with the `_t` suffix. Examples: + `allocator_t`, `type(stencil_t) :: s`. +- The `contains` keyword is omitted is the type does not define any + type-bound procedures. +- All type components are `private` by default. + +Custom structure constructors +----------------------------- + +- Are named like `create_[_]` +- Are declared with the `private` attribute +- Are defined at the top of the module's `contains` block. + +Example + +.. code:: fortran + + module square_module + + type :: square_t + real :: size + character(:), allocatable :: color + end type square_t + + interface square_t + module procedure create_square_from_square + module procedure create_square_default_color + end interface square_t + + contains + + type(square_t) function create_square_from_square(sq_in) + type(square), intent(in) :: sq_in + ! ... + end function create_square_from_square + + type(square_t) function create_square_default_color(sq_size) + real, intent(in) :: sq_size + ! ... + end function create_square_default_color + +.. _in-code-docs: + +In-code documentation +--------------------- + +The body of modules, public types, public procedures and public +type-bound methods MUST be preceded of one or more documentation +paragraphs. Optionally, the body of private symbols MAY be +preceded by documentation paragraph. + +Procedure dummy arguments, interface components and type-bound +procedures declarations MAY be documented using an inline comment +either on the same line directly following the statement (using the +docmark `!!`) or on the line directly above the statement (using the +predocmark `!>`). + +x3d2 uses `ford `_ to +extract in-code documentation and generate HTML pages. The syntax for +in-code documentation follows ford's syntax for comments. See +`(ford)Writing documentation +`_ + +.. code:: fortran + + subroutine add(a, b, c) + !! This is the first paragraph of the procedures + !! documentation. Note that it starts with TWO !. + real, intent(in) :: a, b !! Optional documentation for dummy argument. + real, intent(out) :: c !! The result of a + b + + ! The line below is a regular comment. + ! Make use of the well-known the addition algorithm. + c = a + b + end subroutine diff --git a/_sources/developer/tooling.rst.txt b/_sources/developer/tooling.rst.txt new file mode 100644 index 00000000..82b67e97 --- /dev/null +++ b/_sources/developer/tooling.rst.txt @@ -0,0 +1,80 @@ +.. _tooling: + +Required tools +============== + +To contribute to x3d2 you need a few things on your toolbelt + +- A Fortran 2003 compiler (e.g. gfortran) +- The `NVIDA HPC Fortran compiler `_ [optional] +- The CMake build system +- The fprettify auto-formatter +- The FORD and Sphinx documentation generators. + +The above tools can all be installed via you distribution's package +manager or the Python package pamanger `pip`. + +.. note:: + + We strongly recommend to use the `pipx` wrapper around `pip` to + ensure installed Python packages are installed into isolated + virtual environments. + +Fortran compiler +---------------- + +You can get started with the GNU Fortran compiler + +.. code:: console + + $ sudo apt install gfortran + +CMake +----- + +CMake is used to configure the build. This means, among other things, +finding the location of the required compiler and libraries, as well +as resolving the links between different components of the software. + +To configure and build x3d2 you will need CMake version 3.18 and +above. At the time of writing the currently distributed version of +CMake in Debain stable is 3.18, so you should be able to install CMake +from your distribution's package manager, for instance + +.. code:: console + + sudo apt install cmake + +Recent CMake versions are packaged for a variety of package managers, +including `pipx`: + +.. code:: console + + $ pipx install cmake + +fprettify +--------- + +Auto-formatter for fortran 90 and above. + +.. code:: console + + $ pipx install fprettify + +FORD +---- + +Documentation generator for fortran 90 and above. + +.. code:: console + + $ pipx install ford + +Sphinx +------ + +.. code:: console + + $ pipx install sphinx + + diff --git a/_sources/developer/writing_docs.rst.txt b/_sources/developer/writing_docs.rst.txt new file mode 100644 index 00000000..41910136 --- /dev/null +++ b/_sources/developer/writing_docs.rst.txt @@ -0,0 +1,47 @@ +Contributing documentation +========================== + +x3d2 uses both `Sphinx `_ and `ford +`_ for documentation. Sphinx is +used to generate the user and developer guides (i.e. this website). +ford is used to generate the API documentation website by extraction +in-code documentation. + +Building the documentation +-------------------------- + +To build the user and developer docs (Sphinx): + +.. code:: console + + # From the repository root + $ cd docs && make html + +The above command generate hmtl pages in `docs/build/html`. You can +display the user and developer docs by opening +`docs/build/html/index.html` with a web browser. + + +To build the API docs (ford): + +.. code:: console + + # From the repository root + $ ford ford.md -o api_docs + +You can display the API docs by opening `api_docs/index.html` with a +web browser. + +Writing user or developer documentation +--------------------------------------- + +Documentation sources are located under `docs/sources/`. They consist +in a hierachy of reStructuredText files. reStructuredText (rST) is a +light markup language similar to markdown. For an introduction to +rST, see `(Sphinx)ReStructuredText primer +`_. + +In-code documentation +--------------------- + +See :ref:`in-code-docs`. diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..452f2394 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,21 @@ +.. x3d2 documentation master file, created by + sphinx-quickstart on Mon Feb 27 14:46:56 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +**x3d2** is the current codename for what is to become Xcompact3d +version 2.0. This project is a rewrite of Xcompact3d leading to + +- Improved serial and parallel performance. +- Support for NVIDIA GPU accelerators (using CUDA Fortran). +- Improved modularity and testability. + +Contents: + +.. toctree:: + :maxdepth: 2 + + report_a_bug + internals/index + developer/index + API reference diff --git a/_sources/internals/allocator.rst.txt b/_sources/internals/allocator.rst.txt new file mode 100644 index 00000000..0d6101bb --- /dev/null +++ b/_sources/internals/allocator.rst.txt @@ -0,0 +1,110 @@ +Memory management +================= + +The parallel processing carried out in x3d2 requires that the +computational domain is sliced into slabs along a specific direction +of space. + +Data slabs (instances of the derived type `slab_t`) hold a pointer to +an `allocator_t` instance that is responsible for the allocation and +dispatching of memory blocks to data slabs. See `(API)allocator_t +`_. Whenever +data slabs are no longer required, the associated memory blocks can be +released to the allocator, ready to be dispatched to other slabs or +objects who might need them. + +An instance of `allocator_t` maintains a linked list of memory blocks, +which each element in the list labelled with a unique identifier: + +.. graphviz:: + + digraph freelist { + rank=LR; + memblock1 [label="memory block\lid: 1"]; + memblock2 [label="memory block\lid: 2"]; + memblock3 [label="memory block\lid: 3"]; + + memblock1 -> memblock2 -> memblock3; + } + +Each memory block is an instance of the `memblock_t` derived type +(`(API)memblock_t +`_). In +addition to its integer identifier, a instance of the `memblock_t` +type holds a 3D data array and a pointer to the next block in the +list. + +All memory blocks in an allocator's list have the same size. An +allocator can be created by passing in the dimension of the memory +blocks: + +.. code:: fortran + + allocator = allocator_t([32 16 32]) + +Given an `allocator_t` instance, memory blocks can requested using the +`get_block` function. + +.. code:: fortran + + use m_allocator, only: memory_block_t, allocator_t + ! ... + type(memory_block_t), pointer :: memblock_ptr + ! .. + ptr => allocator%get_block() + +Note that `get_block` returns a *pointer* to a memory block instead of +a copy. In practice, the head of the block list is detached from the +list (pop operation): + +.. graphviz:: + + digraph allocation { + + memblock1 [label="memory block\lid: 1"]; + memblock2 [label="memory block\lid: 2"]; + memblock3 [label="memory block\lid: 3"]; + ptr [shape=box, label="memblock_ptr"] + + memblock2 -> memblock3; + ptr -> memblock1; + } + +Dispatched memory blocks ban be released to the allocator by calling +the `release_block` subroutine: + +.. code:: fortran + + ! Request two blocks and release the first one, which becomes the + ! head of the free block list + ptr1 => allocator%get_block() + ptr2 => allocator%get_block() + call allocator%release_block(ptr1) + +Released blocks are pushed on top of the allocator's free blocks list: + +.. graphviz:: + + digraph release { + + memblock1 [label="memory block\lid: 1"]; + memblock2 [label="memory block\lid: 2"]; + memblock3 [label="memory block\lid: 3"]; + ptr1 [shape=box] + ptr2 [shape=box] + null [shape=box] + + memblock1 -> memblock3; + ptr2 -> memblock2; + ptr1 -> null + } + +Memory block allocation +----------------------- + +If a request is made to an allocator whose free block list is empty, a +new block is allocated before it is immediately dispacted to the +requesting object. As a consequence the memory footprint of a program +is expected to grow in early stages of a program's lifetime, before +reaching maximum where enough memory has been allocated and some can +be reused. diff --git a/_sources/internals/index.rst.txt b/_sources/internals/index.rst.txt new file mode 100644 index 00000000..f13bb806 --- /dev/null +++ b/_sources/internals/index.rst.txt @@ -0,0 +1,13 @@ +Internals +========= + +The following section describe various internals of the library. They +are aimed at developers willing to learn about the algorithmns and +data structures used, or users curious about how things are +implemented. + +.. toctree:: + :maxdepth: 1 + + momentum_rhs_calculation.rst + allocator.rst diff --git a/_sources/internals/momentum_rhs_calculation.rst.txt b/_sources/internals/momentum_rhs_calculation.rst.txt new file mode 100644 index 00000000..2642055d --- /dev/null +++ b/_sources/internals/momentum_rhs_calculation.rst.txt @@ -0,0 +1,88 @@ +Computing the spatial contribution to the momentum equation +=========================================================== + +The first stage of solving the momentum equation at a given time-step +:math:`k` is to evaluate the spatial contribution + +.. math:: + :label: rhs + + \mathbf{F}^k = - \frac{1}{2}[\nabla (\mathbf{u}^k \otimes \mathbf{u}^k) + + (\mathbf{u}^k \cdot \nabla) \mathbf{u}^k] + \nu \nabla^2\mathbf{u}^k + +This term involves spatial derivatives along the three directions +:math:`\hat{\mathbf{x}}`, :math:`\hat{\mathbf{y}}` and +:math:`\hat{\mathbf{z}}`. In order to reduce the number of +communications between MPI processes, the computation is performed in +three stages corresponding to three different data configurations: + +- In the x-configuration, the process has access to a data slab + covering the x-y plane. This a 1D domain decomposition along the + :math:`\hat{\mathbf{z}}` direction. Derivatives along + :math:`\hat{\mathbf{x}}` can be computed without communications. +- In the z-configuration, a process has access to a data slab + covering the y-z plane. This a 1D domain decomposition along the + :math:`\hat{\mathbf{x}}` direction. Derivatives along + :math:`\hat{\mathbf{z}}` can be computed without communications. +- In the y-configuration, a process has access to a data slab + covering the x-y plane. This a 1D domain decomposition along the + :math:`\hat{\mathbf{z}}` direction. Derivatives along + :math:`\hat{\mathbf{y}}` can be computed without communications. + +In the i-configuration, field data (e.g. the x-component of the +velocity field) is stored in a three-dimensional array of dimension +``dimension(SZ, N, M)`` where ``N`` is the size of the domain in the i +direction. This data layout decomposes slab data into ``M * SZ`` ` 1D +arrays (called pencils) of size ``N``. Pencils are processed in +batches of size ``SZ`` allowing for vectorised operations. + +The algorithm for computing :math:numref:`rhs` then becomes: + +.. code:: fortran + + ! Instances of type slab_t have access to slab data + ! and can compute derivatives and contributions to + ! momentum equation along a specific direction. + type(slab_t) :: xslab, yslab, zslab + + ! ... + + ! Perform necesseary communications across processes + ! asynchonously + call async_rotate_x_to_z(xslab, z_comm_buffer) + + ! Meanwhile, compute the contribution in the x direction + x_contrib = x_slab%transport() + + ! Assuming x to z transfer is done, arrange field data + ! in the correct z-configuration layout and compute + ! z contribution + call from_comms_buffer(z_comm_buffer, z_slab) + z_dir_contrib = z_slab%transport() + + ! Transfer the result back + call async_rotate_z_to_x(z_dir_contrib, x_slab_z) + + ! Meanwhile, switch from x-config to y-config + ! (no communications needed, only data reshuffling) + call rotate_x_to_y(x_slab, y_slab) + y_dir_contrib = yslab%transport() + + F = x_dir_contrib%data + y_dir_contrib%data + z_dir_contrib%data + +The ``slab3d_t`` type +--------------------- + +Computation of :math:numref:`rhs` is supported by instances of the +``slab3d_t`` derived type. These hold data for the three components +of a 3D vector in 3D space (thinks :math:`u_x`, :math:`u_y` and +:math:`u_z`) within a single data slab in the x, y or z- + +The purpose of ``slab3d_t`` instances is to compute spatial +derivatives along a given direction referred to as the slab's primary +direction. More precisely, user code is given access to type-bound +procedures such as ``transport`` or ``divergence`` which compute +contributions to physical quantities coming from spatial derivatives +in the slab's primary direction. + +For more details, see the API docs. diff --git a/_sources/report_a_bug.rst.txt b/_sources/report_a_bug.rst.txt new file mode 100644 index 00000000..d50b8700 --- /dev/null +++ b/_sources/report_a_bug.rst.txt @@ -0,0 +1,11 @@ +Report a bug +============ + +You can do so by adding a new issue to the x3d2 issue tracker on +GitHub. See `(GitHub docs) Creating an issue `_. + +If you are reporting a bug, be sure to include + +- The version of x3d2 you are using +- Information about your operating system. +- Every information required to reproduce the bug (e.g. input files). diff --git a/_static/alabaster.css b/_static/alabaster.css new file mode 100644 index 00000000..517d0b29 --- /dev/null +++ b/_static/alabaster.css @@ -0,0 +1,703 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 00000000..2a924f1d --- /dev/null +++ b/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..7e4c114f --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/_static/graphviz.css b/_static/graphviz.css new file mode 100644 index 00000000..8d81c02e --- /dev/null +++ b/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 00000000..250f5665 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..57c7df37 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,84 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902 } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000 } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #990000 } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #888888 } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ +.highlight .mb { color: #990000 } /* Literal.Number.Bin */ +.highlight .mf { color: #990000 } /* Literal.Number.Float */ +.highlight .mh { color: #990000 } /* Literal.Number.Hex */ +.highlight .mi { color: #990000 } /* Literal.Number.Integer */ +.highlight .mo { color: #990000 } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/developer/build.html b/developer/build.html new file mode 100644 index 00000000..aba06367 --- /dev/null +++ b/developer/build.html @@ -0,0 +1,155 @@ + + + + + + + + Building and running the unit tests — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Building and running the unit tests

+

x3d2 is in early development phase, and there is no main executable +yet to be built. However, currently implemented functionality is +covered by unit tests, which you can build and run on you development +machine.

+

To build x3d2, you will need git, a fortran compiler and CMake, see +Required tools.

+

Start by configuring the build directory:

+
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
+
+
+

To configure the build with the NVIDIA Fortran compiler, you can set +the FC environment variable to the compiler executable. If you +specify an relative path, it must be present in your current PATH.

+
$ FC=nvfortran cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
+
+
+

Setting the Fortran compiler to the NVIDIA Fortran compiler will +automatically include the CUDA Fortran source files into the build +tree, which are ignored by default.

+

Once the build directory is configured, the tests can be built and run +as follows:

+
$ cd build
+$ make
+$ make test
+
+
+

Note that make test is only a launcher for the ctest +executable. By default ctest does not show the output of test +executables on failure. If one of more tests fail, you probably want +to run the tests with:

+
$ ctest --output-on-failure
+
+
+

instead of make test.

+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/contributing_guidelines.html b/developer/contributing_guidelines.html new file mode 100644 index 00000000..f9424902 --- /dev/null +++ b/developer/contributing_guidelines.html @@ -0,0 +1,254 @@ + + + + + + + + Contributing guidelines — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Contributing guidelines

+

x3d2 is a collaborative project, open to all. In order to enable +effective collaboration, however, we ask that your contribution(s) +comply with a set of ground rules.

+
+

In a nutshell

+
    +
  • For any contribution not covered by an existing issue, open an issue +first.

  • +
  • Respect the commit format. (Install the git hook!).

  • +
  • Only commit changes formatted with fprettify, using the project’s +configuration. (Install the git hook!).

  • +
  • Strive to contribute small and focused Pull Requests with detailed +descriptions.

  • +
  • Add (a) unit test(s) covering a new feature, or (a) regression +test(s) for a bug fix.

  • +
+
+
+

Issues first

+

Issues are opened as soon as possible, particularly before any +significant implementation work is carried out or any pull request is +opened. Starting with issues greatly facilitates collaboration:

+
    +
  • It encourages developers to write (and therefore think) about the +work they plan to achieve.

  • +
  • It helps maintaining a shared and up to date record of current work +(known bugs, current developments).

  • +
  • It helps coordination between developers by sign-posting who is +working on what, as well as what is not being worked on.

  • +
  • It allows discussions between developers on how to best fix the +issue or implement the described improvement(s).

  • +
+

This doesn’t mean that you should forbid yourself from exploratory +prototyping until an issue has been opened. In fact, prototyping is +often helpful to write the content of the issue. On the other hand, +do open an issue before commiting to a particular design or +implementation.

+
+
+

Format commits accordingly

+

Commits messages are formatted according to the conventional commits +specification (v1.0.0). Commit messages must respect the following +structure:

+
<type>[optional scope]: <description>
+
+[optional body]
+
+
+

where <type> is one of fix, feat, build, chore, ci, +docs, style, refactor, perf or test.

+

Breaking changes are specified by adding an ! before the colon :. Example:

+
fix(allocator)!: Return 1D arrays as data blocks
+
+This is a breaking change because e.g. the allocator used to
+return 3D data blocks.
+
+
+

In addition, commit message header lines must not contain more than 68 +characters. Lines in the commit message body cannot exceed 72 +characters.

+
+

Note

+

Commit messages in x3d2 do not use footers as specified in the +conventional commit specs. You are welcome to use footers in your +commit messages, but know that they hold no special place in the +commit format policy.

+
+

A Git hook is provided to prevent you from registering non-conformant +commit messages. See setting up your development environment.

+
+
+

Fortran code formatting

+

Code formatting dictates things like indentation levels, number of +whitespace between operators or use upper/lowercase characters for +keywords.

+

Because having to learn such project specific rules isn’t terribily +interesting, all Fortran code in x3d2 is formatted automatically using +fprettify. Some non-default +configuraiton options are specified in the project’s .fprettify.ini +file.

+

Note that a a GitHub pull request will not be merged until all the +associated code addtions conform to the formatting.

+

The best way to deal with code formatting is to automate it and +forget about it. To do so, make sure you install the pre-commit +hook into your local git repository, see . This way, fprettify will +run automatically each time you commit new changes.

+
+
+

Pull requests and code review

+

Code review is a fondamental part of x3d2’s collaborative development. +Particularly, GitHub pull requests must be approved by at least two +maintainers before the associated commits are merged. Code review allows for

+
    +
  • Gatekeeping, by preventing the integration of changes that are not +up to standards, introducing bugs or potentially disruptive to +ongoing and/or future developments.

  • +
  • Knowledge transfer, by making sure that at least a couple of project +developers have an opportunity to study and understand the code to +be integrated.

  • +
  • Training, by giving new contributors opportunities to get feedback +and help, as well as chances to review contributions from more +experienced developers.

  • +
+

Poor quality pull requests can however turn the code review process +into a bottleneck or worse, lead to poor quality reviews. In order to +facilitate the code review process, pull request must be both +focused and small and have a detailed description.

+
    +
  1. Pull requests should aim to merge a be coherent body of changes, +targeting a single aspect of an issue. It is much prefereable to +fix an issue through multiple pull requests than one big +contribution.

  2. +
  3. Pull requests should aim to merge a limited number of changes. As +a rule of thumb, pull requests usually become much harder to review +beyond 10 changes.

  4. +
  5. Pull requests should come with a detailed description containing:

    +
      +
    • One or two sentences summing up the motivation for the changes.

    • +
    • A link to the addressed issue(s).

    • +
    • A summary of the changes.

    • +
    • A technical description of the changes.

    • +
    +

    The description is important for archiving purposes, but most +importlantl in order to guide the work of reviewers.

    +
  6. +
+

Note that the points above are guidelines as opposed to hard and fast +rules. For a given pull request, the amount of work required to +review the changes will vary across reviewers. Generally, however, +please empathise with your fellow contributors who are going to spend +time reviewing your code. Aim to make their work easier, and they +will do the same for you.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/contribution_workflow.html b/developer/contribution_workflow.html new file mode 100644 index 00000000..77128449 --- /dev/null +++ b/developer/contribution_workflow.html @@ -0,0 +1,150 @@ + + + + + + + + Overview of the contribution process — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Overview of the contribution process

+

The graph below illustrates the general process for contributing code +changes to x3d2:

+
digraph G {
+    review[shape="diamond", label="Changes approved"]
+    commit[label="commit changes locally"]
+
+    PR[label="Open/update Pull Request"];
+
+    Idea -> "Open new issue" -> commit -> PR
+    PR -> review
+    review -> merge [label="yes"]
+    review -> commit [label=" no"]
+    "Pick existing issue" -> commit
+
+    {
+        rank=sink;
+        review; merge
+    }
+}
+

Contributions are accepeted in the form of pull requests targeting the +main branch on the x3d2 GitHub repository. See (GitHub docs) +Creating a pull request.

+

By default your GitHub account will not be able to push changes to the +x3d2 repo, and you will have to open the pull request from a fork. See +(GitHub docs) Creating a pull request from a fork.

+

Note that the whole process is driven by issues. If you found a +bug not currently referenced by an existing issue, or have an idea on +how to improve a part of x3d2, please open a new item on the issue +tracker before opening a pull request.

+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/dev_environment.html b/developer/dev_environment.html new file mode 100644 index 00000000..c1654243 --- /dev/null +++ b/developer/dev_environment.html @@ -0,0 +1,156 @@ + + + + + + + + Setting up for development — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Setting up for development

+
    +
  1. To begin with, make sure you have the right tools installed by going +through the required tooling.

  2. +
  3. Download the x3d2 repository from GitHub:

    +
    $ git clone git@github.com:xcompact3d/x3d2.git
    +$ cd x3d2/
    +
    +
    +
  4. +
+
+

The following commands assume that your shell’s current directory is +the root of the x3d2 repository.

+
+
    +
  1. Install the pre-commit Git hook into your project-local +configuration:

    +
    $ cp githooks/pre-commit .git/hooks/
    +$ chmod +x .git/hooks/pre-commit
    +
    +
    +

    This Git hook will cause the automatic formatting of all fortran +files staged in your commit, using fprettify.

    +
  2. +
  3. Install the commit-msg Git hook into your project-local +configuration:

    +
    $ cp githooks/commit-msg .git/hooks/
    +$ chmod +x .git/hooks/commit-msg
    +
    +
    +

    This Git hook will automatically check your commit message against +the commit message format, based on the conventional commits +specification. See the contribution guidelines.

    +
  4. +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/index.html b/developer/index.html new file mode 100644 index 00000000..a5344a8d --- /dev/null +++ b/developer/index.html @@ -0,0 +1,151 @@ + + + + + + + + Contributing to x3d2 — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Contributing to x3d2

+

Fixed a bug? Have an idea for improving x3d2? x3d2 is developed in +the open with a license that allows anyone to:

+
    +
  • Run the program as they wish, for any purpose.

  • +
  • Access and study its source code, and making changes to it.

  • +
  • Redistribute copies (source or binary).

  • +
  • Distribute copies of your modified versions (source or binary).

  • +
+

Particularly, we encourage developers to contribute their changes back +to the x3d2 project. The following sections describe the process for +doing so.

+ +

If you are looking to take part in the project but don’t have anything +specific in mind, you could consider:

+
    +
  • Reporting (a) bug(s), suggest improvement(s) or share a user experience.

  • +
  • Adding documentation or improving the current one.

  • +
  • Working on fixing issues or implementing new features.

  • +
+

In any of the cases above, your entry point should be the issue +tracker – either to +pick an existing issue to work on or to create a new one.

+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/style.html b/developer/style.html new file mode 100644 index 00000000..3e04ff29 --- /dev/null +++ b/developer/style.html @@ -0,0 +1,267 @@ + + + + + + + + Fortran style guide — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Fortran style guide

+
+

Basic formatting

+

Identation, whitespaces and line length are enforced by fprettify. +Project settings are defined in the .fprettify.ini located at the +root of the repository.

+

In most cases, developers are expected to install the associated +pre-commit git hook. Additionally, it is recommended to configure +your text editor to run fprettify for you (for instance on saving a +file).

+

If you want to preview changes without overwriting a file, you can do +so using the –stdout option:

+
$ fprettify --config .fprettify.ini --stdout
+
+
+
+
+

Naming conventions

+

In the following “symbol” is a catch all phrase for variables, +procedures, derived types, type components and interfaces.

+
    +
  • Symbols are name using the snake_case convention.

  • +
  • Variable declared with the parameter are named using UPPER CASE +letters.

  • +
  • Symbols should, as much as possible, be named after they meaning +rather than their mathematical notation (.e.g velocity_field +instead of u).

  • +
+
+
+

Procedure definitions

+
    +
  • Procedure prototypes spanning more than 79 characters should be split +before the first dummy argument is defined, after the opening +parenthese. If the list of dummy arguments spans more than 79 +characters each argument is defined on it own line.

    +
    subroutine my_long_subroutine( &
    +   argument1, argument3, argument4, argument5, argument5, argument6 &
    +   )
    +
    +subroutine my_very_long_subroutine( &
    +   argument1, &
    +   argument2, &
    +   argument3, &
    +   argument4, &
    +   argument5, &
    +   argument6, &
    +   argument7, &
    +   )
    +
    +
    +
  • +
  • Function prototypes indicate the return object type unless the +return object is an array.

  • +
  • Functions are always defined with the pure prefix. A procedure +with side effects must be a subroutine.

  • +
+
+
+

Modules

+
    +
  • Module names end with the _m suffix. Examples: +module allocator_m, use allocator_m, only: ….

  • +
  • All module components are private by default.

  • +
  • The module components are always acessed through the only keyword:

    +
    module a_module_m
    +   ! Non compliant
    +   use stencil_m
    +   ! Compliant
    +   use stencil_m, only: stencil_t
    +
    +
    +
  • +
+
+
+

Derived type definitions

+
    +
  • Derived type names end with the _t suffix. Examples: +allocator_t, type(stencil_t) :: s.

  • +
  • The contains keyword is omitted is the type does not define any +type-bound procedures.

  • +
  • All type components are private by default.

  • +
+
+
+

Custom structure constructors

+
    +
  • Are named like create_<type_root_name>[_<suffix>]

  • +
  • Are declared with the private attribute

  • +
  • Are defined at the top of the module’s contains block.

  • +
+

Example

+
module square_module
+
+   type :: square_t
+      real :: size
+      character(:), allocatable :: color
+   end type square_t
+
+   interface square_t
+      module procedure create_square_from_square
+      module procedure create_square_default_color
+   end interface square_t
+
+contains
+
+   type(square_t) function create_square_from_square(sq_in)
+      type(square), intent(in) :: sq_in
+      ! ...
+   end function create_square_from_square
+
+   type(square_t) function create_square_default_color(sq_size)
+      real, intent(in) :: sq_size
+      ! ...
+   end function create_square_default_color
+
+
+
+
+

In-code documentation

+

The body of modules, public types, public procedures and public +type-bound methods MUST be preceded of one or more documentation +paragraphs. Optionally, the body of private symbols MAY be +preceded by documentation paragraph.

+

Procedure dummy arguments, interface components and type-bound +procedures declarations MAY be documented using an inline comment +either on the same line directly following the statement (using the +docmark !!) or on the line directly above the statement (using the +predocmark !>).

+

x3d2 uses ford to +extract in-code documentation and generate HTML pages. The syntax for +in-code documentation follows ford’s syntax for comments. See +(ford)Writing documentation

+
subroutine add(a, b, c)
+    !! This is the first paragraph of the procedures
+    !! documentation.  Note that it starts with TWO !.
+    real, intent(in) :: a, b !! Optional documentation for dummy argument.
+    real, intent(out) :: c !! The result of a + b
+
+    ! The line below is a regular comment.
+    ! Make use of the well-known the addition algorithm.
+    c = a + b
+end subroutine
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/tooling.html b/developer/tooling.html new file mode 100644 index 00000000..15ea48b7 --- /dev/null +++ b/developer/tooling.html @@ -0,0 +1,182 @@ + + + + + + + + Required tools — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Required tools

+

To contribute to x3d2 you need a few things on your toolbelt

+
    +
  • A Fortran 2003 compiler (e.g. gfortran)

  • +
  • The NVIDA HPC Fortran compiler [optional]

  • +
  • The CMake build system

  • +
  • The fprettify auto-formatter

  • +
  • The FORD and Sphinx documentation generators.

  • +
+

The above tools can all be installed via you distribution’s package +manager or the Python package pamanger pip.

+
+

Note

+

We strongly recommend to use the pipx wrapper around pip to +ensure installed Python packages are installed into isolated +virtual environments.

+
+
+

Fortran compiler

+

You can get started with the GNU Fortran compiler

+
$ sudo apt install gfortran
+
+
+
+
+

CMake

+

CMake is used to configure the build. This means, among other things, +finding the location of the required compiler and libraries, as well +as resolving the links between different components of the software.

+

To configure and build x3d2 you will need CMake version 3.18 and +above. At the time of writing the currently distributed version of +CMake in Debain stable is 3.18, so you should be able to install CMake +from your distribution’s package manager, for instance

+
sudo apt install cmake
+
+
+

Recent CMake versions are packaged for a variety of package managers, +including pipx:

+
$ pipx install cmake
+
+
+
+
+

fprettify

+

Auto-formatter for fortran 90 and above.

+
$ pipx install fprettify
+
+
+
+
+

FORD

+

Documentation generator for fortran 90 and above.

+
$ pipx install ford
+
+
+
+
+

Sphinx

+
$ pipx install sphinx
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/developer/writing_docs.html b/developer/writing_docs.html new file mode 100644 index 00000000..256c48c4 --- /dev/null +++ b/developer/writing_docs.html @@ -0,0 +1,152 @@ + + + + + + + + Contributing documentation — x3d2 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Contributing documentation

+

x3d2 uses both Sphinx and ford for documentation. Sphinx is +used to generate the user and developer guides (i.e. this website). +ford is used to generate the API documentation website by extraction +in-code documentation.

+
+

Building the documentation

+

To build the user and developer docs (Sphinx):

+
# From the repository root
+$ cd docs && make html
+
+
+

The above command generate hmtl pages in docs/build/html. You can +display the user and developer docs by opening +docs/build/html/index.html with a web browser.

+

To build the API docs (ford):

+
# From the repository root
+$ ford ford.md -o api_docs
+
+
+

You can display the API docs by opening api_docs/index.html with a +web browser.

+
+
+

Writing user or developer documentation

+

Documentation sources are located under docs/sources/. They consist +in a hierachy of reStructuredText files. reStructuredText (rST) is a +light markup language similar to markdown. For an introduction to +rST, see (Sphinx)ReStructuredText primer.

+
+
+

In-code documentation

+

See In-code documentation.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..9cc8520c --- /dev/null +++ b/genindex.html @@ -0,0 +1,105 @@ + + + + + + + Index — x3d2 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..0ca67f8e --- /dev/null +++ b/index.html @@ -0,0 +1,134 @@ + + + + + + + + <no title> — x3d2 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

x3d2 is the current codename for what is to become Xcompact3d +version 2.0. This project is a rewrite of Xcompact3d leading to

+
    +
  • Improved serial and parallel performance.

  • +
  • Support for NVIDIA GPU accelerators (using CUDA Fortran).

  • +
  • Improved modularity and testability.

  • +
+

Contents:

+ + + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/internals/allocator.html b/internals/allocator.html new file mode 100644 index 00000000..d5e6038f --- /dev/null +++ b/internals/allocator.html @@ -0,0 +1,200 @@ + + + + + + + + Memory management — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Memory management

+

The parallel processing carried out in x3d2 requires that the +computational domain is sliced into slabs along a specific direction +of space.

+

Data slabs (instances of the derived type slab_t) hold a pointer to +an allocator_t instance that is responsible for the allocation and +dispatching of memory blocks to data slabs. See (API)allocator_t. Whenever +data slabs are no longer required, the associated memory blocks can be +released to the allocator, ready to be dispatched to other slabs or +objects who might need them.

+

An instance of allocator_t maintains a linked list of memory blocks, +which each element in the list labelled with a unique identifier:

+
digraph freelist {
+     rank=LR;
+     memblock1 [label="memory block\lid: 1"];
+     memblock2 [label="memory block\lid: 2"];
+     memblock3 [label="memory block\lid: 3"];
+
+     memblock1 -> memblock2 -> memblock3;
+}
+

Each memory block is an instance of the memblock_t derived type +((API)memblock_t). In +addition to its integer identifier, a instance of the memblock_t +type holds a 3D data array and a pointer to the next block in the +list.

+

All memory blocks in an allocator’s list have the same size. An +allocator can be created by passing in the dimension of the memory +blocks:

+
allocator = allocator_t([32 16 32])
+
+
+

Given an allocator_t instance, memory blocks can requested using the +get_block function.

+
use m_allocator, only: memory_block_t, allocator_t
+! ...
+type(memory_block_t), pointer :: memblock_ptr
+! ..
+ptr => allocator%get_block()
+
+
+

Note that get_block returns a pointer to a memory block instead of +a copy. In practice, the head of the block list is detached from the +list (pop operation):

+
digraph allocation {
+
+ memblock1 [label="memory block\lid: 1"];
+ memblock2 [label="memory block\lid: 2"];
+ memblock3 [label="memory block\lid: 3"];
+ ptr [shape=box, label="memblock_ptr"]
+
+ memblock2 -> memblock3;
+ ptr -> memblock1;
+}
+

Dispatched memory blocks ban be released to the allocator by calling +the release_block subroutine:

+
! Request two blocks and release the first one, which becomes the
+! head of the free block list
+ptr1 => allocator%get_block()
+ptr2 => allocator%get_block()
+call allocator%release_block(ptr1)
+
+
+

Released blocks are pushed on top of the allocator’s free blocks list:

+
digraph release {
+
+ memblock1 [label="memory block\lid: 1"];
+ memblock2 [label="memory block\lid: 2"];
+ memblock3 [label="memory block\lid: 3"];
+ ptr1 [shape=box]
+ ptr2 [shape=box]
+ null [shape=box]
+
+ memblock1 -> memblock3;
+ ptr2 -> memblock2;
+ ptr1 -> null
+}
+
+

Memory block allocation

+

If a request is made to an allocator whose free block list is empty, a +new block is allocated before it is immediately dispacted to the +requesting object. As a consequence the memory footprint of a program +is expected to grow in early stages of a program’s lifetime, before +reaching maximum where enough memory has been allocated and some can +be reused.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/internals/index.html b/internals/index.html new file mode 100644 index 00000000..2f6c5e3a --- /dev/null +++ b/internals/index.html @@ -0,0 +1,124 @@ + + + + + + + + Internals — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Internals

+

The following section describe various internals of the library. They +are aimed at developers willing to learn about the algorithmns and +data structures used, or users curious about how things are +implemented.

+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/internals/momentum_rhs_calculation.html b/internals/momentum_rhs_calculation.html new file mode 100644 index 00000000..b16277c0 --- /dev/null +++ b/internals/momentum_rhs_calculation.html @@ -0,0 +1,193 @@ + + + + + + + + Computing the spatial contribution to the momentum equation — x3d2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Computing the spatial contribution to the momentum equation

+

The first stage of solving the momentum equation at a given time-step +\(k\) is to evaluate the spatial contribution

+
+(1)\[\mathbf{F}^k = - \frac{1}{2}[\nabla (\mathbf{u}^k \otimes \mathbf{u}^k) ++ (\mathbf{u}^k \cdot \nabla) \mathbf{u}^k] + \nu \nabla^2\mathbf{u}^k\]
+

This term involves spatial derivatives along the three directions +\(\hat{\mathbf{x}}\), \(\hat{\mathbf{y}}\) and +\(\hat{\mathbf{z}}\). In order to reduce the number of +communications between MPI processes, the computation is performed in +three stages corresponding to three different data configurations:

+
    +
  • In the x-configuration, the process has access to a data slab +covering the x-y plane. This a 1D domain decomposition along the +\(\hat{\mathbf{z}}\) direction. Derivatives along +\(\hat{\mathbf{x}}\) can be computed without communications.

  • +
  • In the z-configuration, a process has access to a data slab +covering the y-z plane. This a 1D domain decomposition along the +\(\hat{\mathbf{x}}\) direction. Derivatives along +\(\hat{\mathbf{z}}\) can be computed without communications.

  • +
  • In the y-configuration, a process has access to a data slab +covering the x-y plane. This a 1D domain decomposition along the +\(\hat{\mathbf{z}}\) direction. Derivatives along +\(\hat{\mathbf{y}}\) can be computed without communications.

  • +
+

In the i-configuration, field data (e.g. the x-component of the +velocity field) is stored in a three-dimensional array of dimension +dimension(SZ, N, M) where N is the size of the domain in the i +direction. This data layout decomposes slab data into M * SZ ` 1D +arrays (called pencils) of size N. Pencils are processed in +batches of size SZ allowing for vectorised operations.

+

The algorithm for computing (1) then becomes:

+
! Instances of type slab_t have access to slab data
+! and can compute derivatives and contributions to
+! momentum equation along a specific direction.
+type(slab_t) :: xslab, yslab, zslab
+
+! ...
+
+! Perform necesseary communications across processes
+! asynchonously
+call async_rotate_x_to_z(xslab, z_comm_buffer)
+
+! Meanwhile, compute the contribution in the x direction
+x_contrib = x_slab%transport()
+
+! Assuming x to z transfer is done, arrange field data
+! in the correct z-configuration layout and compute
+! z contribution
+call from_comms_buffer(z_comm_buffer, z_slab)
+z_dir_contrib = z_slab%transport()
+
+! Transfer the result back
+call async_rotate_z_to_x(z_dir_contrib, x_slab_z)
+
+! Meanwhile, switch from x-config to y-config
+! (no communications needed, only data reshuffling)
+call rotate_x_to_y(x_slab, y_slab)
+y_dir_contrib = yslab%transport()
+
+F = x_dir_contrib%data + y_dir_contrib%data + z_dir_contrib%data
+
+
+
+

The slab3d_t type

+

Computation of (1) is supported by instances of the +slab3d_t derived type. These hold data for the three components +of a 3D vector in 3D space (thinks \(u_x\), \(u_y\) and +\(u_z\)) within a single data slab in the x, y or z-

+

The purpose of slab3d_t instances is to compute spatial +derivatives along a given direction referred to as the slab’s primary +direction. More precisely, user code is given access to type-bound +procedures such as transport or divergence which compute +contributions to physical quantities coming from spatial derivatives +in the slab’s primary direction.

+

For more details, see the API docs.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..7a60dabe7ce8c75d049a6cde7f1f3c3b14d74c8f GIT binary patch literal 622 zcmV-!0+IbAAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk-Gh{Lf zBOq2~a&u{KZaN?eBOp|0Wgv28ZDDC{WMy(7Z)PBLXlZjGW@&6?AZc?TV{dJ6a%FRK zWn>_Ab7^j8AbMtkVfe6%*1UTUKZ^j!A{RhNNnSD499L(Jb<#!^14VKvU!Woe-}7gFiEs*haxQh8PxE^ie9KN=9uVAqS>cp(40F?6`+)KII>?>+jx#sko%l+{vU@+2{| zru;Rc+iOqGqKkdI3sN=ui*=%D0-o>8&UhoQox+#CXn{Jti3Bg7)u%=z#G}E!NP(&d z?@08*L1mW?HyV-1%=>qxassQ)AN-fJM+G_Bw(8(@nJlN@Sb&z%sf@!Z_ebPe6k)d? z0!HrOjkD-Ap3mWp)^E|Bd;Y38N9&^=^XE#tL6XAZwVaOsxxMWASQ9SFxSDWd^wkkW z9SweCT14-J2@k>;k|OfE7fDxemH360{1L2hVvD81Gqq#AfaYpX!6wsEmP&T?yD&;& zWHP0izSu4HJYqYYHkZ#WObiLLJUd?LjLka08&;cVNp+?*9fuh>HGx#(ovw3h&^u{Q z$GBtnMYhL@?_?C?IxUW&jn8+GBOrhytAN7G-O{hd=AS{qpLj^C_S8B%)gBvf)y28} I2jeJB + + + + + + + Report a bug — x3d2 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Report a bug

+

You can do so by adding a new issue to the x3d2 issue tracker on +GitHub. See (GitHub docs) Creating an issue.

+

If you are reporting a bug, be sure to include

+
    +
  • The version of x3d2 you are using

  • +
  • Information about your operating system.

  • +
  • Every information required to reproduce the bug (e.g. input files).

  • +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 00000000..01881c2a --- /dev/null +++ b/search.html @@ -0,0 +1,124 @@ + + + + + + + Search — x3d2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..461d6147 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["developer/build", "developer/contributing_guidelines", "developer/contribution_workflow", "developer/dev_environment", "developer/index", "developer/style", "developer/tooling", "developer/writing_docs", "index", "internals/allocator", "internals/index", "internals/momentum_rhs_calculation", "report_a_bug"], "filenames": ["developer/build.rst", "developer/contributing_guidelines.rst", "developer/contribution_workflow.rst", "developer/dev_environment.rst", "developer/index.rst", "developer/style.rst", "developer/tooling.rst", "developer/writing_docs.rst", "index.rst", "internals/allocator.rst", "internals/index.rst", "internals/momentum_rhs_calculation.rst", "report_a_bug.rst"], "titles": ["Building and running the unit tests", "Contributing guidelines", "Overview of the contribution process", "Setting up for development", "Contributing to x3d2", "Fortran style guide", "Required tools", "Contributing documentation", "<no title>", "Memory management", "Internals", "Computing the spatial contribution to the momentum equation", "Report a bug"], "terms": {"x3d2": [0, 1, 2, 3, 5, 6, 7, 8, 9, 12], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11], "earli": [0, 9], "develop": [0, 1, 4, 5, 8, 10], "phase": 0, "main": [0, 2], "execut": 0, "yet": 0, "built": 0, "howev": [0, 1], "current": [0, 1, 2, 3, 4, 6, 8], "implement": [0, 1, 4, 10], "function": [0, 5, 9], "cover": [0, 1, 11], "which": [0, 9, 11], "you": [0, 1, 2, 3, 4, 5, 6, 7, 12], "can": [0, 1, 5, 6, 7, 9, 11, 12], "machin": 0, "To": [0, 1, 3, 6, 7], "need": [0, 6, 9, 11], "git": [0, 1, 3, 5], "fortran": [0, 3, 4, 8], "compil": 0, "cmake": 0, "see": [0, 1, 2, 3, 5, 7, 9, 11, 12], "requir": [0, 1, 3, 4, 8, 9, 12], "tool": [0, 3, 4, 8], "start": [0, 1, 5, 6], "configur": [0, 1, 3, 5, 6, 11], "directori": [0, 3], "": [0, 1, 3, 4, 5, 6, 9, 11], "b": [0, 5], "dcmake_build_typ": 0, "debug": 0, "nvidia": [0, 8], "set": [0, 1, 4, 5, 8], "fc": 0, "environ": [0, 1, 6], "variabl": [0, 5], "If": [0, 2, 4, 5, 9, 12], "specifi": [0, 1], "an": [0, 1, 2, 4, 5, 7, 9, 12], "rel": 0, "path": 0, "must": [0, 1, 5], "present": 0, "your": [0, 1, 2, 3, 4, 5, 6, 12], "nvfortran": 0, "automat": [0, 1, 3], "includ": [0, 6, 12], "cuda": [0, 8], "sourc": [0, 4, 7], "file": [0, 1, 3, 5, 7, 12], "tree": 0, "ar": [0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 12], "ignor": 0, "default": [0, 1, 2, 5], "onc": 0, "follow": [0, 1, 3, 4, 5, 10], "cd": [0, 3, 7], "make": [0, 1, 3, 4, 5, 7], "note": [0, 1, 2, 5, 9], "onli": [0, 1, 5, 9, 11], "launcher": 0, "ctest": 0, "By": [0, 2], "doe": [0, 5], "show": 0, "output": 0, "failur": 0, "one": [0, 1, 4, 5, 9], "more": [0, 1, 5, 11], "fail": 0, "probabl": 0, "want": [0, 5], "instead": [0, 5, 9], "collabor": 1, "project": [1, 3, 4, 5, 8], "open": [1, 2, 4, 5, 7], "all": [1, 3, 5, 6, 9], "order": [1, 11], "enabl": 1, "effect": [1, 5], "we": [1, 4, 6], "ask": 1, "compli": 1, "ground": 1, "rule": 1, "For": [1, 7, 11], "ani": [1, 4, 5], "exist": [1, 2, 4], "respect": 1, "instal": [1, 3, 5, 6], "hook": [1, 3, 5], "chang": [1, 2, 4, 5], "fprettifi": [1, 3, 5], "us": [1, 3, 5, 6, 7, 8, 9, 10, 12], "strive": 1, "small": 1, "focus": 1, "detail": [1, 11], "descript": 1, "add": [1, 5], "unit": [1, 4, 8], "test": [1, 4, 8], "new": [1, 2, 4, 9, 12], "featur": [1, 4], "regress": 1, "bug": [1, 2, 4, 8], "fix": [1, 4], "soon": 1, "possibl": [1, 5], "particularli": [1, 4], "befor": [1, 2, 5, 9], "signific": 1, "work": [1, 4], "carri": [1, 9], "out": [1, 5, 9], "greatli": 1, "facilit": 1, "It": 1, "encourag": [1, 4], "write": [1, 5, 6], "therefor": 1, "think": [1, 11], "about": [1, 10, 12], "thei": [1, 4, 5, 7, 10], "plan": 1, "achiev": 1, "help": 1, "maintain": [1, 9], "share": [1, 4], "up": [1, 4, 8], "date": 1, "record": 1, "known": [1, 5], "coordin": 1, "between": [1, 6, 11], "sign": 1, "post": 1, "who": [1, 9], "what": [1, 8], "well": [1, 5, 6], "being": 1, "allow": [1, 4, 11], "discuss": 1, "how": [1, 2, 10], "best": 1, "describ": [1, 4, 10], "improv": [1, 2, 4, 8], "thi": [1, 3, 5, 6, 7, 8, 11], "doesn": 1, "t": [1, 4], "mean": [1, 5, 6], "should": [1, 4, 5, 6], "forbid": 1, "yourself": 1, "from": [1, 2, 3, 6, 7, 9, 11], "exploratori": 1, "prototyp": [1, 5], "until": 1, "ha": [1, 9, 11], "been": [1, 9], "fact": 1, "often": 1, "content": [1, 8], "On": 1, "other": [1, 6, 9], "hand": 1, "do": [1, 4, 5, 12], "particular": 1, "design": 1, "messag": [1, 3], "accord": 1, "convent": [1, 3], "specif": [1, 3, 4, 9, 11], "v1": 1, "0": [1, 8], "structur": [1, 10], "type": [1, 9], "option": [1, 5, 6], "scope": 1, "bodi": [1, 5], "where": [1, 9, 11], "feat": 1, "build": [1, 4, 6, 8], "chore": 1, "ci": 1, "doc": [1, 2, 7, 11, 12], "style": [1, 4, 8], "refactor": 1, "perf": 1, "break": 1, "ad": [1, 4, 12], "colon": 1, "exampl": [1, 5], "alloc": 1, "return": [1, 5, 9], "1d": [1, 11], "arrai": [1, 5, 9, 11], "data": [1, 9, 10, 11], "block": [1, 5], "becaus": 1, "e": [1, 5, 6, 7, 11, 12], "g": [1, 5, 6, 11, 12], "3d": [1, 9, 11], "addit": [1, 5, 9], "header": 1, "line": [1, 5], "contain": [1, 5], "than": [1, 5], "68": 1, "charact": [1, 5], "cannot": 1, "exce": 1, "72": 1, "footer": 1, "spec": 1, "welcom": 1, "know": 1, "hold": [1, 9, 11], "special": 1, "place": 1, "polici": 1, "A": [1, 5, 6], "provid": 1, "prevent": 1, "regist": 1, "non": [1, 5], "conform": 1, "dictat": 1, "thing": [1, 6, 10], "like": [1, 5], "indent": 1, "level": 1, "number": [1, 11], "whitespac": [1, 5], "oper": [1, 9, 11, 12], "upper": [1, 5], "lowercas": 1, "keyword": [1, 5], "have": [1, 2, 3, 4, 9, 11], "learn": [1, 10], "isn": 1, "terribili": 1, "interest": 1, "some": [1, 9], "configuraiton": 1, "ini": [1, 5], "github": [1, 2, 3, 12], "merg": 1, "associ": [1, 5, 9], "addtion": 1, "The": [1, 2, 3, 4, 5, 6, 7, 9, 10, 12], "wai": 1, "deal": 1, "autom": 1, "forget": 1, "so": [1, 4, 5, 6, 12], "sure": [1, 3, 12], "pre": [1, 3, 5], "local": [1, 3], "repositori": [1, 2, 3, 5, 7], "run": [1, 4, 5, 8], "each": [1, 5, 9], "time": [1, 6, 11], "fondament": 1, "part": [1, 2, 4], "approv": 1, "least": 1, "two": [1, 5, 9], "gatekeep": 1, "integr": 1, "standard": 1, "introduc": 1, "potenti": 1, "disrupt": 1, "ongo": 1, "futur": 1, "knowledg": 1, "transfer": [1, 11], "coupl": 1, "opportun": 1, "studi": [1, 4], "understand": 1, "train": 1, "give": 1, "contributor": 1, "get": [1, 6], "feedback": 1, "chanc": 1, "experienc": 1, "poor": 1, "qualiti": 1, "turn": 1, "process": [1, 4, 8, 9, 11], "bottleneck": 1, "wors": 1, "lead": [1, 8], "both": [1, 7], "aim": [1, 10], "coher": 1, "target": [1, 2], "singl": [1, 11], "aspect": 1, "much": [1, 5], "prefer": 1, "through": [1, 3, 5], "multipl": 1, "big": 1, "limit": 1, "As": [1, 9], "thumb": 1, "usual": 1, "becom": [1, 8, 9, 11], "harder": 1, "beyond": 1, "10": 1, "come": [1, 11], "One": 1, "sentenc": 1, "sum": 1, "motiv": 1, "link": [1, 6, 9], "address": 1, "summari": 1, "technic": 1, "import": 1, "archiv": 1, "purpos": [1, 4, 11], "most": [1, 5], "importlantl": 1, "guid": [1, 4, 7, 8], "point": [1, 4], "abov": [1, 4, 5, 6, 7], "oppos": 1, "hard": 1, "fast": 1, "given": [1, 9, 11], "amount": 1, "vari": 1, "across": [1, 11], "gener": [1, 2, 5, 6, 7], "pleas": [1, 2], "empathis": 1, "fellow": 1, "go": [1, 3], "spend": 1, "easier": 1, "same": [1, 5, 9], "graph": 2, "below": [2, 5], "illustr": 2, "code": [2, 4, 11], "accepet": 2, "form": 2, "pull": 2, "request": [2, 9], "branch": 2, "creat": [2, 4, 9, 12], "account": 2, "abl": [2, 6], "push": [2, 9], "repo": 2, "fork": 2, "whole": 2, "driven": 2, "issu": [2, 4, 12], "found": 2, "referenc": 2, "idea": [2, 4], "item": 2, "tracker": [2, 4, 12], "begin": 3, "right": 3, "download": 3, "clone": 3, "com": 3, "xcompact3d": [3, 8], "command": [3, 7], "assum": [3, 11], "shell": 3, "root": [3, 5, 7], "commit": [3, 5], "cp": 3, "githook": 3, "chmod": 3, "x": [3, 11], "caus": 3, "format": 3, "stage": [3, 9, 11], "msg": 3, "check": 3, "against": 3, "base": 3, "contribut": [3, 6, 8, 10], "guidelin": [3, 4, 8], "licens": 4, "anyon": 4, "program": [4, 9], "wish": 4, "access": [4, 11], "its": [4, 9], "redistribut": 4, "copi": [4, 9], "binari": 4, "distribut": [4, 6], "modifi": 4, "version": [4, 6, 8, 12], "back": [4, 11], "section": [4, 10], "overview": [4, 8], "document": [4, 6, 8], "look": 4, "take": 4, "don": 4, "anyth": 4, "mind": 4, "could": 4, "consid": 4, "report": [4, 8], "suggest": 4, "user": [4, 10, 11], "experi": 4, "In": [4, 9, 11], "case": [4, 5], "entri": 4, "either": [4, 5], "pick": 4, "ident": 5, "length": 5, "enforc": 5, "defin": 5, "locat": [5, 6, 7], "expect": [5, 9], "addition": 5, "recommend": [5, 6], "text": 5, "editor": 5, "instanc": [5, 6, 9, 11], "save": 5, "preview": 5, "without": [5, 11], "overwrit": 5, "stdout": 5, "config": [5, 11], "symbol": 5, "catch": 5, "phrase": 5, "compon": [5, 6, 11], "interfac": 5, "snake_cas": 5, "declar": 5, "paramet": 5, "letter": 5, "after": 5, "rather": 5, "mathemat": 5, "notat": 5, "velocity_field": 5, "u": [5, 11], "span": 5, "79": 5, "split": 5, "first": [5, 9, 11], "dummi": 5, "argument": 5, "parenthes": 5, "list": [5, 9], "own": 5, "subroutin": [5, 9], "my_long_subroutin": 5, "argument1": 5, "argument3": 5, "argument4": 5, "argument5": 5, "argument6": 5, "my_very_long_subroutin": 5, "argument2": 5, "argument7": 5, "indic": 5, "object": [5, 9], "unless": 5, "alwai": 5, "pure": 5, "prefix": 5, "side": 5, "end": 5, "_m": 5, "suffix": 5, "allocator_m": 5, "privat": 5, "acess": 5, "a_module_m": 5, "compliant": 5, "stencil_m": 5, "stencil_t": 5, "_t": 5, "allocator_t": [5, 9], "omit": 5, "bound": [5, 11], "create_": 5, "type_root_nam": 5, "_": 5, "attribut": 5, "top": [5, 9], "square_modul": 5, "square_t": 5, "real": 5, "size": [5, 9, 11], "allocat": 5, "color": 5, "create_square_from_squar": 5, "create_square_default_color": 5, "sq_in": 5, "squar": 5, "intent": 5, "sq_size": 5, "public": 5, "method": 5, "preced": 5, "paragraph": 5, "mai": 5, "inlin": 5, "comment": 5, "directli": 5, "statement": 5, "docmark": 5, "predocmark": 5, "ford": [5, 7], "extract": [5, 7], "html": [5, 7], "page": [5, 7], "syntax": 5, "c": 5, "result": [5, 11], "regular": 5, "algorithm": [5, 11], "few": 6, "toolbelt": 6, "2003": 6, "gfortran": 6, "nvida": 6, "hpc": 6, "system": [6, 12], "auto": 6, "formatt": 6, "via": 6, "packag": 6, "manag": [6, 8, 10], "python": 6, "pamang": 6, "pip": 6, "strongli": 6, "pipx": 6, "wrapper": 6, "around": 6, "ensur": 6, "isol": 6, "virtual": 6, "gnu": 6, "sudo": 6, "apt": 6, "among": 6, "find": 6, "librari": [6, 10], "resolv": 6, "differ": [6, 11], "softwar": 6, "3": 6, "18": 6, "At": 6, "debain": 6, "stabl": 6, "recent": 6, "varieti": 6, "90": 6, "sphinx": 7, "websit": 7, "api": [7, 8, 9, 11], "hmtl": 7, "displai": 7, "index": 7, "web": 7, "browser": 7, "md": 7, "o": 7, "api_doc": 7, "under": 7, "consist": 7, "hierachi": 7, "restructuredtext": 7, "rst": 7, "light": 7, "markup": 7, "languag": 7, "similar": 7, "markdown": 7, "introduct": 7, "primer": 7, "codenam": 8, "2": [8, 11], "rewrit": 8, "serial": 8, "parallel": [8, 9], "perform": [8, 11], "support": [8, 11], "gpu": 8, "acceler": 8, "modular": 8, "testabl": 8, "intern": 8, "comput": [8, 9, 10], "spatial": [8, 10], "momentum": [8, 10], "equat": [8, 10], "memori": [8, 10], "refer": [8, 11], "domain": [9, 11], "slice": 9, "slab": [9, 11], "along": [9, 11], "direct": [9, 11], "space": [9, 11], "deriv": [9, 11], "slab_t": [9, 11], "pointer": 9, "respons": 9, "dispatch": 9, "whenev": 9, "longer": 9, "releas": 9, "readi": 9, "might": 9, "them": 9, "element": 9, "label": 9, "uniqu": 9, "identifi": 9, "memblock_t": 9, "integ": 9, "next": 9, "pass": 9, "dimens": [9, 11], "32": 9, "16": 9, "get_block": 9, "m_alloc": 9, "memory_block_t": 9, "memblock_ptr": 9, "ptr": 9, "practic": 9, "head": 9, "detach": 9, "pop": 9, "ban": 9, "call": [9, 11], "release_block": 9, "free": 9, "ptr1": 9, "ptr2": 9, "made": 9, "whose": 9, "empti": 9, "immedi": 9, "dispact": 9, "consequ": 9, "footprint": 9, "grow": 9, "lifetim": 9, "reach": 9, "maximum": 9, "enough": 9, "reus": 9, "variou": 10, "willing": 10, "algorithmn": 10, "curiou": 10, "solv": 11, "step": 11, "k": 11, "evalu": 11, "mathbf": 11, "f": 11, "frac": 11, "1": 11, "nabla": 11, "otim": 11, "cdot": 11, "nu": 11, "term": 11, "involv": 11, "three": 11, "hat": 11, "y": 11, "z": 11, "reduc": 11, "commun": 11, "mpi": 11, "correspond": 11, "plane": 11, "decomposit": 11, "field": 11, "veloc": 11, "store": 11, "dimension": 11, "sz": 11, "n": 11, "m": 11, "layout": 11, "decompos": 11, "pencil": 11, "batch": 11, "vectoris": 11, "xslab": 11, "yslab": 11, "zslab": 11, "necesseari": 11, "asynchon": 11, "async_rotate_x_to_z": 11, "z_comm_buff": 11, "meanwhil": 11, "x_contrib": 11, "x_slab": 11, "transport": 11, "done": 11, "arrang": 11, "correct": 11, "from_comms_buff": 11, "z_slab": 11, "z_dir_contrib": 11, "async_rotate_z_to_x": 11, "x_slab_z": 11, "switch": 11, "reshuffl": 11, "rotate_x_to_i": 11, "y_slab": 11, "y_dir_contrib": 11, "x_dir_contrib": 11, "These": 11, "vector": 11, "u_x": 11, "u_i": 11, "u_z": 11, "within": 11, "primari": 11, "precis": 11, "procedur": 11, "diverg": 11, "physic": 11, "quantiti": 11, "inform": 12, "everi": 12, "reproduc": 12, "input": 12}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"build": [0, 7], "run": 0, "unit": 0, "test": 0, "contribut": [1, 2, 4, 7, 11], "guidelin": 1, "In": [1, 5, 7], "nutshel": 1, "issu": 1, "first": 1, "format": [1, 5], "commit": 1, "accordingli": 1, "fortran": [1, 5, 6], "code": [1, 5, 7], "pull": 1, "request": 1, "review": 1, "overview": 2, "process": 2, "set": 3, "up": 3, "develop": [3, 7], "x3d2": 4, "style": 5, "guid": 5, "basic": 5, "name": 5, "convent": 5, "procedur": 5, "definit": 5, "modul": 5, "deriv": 5, "type": [5, 11], "custom": 5, "structur": 5, "constructor": 5, "document": [5, 7], "requir": 6, "tool": 6, "compil": 6, "cmake": 6, "fprettifi": 6, "ford": 6, "sphinx": 6, "write": 7, "user": 7, "memori": 9, "manag": 9, "block": 9, "alloc": 9, "intern": 10, "comput": 11, "spatial": 11, "momentum": 11, "equat": 11, "The": 11, "slab3d_t": 11, "report": 12, "bug": 12}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Building and running the unit tests": [[0, "building-and-running-the-unit-tests"]], "Contributing guidelines": [[1, "contributing-guidelines"]], "In a nutshell": [[1, "in-a-nutshell"]], "Issues first": [[1, "issues-first"]], "Format commits accordingly": [[1, "format-commits-accordingly"]], "Fortran code formatting": [[1, "fortran-code-formatting"]], "Pull requests and code review": [[1, "pull-requests-and-code-review"]], "Overview of the contribution process": [[2, "overview-of-the-contribution-process"]], "Setting up for development": [[3, "setting-up-for-development"]], "Contributing to x3d2": [[4, "contributing-to-x3d2"]], "Fortran style guide": [[5, "fortran-style-guide"]], "Basic formatting": [[5, "basic-formatting"]], "Naming conventions": [[5, "naming-conventions"]], "Procedure definitions": [[5, "procedure-definitions"]], "Modules": [[5, "modules"]], "Derived type definitions": [[5, "derived-type-definitions"]], "Custom structure constructors": [[5, "custom-structure-constructors"]], "In-code documentation": [[5, "in-code-documentation"], [7, "in-code-documentation"]], "Required tools": [[6, "required-tools"]], "Fortran compiler": [[6, "fortran-compiler"]], "CMake": [[6, "cmake"]], "fprettify": [[6, "fprettify"]], "FORD": [[6, "ford"]], "Sphinx": [[6, "sphinx"]], "Contributing documentation": [[7, "contributing-documentation"]], "Building the documentation": [[7, "building-the-documentation"]], "Writing user or developer documentation": [[7, "writing-user-or-developer-documentation"]], "Memory management": [[9, "memory-management"]], "Memory block allocation": [[9, "memory-block-allocation"]], "Internals": [[10, "internals"]], "Computing the spatial contribution to the momentum equation": [[11, "computing-the-spatial-contribution-to-the-momentum-equation"]], "The slab3d_t type": [[11, "the-slab3d-t-type"]], "Report a bug": [[12, "report-a-bug"]]}, "indexentries": {}}) \ No newline at end of file