From 16d09985cd544ed3b4e24f18e226bf30128ce039 Mon Sep 17 00:00:00 2001 From: Paul Joannon Date: Sat, 28 Jan 2023 20:36:53 +0100 Subject: [PATCH] Updates to C# basics + explain CS1612 - Replace mentions to Mono with mentions to .NET 6 - Update prerequisites / setup instructions - Update 'attach script' image - Fix code guidelines - Add a 'common errors' section with an explanation about CS1612 --- .../scripting/c_sharp/c_sharp_basics.rst | 151 +++++++++++------- .../c_sharp/img/attachcsharpscript.png | Bin 5619 -> 0 bytes .../c_sharp/img/attachcsharpscript.webp | Bin 0 -> 13638 bytes 3 files changed, 94 insertions(+), 57 deletions(-) delete mode 100644 tutorials/scripting/c_sharp/img/attachcsharpscript.png create mode 100644 tutorials/scripting/c_sharp/img/attachcsharpscript.webp diff --git a/tutorials/scripting/c_sharp/c_sharp_basics.rst b/tutorials/scripting/c_sharp/c_sharp_basics.rst index 0ed6c0b1e..5fa0f4c09 100644 --- a/tutorials/scripting/c_sharp/c_sharp_basics.rst +++ b/tutorials/scripting/c_sharp/c_sharp_basics.rst @@ -6,68 +6,57 @@ C# basics Introduction ------------ -.. warning:: C# support is a new feature available since Godot 3.0. - As such, you may still run into some issues, or find spots - where the documentation could be improved. - Please report issues with C# in Godot on the - `engine GitHub page `_, - and any documentation issues on the - `documentation GitHub page `_. +.. warning:: + + .NET support has been heavily modified between Godot 3 and 4. As such, you + may still run into some issues, or find spots where the documentation could + be improved. + + Please report issues with C# in Godot on the + `engine GitHub page `_, + and any documentation issues on the + `documentation GitHub page `_. This page provides a brief introduction to C#, both what it is and how to use it in Godot. Afterwards, you may want to look at :ref:`how to use specific features `, read about the -:ref:`differences between the C# and the GDScript API ` +:ref:`differences between the C# and the GDScript API `, and (re)visit the :ref:`Scripting section ` of the step-by-step tutorial. C# is a high-level programming language developed by Microsoft. In Godot, -it is implemented with the Mono 6.x .NET framework, including full support -for C# 8.0. Mono is an open source implementation of Microsoft's .NET Framework -based on the ECMA standards for C# and the Common Language Runtime. -A good starting point for checking its capabilities is the -`Compatibility `_ -page in the Mono documentation. +it is implemented with .NET 6.0. -.. note:: This is **not** a full-scale tutorial on the C# language as a whole. - If you aren't already familiar with its syntax or features, - see the - `Microsoft C# guide `_ - or look for a suitable introduction elsewhere. +.. note:: + + This is **not** a full-scale tutorial on the C# language as a whole. + If you aren't already familiar with its syntax or features, see the + `Microsoft C# guide `_ + or look for a suitable introduction elsewhere. .. _doc_c_sharp_setup: -Setting up C# for Godot ------------------------ - Prerequisites -~~~~~~~~~~~~~ +------------- -Install the latest stable version of the -`.NET SDK `__, previously known as the -.NET Core SDK. - -As of Godot 3.2.3, installing Mono SDK is not a requirement anymore, -except it is required if you are building the engine from source. - -Godot bundles the parts of Mono needed to run already compiled games. +Godot bundles the parts of .NET needed to run already compiled games. However, Godot does not bundle the tools required to build and compile games, such as MSBuild and the C# compiler. These are -included in the .NET SDK, which needs to be installed separately. +included in the .NET SDK, and need to be installed separately. -In summary, you must have installed the .NET SDK -**and** the Mono-enabled version of Godot. +In summary, you must have installed the .NET SDK **and** the .NET-enabled +version of Godot. -Additional notes -~~~~~~~~~~~~~~~~ +Download and install the latest stable version of the SDK from the +`.NET download page `__. -Be sure to install the 64-bit version of the SDK(s) -if you are using the 64-bit version of Godot. +.. important:: -If you are building Godot from source, install the latest stable version of -`Mono `__, and make sure to -follow the steps to enable Mono support in your build as outlined in the -:ref:`doc_compiling_with_mono` page. + Be sure to install the 64-bit version of the SDK(s) + if you are using the 64-bit version of Godot. + +If you are building Godot from source, make sure to follow the steps to enable +.NET support in your build as outlined in the :ref:`doc_compiling_with_mono` page. Configuring an external editor ------------------------------ @@ -121,9 +110,10 @@ In Visual Studio Code: - Install the `Mono Debug `__ extension. - Install the `C# Tools for Godot `__ extension. -.. note:: If you are using Linux you need to install the - `Mono SDK `__ - for the C# tools plugin to work. +.. note:: + + If you are using Linux you need to install the `Mono SDK `__ + for the C# tools plugin to work. To configure a project for debugging open the Godot project folder in VS Code. Go to the Run tab and click on **Add Configuration...**. Select **C# Godot** @@ -174,13 +164,13 @@ Creating a C# script After you successfully set up C# for Godot, you should see the following option when selecting **Attach Script** in the context menu of a node in your scene: -.. image:: img/attachcsharpscript.png +.. image:: img/attachcsharpscript.webp Note that while some specifics change, most concepts work the same when using C# for scripting. If you're new to Godot, you may want to follow the tutorials on :ref:`doc_scripting` at this point. -While some places in the documentation still lack C# examples, most concepts -can be transferred easily from GDScript. +While some documentation pages still lack C# examples, most notions +can be transferred from GDScript. Project setup and workflow -------------------------- @@ -207,8 +197,8 @@ Here's a blank C# script with some comments to demonstrate how it works. public partial class YourCustomClass : Node { // Member variables here, example: - private int a = 2; - private string b = "textvar"; + private int _a = 2; + private string _b = "textvar"; public override void _Ready() { @@ -225,15 +215,16 @@ Here's a blank C# script with some comments to demonstrate how it works. } As you can see, functions normally in global scope in GDScript like Godot's -``print`` function are available in the ``GD`` class which is part of -the ``Godot`` namespace. For a list of methods in the ``GD`` class, see the +``print`` function are available in the ``GD`` static class which is part of +the ``Godot`` namespace. For a full list of methods in the ``GD`` class, see the class reference pages for :ref:`@GDScript ` and :ref:`@GlobalScope `. .. note:: + Keep in mind that the class you wish to attach to your node should have the same - name as the ``.cs`` file. Otherwise, you will get the following error - and won't be able to run the scene: + name as the ``.cs`` file. Otherwise, you will get the following error: + *"Cannot find class XXX for script res://XXX.cs"* General differences between C# and GDScript @@ -285,6 +276,48 @@ As of Godot 4.0, exporting .NET projects is supported for desktop platforms (Linux, Windows and macOS). Other platforms will gain support in future 4.x releases. +Common pitfalls +--------------- + +You might encounter the following error when trying to modify some values in Godot +objects, e.g. when trying to change the X coordinate of a ``Node2D``: + +.. code-block:: csharp + :emphasize-lines: 5 + + public partial class MyNode2D : Node2D + { + public override _Ready() + { + Position.X = 100.0f; + // CS1612: Cannot modify the return value of 'Node2D.Position' because + // it is not a variable. + } + } + +This is perfectly normal. Structs (in this example, a ``Vector2``) in C# are +copied on assignment, meaning that when you retrieve such an object from a +property or an indexer, you get a copy of it, not the object itself. Modifying +said copy without reassigning it afterwards won't achieve anything. + +The workaround is simple: retrieve the entire struct, modify the value you want +to modify, and reassign the property. + +.. code-block:: csharp + + var newPosition = Position; + newPosition.X = 100.0f; + Position = newPosition; + +Since C# 10, it is also possible to use `with expressions `_ +on structs, allowing you to do the same thing in a single line. + +.. code-block:: csharp + + Position = Position with { X = 100.0f }; + +You can read more about this error on the `C# language reference `_. + Performance of C# in Godot -------------------------- @@ -311,7 +344,8 @@ a single code location: for (var i = 0; i < 10; i++) { // Position is read and set 10 times which incurs native interop. - // Furthermore the object is repositioned 10 times in 3D space which takes additional time. + // Furthermore the object is repositioned 10 times in 3D space which + // takes additional time. Position += new Vector3(i, i); } } @@ -358,5 +392,8 @@ packages the next time it builds the project. Profiling your C# code ---------------------- -- `Mono log profiler `_ is available for Linux and macOS. Due to a Mono change, it does not work on Windows currently. -- External Mono profiler like `JetBrains dotTrace `_ can be used as described `here `_. +- `Mono log profiler `_ + is available for Linux and macOS. Due to a Mono change, it does not work on + Windows currently. +- External Mono profiler like `JetBrains dotTrace `_ + can be used as described `here `_. diff --git a/tutorials/scripting/c_sharp/img/attachcsharpscript.png b/tutorials/scripting/c_sharp/img/attachcsharpscript.png deleted file mode 100644 index ce18738efdee62bfa1b67ffd6115b1ddd3ba0b64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5619 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 Jzi8S&{VxVi0?GgY diff --git a/tutorials/scripting/c_sharp/img/attachcsharpscript.webp b/tutorials/scripting/c_sharp/img/attachcsharpscript.webp new file mode 100644 index 0000000000000000000000000000000000000000..99047ca0f293d483f7f2ac22c772b057de0c9e77 GIT binary patch literal 13638 zcmaKSbyOYAvhU#T?(Xgu+}+*XB{;z)I0SchCpZKrKyY_=4G=u|+uu3o-FyFd_tjdx z=QlM~-Bs0H)jeyrnyi$R5ElSwONyyzsqpH+0{}n@YLj35BxI+AQ=$-cWm9PIN1Ni0z(u70I02xk6S7LfJp{` zw}g+6m%@*aw;}+5*Z_b&r~lS>E&u@Ddk{b2zj>7T0Duw(0Ih@n%`-~}fVKz#z+H7Q zbv6ChI1r#;a4RbSxG4t!BwYZ&m;nHI{eQ;|^z5JKK=CpFXn1B6aEf+r(w~gY(M}*Tad7;?&n4hj!zD_u zBR6yq$6svf#nB@i#UIsd*Mr}O#12#& zcKVqkX;0av4L>jKil<|hF-7sD#jL%qt5-9iFg_D*YN42sX1cZ>{yEdYFs@ml9BDoH zOJ;d9^H?;cerwf*F?ug4IK(HY{i-}t=_E?o)J4No%~TIASio2!2p$38iHW%Rh5c@@l{G#f!3Q+6z*aS9AMen^3dIn>Mes zqtWUIw7PVt?OMR`{!C>^U6PC7YiMWzOs8~$6$tc#6!4m3(=gJtm?v^*4FIJM+7yRO zQ>YAe?vBya+_R&XG*QhPnFiMD;pSFWNtxIj92_hh(Vz>$1Y!&&=&s4S;H9VTc5EVvNSFG4fk#uCN!>#O z?TGyjdy&)*mik^XMvjPMlV~52zVpl;Ha?b>gF~M$oiHSGm6>C`R4J}F+$0=ZeawMH z&C?D&FAQ|&3c;W~$i9eLRa=P5FrX0aP||>Jl{LtQ^mWy!gtf_^fD=+(vFO=KAf4Z; zlU$&TECsrdEMwO+iF^WK{Sb!QylP3jY!0IAcZG*nV_^U?cq;%%6g%fnHEB21{m9hi zu;UhJo?1!{b6ij3Jil08->j|AuQeYQ#m5~P(AsO#*9FdNKT=3#)hK1N#--8tHZX)f zJM*o6RC^Vd{WGb!QV^C_R!-$0R}d;#dF!`p6IfqrPs70E{^2y1okKo7YdNB=Qcgcs5_6*FZmxwhMRS z#jU9ydMveY>XAr>m0%Q{zYb)-$QB0>B`b@$l&^zUI<&R*WRH>!QEW_W}sJ&!IJRHcMXp|#VZNkTXu&9vRbm+Ra zg);Y`jTJ2Xu6aLMk|ATjF?^cgTBBPf`a^S(HC2VeqVDIyga+SEO%++RXP>Ty{g2sE zI}2oEpE5}?W)hDc8{D{9^T?+j*e&tHNMPaYZj7v zyK53Op^LlGQ=;?y_+3%dNzlrpfJVXI`!y;yF=MJCi))Ky6^|T_akJYr%U$D6NDpSW zA~^=k=4+1a9kz3I58DR)4u+Mux?LawtHW`M-2n!htiDU0UVX6HFg|Fr45tAv*#ulJ zg9`SMH#d7`S%I^zqx*S>sHsh-ccL%S?81R^}-S>&|@%)fXTV%Oi3LiF&Au3A#P zpiO+aOK?AZ`eb0O6BIkVu-^=WBrh?x0FDYD!tJ2SD#j*q9EFa{KR-L1wgVj+90)s4 zW+1<{hxFd-#VK+-RiU0DGS;^7`{Jm3r$%KRDgC_o2?(JZav0&AB$ta64~oauxXiIXNp9Q7Krod;54b4paO#0U3FF$ua?Ua7L6EeypCjuL#k3 zKTsE?lt9%lNTM>b9c~tm`kf+}Mkv4GnV{4aZrGV6R{8L&dxoBK*n?9p9`XrsQ4G}O zGGu{Be}58g_dX*T1nMzWCk=&h|5k9s6_t?FMEAQg3Fg816X(1c@)zOyGy@O`W zlwDIL`s2xjArDFB7Fx7SCv*GXubT)yTUuo}8m`2IbSsW)%g6%qlA0#V8wjwu5{!(u z#7rW=1{|^P24lPz+$KSvd2e70YZ#!^x8#N=e9p~)X}C4Rw+|^w2Oa+a+HSbZXr0QRZL@-v+c>9SskPCvQ~{+j>Hjn{b{z_3b>yS zy80n~@n__N2TtTvb|{W7pJgDLjP8+n#L7CZrmx#uxy`#Eq7CdrkIcb0lqwkEYC_Un z$sk>V99TEyp;+kDoJwikeHRb6Tz@NBMvsg1Y$1jcxsX2m=9#*!8)v;6+R_)77Esq) zlQ+pV+D>Zo&2>-kLs+33Q}KD(`Lnf2+;1<}0K3hJZCuBdwDW{ih&#tF$L13Ft+XS4 zw@CuqG7qo;jpN@+Ct1@;ydjtN?OLxQ$CD1JcSn>Q^4y&!9wc9jincV`# zRHVpnAfLe;!o#KL?EWcC;^Mo-P1xcEJo;cNdg|p!S#foeADUgv?r8D+SQt-DPtl&R zTYKdk(0D%xu(39D>BDuGz<^&>8KE;zqdF$Ph2PyF!L|f%iM|y+J~V(*W$|g4yqaKM z;S4ernC~kaLG*FK9v&GvD2Q3zAw1gMH6^Jx46W+naCk!j6sN^4VZi5i^kVYlVI|7= za6+A+nrawW{AsIS7;&ua7gU(0!i=CYhf}>>UX#UON(u$s;Qef-t*v8gV70qwd6SX0 zRjA}5qwzHkbKz24X5L|Jd((Pzfv z96^M^&uOD0j@w$tGWI8+d_QP2Wx{c@>8~03CQ{PIh&PqGfL|zTE~GQAsz}E@rB&V1 zO!1Mwr^(Kmd3nrc*UkJ!62kj;n21+BcC-c0R*6`fWw=`8P7 z)qBIX+fQImDUy%ZnJgtodb5(LwrB(u02p$c#QhC+vj4943F&X4LhW@m@ z<;C5x!h>xg`Zke`|CskxKR7kT@W~KK$r8rgVzGe;vil)&5T1KSord^U=-qHp+5W-l zSBZoH9h2>i|97X{KX|-T>x9(l6ZTrb5mxp|ZeP{G{u{-Wk!sDzet})elTvwR=nv8t zMO@6s9`MrcJ5mK$3*&9(Ac6?fAO381a97b@ALN=;-Z*Y@-RUb|=jJliYP2zZ(wx;b zG;A`9R3umLyM^V8T-Er>+4wii*Avx@cAbycyZnFjOI2BG&TWz$#C*Hl7Rr%o(S9FA z;K|4#W@v8nF}_C?yqidY6Kpap7CVrlhb`h>yNIN!lCiN#q>W+sn7j3nuDZ}miN01* z4Bp|bRVA7y-DH&v6tf-$Fsddk$YnXQ6iU+g?@@D`#i%$Y+cRVnO)cO_bKD+NoquHXU5h-LBW~G7 zqBH;WVvp-jR3zN6*ax!5u5)dhgNG)}T2+21GpQy%8`E_Pj??wJt>$Ny3ibyWo^?&7 zFC~E240^a&++1t9-7;!?E6rDvh~&I;Ps_y0-N-Lc^VYqRT}cAQX|Wi*{HyArz_UuE zoWFcii9J|y>u@8EOK^^Ss8$Sf^5EC78!kZbJtSz)&*#tBL^}t zaG-%dCp5bX8Q(9xrE#_>Hb>#Na_{$6Fus3|Q^;JDG;ZQyC z+975)0{9dTKGtY0Z|+{1T|Xg>vm|7K#Z)C!`( z9-_ntZGo}I3L6a_Gz-tDaC1Cm3w{1T0+^FfZ@)yS>>~*?&SdwS$Q11i`J1lBoy&)Z zv;do@0O|uWsU@^3TX097z5;5Hij&+C)u&H4w*jc%pf(V2o2v2 zR_Mq*CqjJgdLBn;K2I?^Rj1a0!0KSuQi_U|vP-b$Gc4JCN?GfI_#5{IE;=NENJzyy zOf@^KvC72<>E#^Xd?`q{`dER4vQV%lW-B-JrC?YyMO*_Ox27sTVBqN~3I^YTC)^Fp zex;Z1sZWXnH2VCm_WoQ3|1AUAjoyhPC5te+m2vZjs}hH2Mv3oFxG~idB5G z;3VFU-J_>VXn;2n`7Wh?u!RoE1_rBC!m%XD0*&ATcK8o_9s!X7FBYQLSyIRB)(-z# za@k_iLbs8XhH_{E@dtkzX$iq9M%t%P%`plOnYrZAQ1$q}g-$>06vX%AY;N?3lrL&S z6EsPj^P?8g3zZShb3*qd*2bA1mmAdcv{~8+M>@7zOo3xmcUUO1F5pzjR_#xzuX0%; zpGw0r27U#K_X^X6sy7-LrscV=H`NmdKu*2EU~`STif8#;QNR89MBUi4M_%Qa?{YjK zzWN-mLNNRIO<|}6VQtW!-7=|xPdiO9&Sazx-8E2{W=g`f`hfwhNG76Gqa=Ign5D8U zQGi$@sZ8gh63(tlQ#R}Aa)i(*ti(rgZY-?0E+DwGzU0I|vO>)+CAt#kA%ERHCu_hb z(1I^PNr7pQW#h=2e9oVxkT|?OP`PoVIeH|6^sael^TCq7kwjByyl!Z5ayhT@*Vvnd zzGBD^18pNYg0McKp(AOrAGbg0_E0Q4d{Xx?CiaO2c=EacNAA@8L~H%kp7zG<$aQm% zrN-_8r+ElL%?#V?HQ(AZ=BEkooVNDffISd|Wh(rg&EFzv&-m#==br zlIvByo=X3AyWV?k-+4>!$TKCN8mu~MO?h=~d}wKD^eZ>e&P7%#>$D+6pKMX+&^*)Z zoFTfH(<705ziv7}JL&K^>s})1Br(Nj;R~KCAnxKbvdfU3`59_ce+ENfD-NaTH)gVL z<4<8!U?SW?iUub9*iQ?i*iFM)G*HBn7%Hb8o?=qtBEH{}FwDJzN|E$Ra}PFVHXQ%; zR+hlaFbT40Emf!WWARF*@e1QF^{6fle!8@^5^vey;w2KjtNSp@xZ24myJHWd@?fQ$ z#>p7u0UZ5vdkQBjR0%97P@@xyEY84rkMfLd+1a$-Csd08QGs@2WA=;jlJZ0>p~G^^ zVYby31A2s&x3fsfCpc-#u>gBj@&^hSEFOieU`DT$-KpK3s6HnMp57W)k%e)b4GN?q zFWA+QarIO`dL5`)O8!X=2#)A&v-n1L(|#d5s>`EshZWp0BS>>9)RX{A=oT6w6^lLi~WJUvYg;u5&%Id!R1E=IPaA|Km9NrmlyC zXGC0|P5c!>XX@7~>Meb~Rg^ygEo&_LUj~M*D|ogmUjM>!tn7Q1BC^;5HA*{^C-c_ujmj6+u<$-t&GtewxmIE1V8| zpF*@gEq7PY7qPp5t>1bPonRtXn&sW(24(heRnhJG0FgE5s_mb6Mo->PIIq6k|S=o3`4WUcx)X zSWirE=AXJanl`b2^Dxz2*IB>Uac08*yp>)2q!O}pd&&eo#+>>xl@UfkhXec`RPR9T zRu>Z`)L@Iud%r1s+g9vb3oaBSSn(;cCH4BXy^O_%7vgApA(iR`BA&9}#`raH*p@Qb zMRb&=w_SItk2E`%%mED3dn}Brp*yn%M^8S*-|K#(wvTsNi?rYagHH24uw?CO5%LYO zAsICas8eAq85$ktSCG{Lgk2K5U-}m5{)U%GLy5|?AI-7&mF?>R}nAtalp(xobr#ne*GH#KS`qVYwwHX(Qy*D>l)f`F5o4&d~RkEYb5T$W7 z6Ok#wb%>_z=!99{&VePznEvH-zh{^49D6wl|%-3~+ z<{U9Flee;8^D&vjw;ixE$3daI19z(8X2N#(5teaVbcLkI^sErx1FG5J{KhGLBN&Q~ zXbEu?T)GMY{z6wZi5f;(i=E9Qkk4#-@PVqk#4xXaVT8Txv0H@-*mKaQn$A0ZKn#3s zCcZ(WFlv&aG}ebs(|=V&Z$X|rBEFpTW@v~cs`nVi2Tg`h$>2G%NPG)yg`X-qg)(QV zzkF6-nQvB~OqWh-xllQ0HPPBJtIkF&CV$B?L=a+3T+|M3-)A{ajSLBLpB}$NMmRN( zB8o}YU^)5Dg;-zT^QJzem`2@VFFD#))jl$vrRI;XuYWJWnyZk5c={R%?gj9XG7x62QoJ zZK2bIX;PmCz3hC>dgti7udI^*e#3-91krYR?tW6EXG18(h;9wv4{om#;&gp!f|e?j z?UJI~3B%GKw8}lqgDCrdxB1uu(3QQ$Fdo+3c z#sQIW*TtgOZ?Y1fM)6ZcEXYp)<6qi1fkMI0<^?&KnoWQ0Wfb9T6bu5811F&_GA^lM zqxsAlpaE1u`Eykr8};d((`)>B1FBp|CH{kV@K4Xy{3~qT*%LOv9Si!m*HZ{* zw1s#z_;t^!3SZyEg*SLCx*gh9)LTGwBGrPFYxNwu9SzQS6 zw8}lUd^xBS|4ra)1CeqF(@HX{4*Q9Ke4EVTU;@-(%e6syi+d34`Z08idGcWg_!+>h7KCCIp-p+3LXRiry5<5Dfy>1ehgRu4)EYtBSh z(V)?Wp@b;)V6di|tlsI3#LJE3J6ZEZq5np=%PmT-ILR0)K#*SilDqQKY}XdiKxNcT z?|JIO3vqq4S`nrx=IGtuUw!bG98pfbVzNhCF`qqBXOJ)O!kJeX)g$`V_px?Bq|2GR z$|OxCCPf`zd9^)DR2QxVzf1pM-rc(72a#k6cWax=Rl2uJ*k9Kr}4vmrQ&8YFw0VMboJZ z^{V^v8z(;Z(i2Ap0|zy%sK_Yg#kpX4SJ|K6*mzbl>7&`IC?WfgcG^%EXa}(RVHxLy zhrr#LX6<|sfk#)y$KjLa}+h8i=zQ zhK3#SqZO+U?zX_vyFjmH^4eh6{^_A|vDf@=JVH2FD1rQ<;>Dlrld$jOz^9%5%QD9X z$+<(GLiobR-eJeMgtc|P{;$pMTBrGb7G~Fu9!mO!<$-EX!L7)Q(^UdmoT#Ewn$~}NS zrM5VXx>yajT;>X_sQ^uwmX>+?J6@4GN|?_WQ<2Trym#4MsxkS-+w9E32FZ>6uKvaT zL`tlVY4S0z2Z93oRw~wq?MlZxFhYr~%jNZbS}ysSv-50h%1(GV*w!hF)FRAE4{51C z2@Deva6F!_L?9gF)-Nuws5C>YM4mW; zUiIC{Dd>;H*Q&x7uoXU+7>dHw3P|nskf7XR)ZeZVRMmINGH0ajv(b@v$`=%(X@Z*b z{Av51-@qhU?OKWIPRfT;fY`-4nkwrcXL*)+qftzAXHndD1r^AN_a6q0mh{ophIWZ6O9;d?UG3#~$J@jBu3pL$YC{SV0-Q+`^Q z?>Ud=^y8Bb3y;Ms%9j{bo)gS(7`>H2-`yC<=Y)$Bw}Z5ttIs3BPO==MkUSgx#;IH4 zkN>_VQX82QS;2x$Y;nte_`qLCG11zZ0T1jK*BXD7*l210*o3sO%nLukS`InGT-0NQ-%a1XIc>81+)1M`th*bW~%=UA-3NR|J4pEBMU9)m% ztWqrQap{V$TXr9qn_Q^v?CBs;J*6Y|YV|N}3_kzfdx=LiPkV9qba|aM6_PCZ%#0dZ zVj^zm*#N(kywQ=ZoB_w+?3$c+)-IJ#|!Uj zi5%Nir*?b%f_+EV7RH<2eVWnCnEOYai=L!v8t(Ln0)aLI!5WFy*`1?IIUQmUG$mNZ z;`$Y8)N593YlavptQi75xp0n0?aM^_rTWhWj(7g#W;Vk5ehZY)`c0v>5}mc=#E3G= ziZl=BZ_iDe_eAH*0j8JX4l-6RH{D@>VJ)D9sN17u#x?>X=+8kjw*insYalvC*ExyI^G?k+@yFU z+8|(vZM@CcNMksMWE-#k-hK9LQXX4BbAmc_dRaTzMg-jfQMt{+zwXhwg~L}$*5q^- z@-b9aH)?+Qua!WXuMeXKcfD}rrv0K^D9z1JpPvSz%z?_dJ|7jG2c@*5NoJ=J;5{Q4 zlc(3k7hqR5b}e98x^?r`*YC?Go+RpMP9J+L&PQ}HaSo4}nV?cOM7=Q98??9_h}|R^ z*NA%=-?pr|BFKl?u~2{H`$8^XPpYd&*4LsIo}bR3^G zv;x9H^%RQetH_LREaUqv|=-|1oQ~Mz{^@&<{^EUS30W+N})(g zoSlXyRVWn#5YS8ePCS9P^f-;s*63KUP1u7UgV5LX5S?7D+eiKsk-9F}C8pj*AaYnS)GCE7=R|3s>R()VZUJKMqMv>{Oy+(@_SFLdH$9U5U>X)Rn^N#?er z{#Y2c!AXG0YJUbo>wDA6*u@qXz9YtqPa)9y;M-zR-O!6m{cMQ!%7rvoIQFoFa zGjpF#Ts|S}jBlzN$2x5C^|H^bU7)59qbo#Z zleOR=3rUOg4z&v|sHS>bNYU2Y3!wfp4wYEtJtxzhE_V%_!E*^4J1G=5Mr})OiJJnf zR_~u1(Q1D*Ox7uBf_hH7f_n&BrW{8cieu8ZcjGncyPtn`$_up2M+K!}T6~x)vZT6Su3URw5^Tz>{?8FO|3^ohgoeDlo$h>+ONJ^k4;c$Ul>w*QIfn; zIPI0vh(&1^c|PI3-xv^YVQl@Bx3TJ|vl1BIi2?_n1l!VOrj;DTQ>OIa?sM?@MiqIqtv$V$e2Ykiab$s=w|A-Lv&C#e#hSK~`5$UxMNL8Z*x9XYJ1uzrkC>g~s65E}xV~QzhEQa%3#On%CgsKLBv{gS!(^Jvx$kt%nZ0!DkeKiu`~ke4oPP}|B?d^au7*> z=A)r8a}3-oi4?y0)7u-T!CeJzLvitoN?}z~Q%wcfRjPxZh*(h61|{U}?i4*7s8~>? zA{aLKz(=8_f^V($(c$W-bT`$QOgz%nF2Ke~d?_Ih{Iw8}I|jCqS`+R2WA7w3Pv)J~}^4fcf&SR=f{{sZv~ zS`24=PS8w~hV=nr$dlhwe%{9uQbCRk^;0L9EUdE|@07!r4k52c?~C6YPyASxK`+dx zbv~o@!bow}Ei8@F^@|?G=Wyw$rY1s(FCpN$0X90Dx8?}^j1KGY8K2}B( zR66rbR7ba&aA>9e(2|{W#0=4(evGeM@};1KcQF)Sr!YL0R+6(so$DeB{r3d4a!7HK zsSu35ZgME=N@Ro~5~6n)UtJNbUeF-x+tju+%iILXZrs*gD5QPatVz`+0ir4 z=ht5Ux(hHCD}2+K6fsiVm`b$-FlKWU=s>^IK2Rn~Ms7G`DSJu0Jyh87sRi)L`-{9i z?CCeB7ogFZ`>9mYNi|Q3%Ec9gL)f0driPVhV^+8RP|6ceJkQi|M0#K5yAZ5qY+jPX zuna2Z*bsK~_KGw!n6YJQ0_}q0K_hSBx!q0-$#^OOlhF1!wL<%x{p&p%%w?w%lkMk< z8AJ-CYQwyb>%IDwjj*%a$gCZ+x3~*UJ&?dSoP@myOzL#9g;Ak^N=S7PM51BGrn&G7 z)K5vgotn$2HBhyC=~;#R2u5~!XtzlRQeV1bo`yy8hl*TDTgB3=kT1T0rhLvmp;u$^ z3Zo*0&6VBVYHUg(vb9vgrQq;-7m&w;$+K{tVg!a>wHq(Efg^1nU;k#Ifhr!5Vsf&SPbd zTi}q(vtHLM%zkgO;TUgW=F%79dAbW^xxe+oLSo?6J)sg1d?d^h^7!mqDjuAu=uZui z#4*=D`b^q1{=DT4k+fsj)Nhy1DXSPrptxp9k&} zMLOhyamWnO(->n0I?s>yq8uZ^fWH5<%O)Np&|9AKtM&33EdHQ6M|0->)zN=-nEIK{ zSg82rZ~$NpylfG1F1>-@1XKF8Nfxx%b|xGXG7hz@v1L^9V`>c|faB_7pAze>k&*78 zg0W@|oiDKql^xSBwe?$g#aA#?iQ#}%y{EVyYH9WANzXTy%wM8wdQx(tu<*x^kWEEt zc+oV1Ejh9gemArGn39#z-NR4$sEFSat)$)x-xA-OXpaegsfa7-!wq7aG@e!Sj{#h* z2pYt@p-yp*Rgs@KH3P-@C$o^2au_EQ8VNtYk9OMJbM|O)ch(%oDIbA0kbXiUd}{dB zYH?LD#B6Zv0<~6VH>0Z0ABGI(Fw>yZ5Ki;W!pn`XkEP#Ox?=pM7!v(G@r&cEea9<0 zI`Ll(dK|)h!~hN!q(9n_?k)v4hFqNzsZR+tUXA&lr0kX>D=g{^4YSK78h>4pC5hKa zMqfuiSzd?Y#T;Em9kA|;+>c3V$Y38PM>TGyEpPQwm>#U+;MiJqJ&CYsTZZKx7q4pW zAwcwvIfIo|x0W@t>K8baJR`jtM`}7T=RNIK5=GWr2;Q8T0x+(O(Y+tTiR@fGpucbx zKE|_$j zt6__tS_ntM0YS1zJ1{^#7j3SR{`^?Hu@XRgIlLzDry_!n?dqO_zSAV_l5oxN#_Ehf zh`t#O8)O)fmq^EmbOlWdIrjLRQ1$PF2lT!UY24IpaK?(~FV+JW>1c9{9GD+o?#c^7 z@YwmTN*3BEkFiNN2x=(aip6${AKhC#Th7QNYb0PQxB&7mTMwHIS_!k0+^&BNzfX6K znS(0D9(_mm^`Qbyg@F|()=$+WF1tmaQM2ry*DIqEseG7E za9(&Vi2oQLWyYQST8#^gE>k4^jIB2M?zdS!90RhQ(x-g4Jjq0@$h%j%YMQ~9JK2Qj zW%U)?M0Ak~AsE2%+h7i;%j((P8F;mcc&}#X!hu)b|T+L1_* zFup=^l3Ox}{60+mLubrg>>EiF1{Ne!+bQvnX$_fexk9~K-B2R3@zQ#zRq~Ua#D&zx zRKWRxHTqzHAlwed5V(Y^&I7m`E~_^=3CkD_2I%a25Vj|uh7}993lBwR(}(Cv&Dm|x zRIg32dHKZD7gF^z2~<{nPF;nv;G|B-!oG+yzyN<#<0>?Z9^*(xuIbW{k<`D&>cK*S zMa!(h|M_={O`dESZ`wZCu3fkx$$)>68XW*gg??1tTzzh{}Y6iiV0j_|AB8AzI-Wg>#ThSF2!U z_q`S(@p=Kf^YaGA6y&*l8m9d8KB=M5-6Lr$fKcVRl-l}=k|Da}@cl@(<)gk3g6i&s zsviWUsa!#bYU9tT`ffPPEt#Ar>}*Lq45}g>OMmq&q1&%_2FstnHT*VV6pIM26f?X1 zse6wrxlIvWR|_`m=h{wtu)#^|+msESov*z)5Wb-&63Dq11Mi*)Qv#l9_6ym)z>|04 z<+3#XlSRwCisx~NOJRsjWXu;!905{GH6hKP2L3UC6cZv4DAi`M3BNFgVr|ae{VQ(o zXdu@9068K*7D|Uh;1YQ?7lGZiNS<|Ys48=6`c>tN#(LrcJ1v1*r!RNQS}fCKp5O}{ z2C%85jg4+1qjPNd^2wXSMH%I>*th}-QmL9PqI$ENgz!sBSTORAig_VhB#P7 z^&Mj`oP2jPmEv}dfOz0{fgc9#5+>+;vsAcD1@>k8mQBpG+4K7mt_3l4rGNv^KfU*4 zO0AF=S1wXlg2_f!BHA5;3(rywgPchgIZLbI=)Jc1D)5d{QOR5}y9@IDy!Y$IZV+oZ zr@Y*y!4A!jL699QV03wRA8HxtMNYGStvdOeDDZG^=-bTFg=ven37z8q6Em0s>lBTR z9Z%*N1gyamE&`AmIDSHysUMo#(SfeWT2sBzfpH4T=zm7~E6ub)#|4r44Mo^@2Q#*h z;=FVt@3%;a-Fxgw-_fyV%o9uMNp`2+Jcn1#^5w6q!NQDonH<)O*1e&jLCL+aQv=N9 zTAa!P%gl(&_Uv8Ch=acq`pI1SqD|AfGe|hHv7e*Ikwe{u6h3q?J-J)=DjiP3Vy#lwb!=eV{bw*CO$^Ar$RF?x<%;=jh9P5|MFEk5j>GMxq;nX!Wlh>|=8lp6tm z00_io_FaEq^}`Ud5+UguZG{}=A%c(sa$C+u_!OiGuI_sJ^>RHMCX_k{=B7*HZ@#}D zt}7W9VlCc8l=Eq6gS7fCeh2Lsw2}KbyqE(Wa#X0WiK+Yi5qwL5@^*+Uy z6rH5qUOg}{7%#&kHyGOVCF4ph4W~PkeB(`2rCE^5HzxpDRH793xcqbGx3$@qv-KUr z(JAGjhd`z|5&6-JE4|k-d86k)RkB#<`y*@MRuK*l*=N0_N)>TSh?}!WIH%Af#(759 s0Uv=T)SL%uiKf>vyBi_3m<(r0cau-Mp3SAsJ@oq96B#zX9suxv01>pA2><{9 literal 0 HcmV?d00001