From 4e01de845a66ccc1623eb1a335f7648f82043510 Mon Sep 17 00:00:00 2001 From: "Nick J. Connors" Date: Sat, 18 Dec 2021 03:05:37 -0500 Subject: [PATCH] Improved the cube sphere textures --- NewHorizons/Body/Geometry/CubeSphere.cs | 26 ++++++++++++++++++++--- NewHorizons/Body/Geometry/Icosphere.cs | 15 ++++++++++--- NewHorizons/Body/HeightMapBuilder.cs | 16 ++++++++++---- NewHorizons/General/GravityBuilder.cs | 2 +- NewHorizons/General/SpawnpointBuilder.cs | 3 +++ NewHorizons/assets/shader | Bin 0 -> 18191 bytes NewHorizons/assets/shader.manifest | 16 ++++++++++++++ 7 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 NewHorizons/assets/shader create mode 100644 NewHorizons/assets/shader.manifest diff --git a/NewHorizons/Body/Geometry/CubeSphere.cs b/NewHorizons/Body/Geometry/CubeSphere.cs index 6593f361..05962a78 100644 --- a/NewHorizons/Body/Geometry/CubeSphere.cs +++ b/NewHorizons/Body/Geometry/CubeSphere.cs @@ -25,6 +25,9 @@ namespace NewHorizons.Body CreateVertices(mesh, resolution, heightMap, minHeight, maxHeight); CreateTriangles(mesh, resolution); + mesh.RecalculateNormals(); + mesh.RecalculateTangents(); + return mesh; } @@ -45,6 +48,10 @@ namespace NewHorizons.Body for (int x = 0; x <= resolution; x++) { SetVertex(vertices, normals, uvs, v++, x, y, 0, resolution, heightMap, minHeight, maxHeight); + if (x == resolution / 2 && y < resolution / 2) + { + Logger.Log($"{uvs[v - 1]}"); + } } for (int z = 1; z <= resolution; z++) { @@ -53,6 +60,10 @@ namespace NewHorizons.Body for (int x = resolution - 1; x >= 0; x--) { SetVertex(vertices, normals, uvs, v++, x, y, resolution, resolution, heightMap, minHeight, maxHeight); + if (x == resolution / 2 && y < resolution / 2) + { + Logger.Log($"{uvs[v - 1]}"); + } } for (int z = resolution - 1; z > 0; z--) { @@ -72,6 +83,10 @@ namespace NewHorizons.Body for (int x = 1; x < resolution; x++) { SetVertex(vertices, normals, uvs, v++, x, 0, z, resolution, heightMap, minHeight, maxHeight); + if (x == resolution / 2) + { + Logger.Log($"{uvs[v - 1]}"); + } } } @@ -92,8 +107,10 @@ namespace NewHorizons.Body v.y = v2.y * Mathf.Sqrt(1f - x2 / 2f - z2 / 2f + x2 * z2 / 3f); v.z = v2.z * Mathf.Sqrt(1f - x2 / 2f - y2 / 2f + x2 * y2 / 3f); - float latitude = (Mathf.Rad2Deg * Mathf.Acos(v.z / Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z))) % 180f; - float longitude = (Mathf.Rad2Deg * (v.x > 0 ? Mathf.Atan(v.y / v.x) : Mathf.Atan(v.y / v.x) + Mathf.PI) + 90f) % 360f; + float latitude = (Mathf.Rad2Deg * Mathf.Acos(v.z / Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z))); + float longitude = 180f; + if(v.x > 0) longitude = Mathf.Rad2Deg * Mathf.Atan(v.y / v.x) + 90f; + if(v.x < 0) longitude = Mathf.Rad2Deg * (Mathf.Atan(v.y / v.x) + Mathf.PI) + 90f; float sampleX = heightMap.width * longitude / 360f; float sampleY = heightMap.height * latitude / 180f; @@ -102,7 +119,10 @@ namespace NewHorizons.Body normals[i] = v.normalized; vertices[i] = normals[i] * (relativeHeight * (maxHeight - minHeight) + minHeight); - uvs[i] = new Vector2(sampleX / (float)heightMap.width, sampleY / (float)heightMap.height); + + var uvX = sampleX / (float)heightMap.width; + var uvY = sampleY / (float)heightMap.height; + uvs[i] = new Vector2(uvX, uvY); } private static void CreateTriangles(Mesh mesh, int resolution) diff --git a/NewHorizons/Body/Geometry/Icosphere.cs b/NewHorizons/Body/Geometry/Icosphere.cs index fd7334fd..5ea5cc2f 100644 --- a/NewHorizons/Body/Geometry/Icosphere.cs +++ b/NewHorizons/Body/Geometry/Icosphere.cs @@ -72,12 +72,14 @@ namespace NewHorizons.Body.Geometry Vector3[] normals = new Vector3[verticesToCopy.Length]; Vector2[] uvs = new Vector2[verticesToCopy.Length]; + Dictionary seamVertices = new Dictionary(); + for(int i = 0; i < verticesToCopy.Length; i++) { var v = verticesToCopy[i]; - float latitude = (Mathf.Rad2Deg * Mathf.Acos(v.z / Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z))) % 180f; - float longitude = (Mathf.Rad2Deg * (v.x > 0 ? Mathf.Atan(v.y / v.x) : Mathf.Atan(v.y / v.x) + Mathf.PI) + 90f) % 360f; + float latitude = Mathf.Repeat(Mathf.Rad2Deg * Mathf.Acos(v.z / Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z)), 180f); + float longitude = Mathf.Repeat(Mathf.Rad2Deg * (v.x > 0 ? Mathf.Atan(v.y / v.x) : Mathf.Atan(v.y / v.x) + Mathf.PI) + 90f, 360f); float sampleX = heightMap.width * longitude / 360f; float sampleY = heightMap.height * latitude / 180f; @@ -86,7 +88,14 @@ namespace NewHorizons.Body.Geometry newVertices[i] = verticesToCopy[i] * height; normals[i] = v.normalized; - uvs[i] = new Vector2(sampleX / (float)heightMap.width, sampleY / (float)heightMap.height); + + var x = longitude / 360f; + var y = latitude / 180f; + + if (x == 0) seamVertices.Add(y, i); + + + uvs[i] = new Vector2(x, y); } mesh.vertices = newVertices; diff --git a/NewHorizons/Body/HeightMapBuilder.cs b/NewHorizons/Body/HeightMapBuilder.cs index 82964176..246a1e42 100644 --- a/NewHorizons/Body/HeightMapBuilder.cs +++ b/NewHorizons/Body/HeightMapBuilder.cs @@ -12,6 +12,9 @@ namespace NewHorizons.Body { static class HeightMapBuilder { + public static AssetBundle ShaderBundle; + public static Shader PlanetShader; + public static void Make(GameObject go, HeightMapModule module) { Texture2D heightMap, textureMap; @@ -26,24 +29,28 @@ namespace NewHorizons.Body return; } - /* + GameObject cubeSphere = new GameObject("CubeSphere"); cubeSphere.transform.parent = go.transform; cubeSphere.transform.rotation = Quaternion.Euler(90, 0, 0); - Mesh mesh = CubeSphere.Build(100, heightMap, module.MinHeight, module.MaxHeight); + Mesh mesh = CubeSphere.Build(51, heightMap, module.MinHeight, module.MaxHeight); cubeSphere.AddComponent(); cubeSphere.GetComponent().mesh = mesh; + if(ShaderBundle == null) ShaderBundle = Main.Instance.ModHelper.Assets.LoadBundle("assets/shader"); + if(PlanetShader == null) PlanetShader = ShaderBundle.LoadAsset("Assets/SphereTextureWrapper.shader"); + var cubeSphereMR = cubeSphere.AddComponent(); - cubeSphereMR.material = new Material(Shader.Find("Standard")); + cubeSphereMR.material = new Material(PlanetShader); cubeSphereMR.material.mainTexture = textureMap; var cubeSphereMC = cubeSphere.AddComponent(); cubeSphereMC.sharedMesh = mesh; - */ + + /* GameObject icosphere = new GameObject("Icosphere"); icosphere.transform.parent = go.transform; icosphere.transform.rotation = Quaternion.Euler(90, 0, 0); @@ -59,6 +66,7 @@ namespace NewHorizons.Body var cubeSphereMC = icosphere.AddComponent(); cubeSphereMC.sharedMesh = mesh; + */ } } } diff --git a/NewHorizons/General/GravityBuilder.cs b/NewHorizons/General/GravityBuilder.cs index 1aa9f92a..d00a5039 100644 --- a/NewHorizons/General/GravityBuilder.cs +++ b/NewHorizons/General/GravityBuilder.cs @@ -25,7 +25,7 @@ namespace NewHorizons.General GravityVolume GV = gravityGO.AddComponent(); GV.SetValue("_cutoffAcceleration", 0.1f); - GV.SetValue("_falloffType", GV.GetType().GetNestedType("FalloffType", BindingFlags.NonPublic).GetField("inverseSquared").GetValue(GV)); + GV.SetValue("_falloffType", GV.GetType().GetNestedType("FalloffType", BindingFlags.NonPublic).GetField("linear").GetValue(GV)); GV.SetValue("_alignmentRadius", 0.75f * upperSurface); GV.SetValue("_upperSurfaceRadius", lowerSurface); GV.SetValue("_lowerSurfaceRadius", 0); diff --git a/NewHorizons/General/SpawnpointBuilder.cs b/NewHorizons/General/SpawnpointBuilder.cs index 03500a1f..e462586a 100644 --- a/NewHorizons/General/SpawnpointBuilder.cs +++ b/NewHorizons/General/SpawnpointBuilder.cs @@ -20,6 +20,9 @@ namespace NewHorizons.General spawnGO.transform.localPosition = module.PlayerSpawnPoint; + // Move it up a bit more + spawnGO.transform.position = spawnGO.transform.position + spawnGO.transform.TransformDirection(Vector3.up) * 1f; + playerSpawn = spawnGO.AddComponent(); GameObject.FindObjectOfType().SetInitialSpawnPoint(playerSpawn); } diff --git a/NewHorizons/assets/shader b/NewHorizons/assets/shader new file mode 100644 index 0000000000000000000000000000000000000000..2340d65c8bcab0cd56639b8fcca6a12773a61492 GIT binary patch literal 18191 zcmV(+K;6GpZfSIRMpFO)000IxE_g0@05UK!H!d_TG%#i{000000000-4*&oFK>z>% zTL1t6LmmJD0I>l80WWL-07jeuK@I>38~^|s0Pq+91VceWEoC)kV>e+kHDx(rIW%E6 zF*0OjIXPxEVm4x8VmLBkHUM1!00;m80AeGrYapoeDQ@+oLQVU_5JTDPZriw3aXFm` zb0H1I6Lk^S<)kCU-hqXgo_g_{fH)Y`FnwzEq(S^7o6}DJMMLmPiK4=T@TLy_)`aa? zxydJ+7tO5ec0~lE7(S~`;&h~$CcC0CY@_ICS3c!KE)Kw_6aB;4s6j0yJz!m@mWjDd znXOE&2)VyOiz@k_rc8!ru(r_=P}5oRX-#3)-Q;pIdWf?f4ytts9|-k3cjHxP9a#kHWA_%bL$S(-TzOTQ7{QyHss=WP6n*aDD*`#Q$99Ubu{9AVG-Au~$AN&z0Dkq(u;w8t3IaCWjGouQ z{ZdEvVbJ`A;Qniq5KIxMy8g?<=Fe<;%}+p zhl_Eqy1FLsBX_7R5>JDsT1<30E^~tS3E_T3IP&8riv(2g?#%Hx;E9V#fA={Yegu}G zXF9P5e9ZKxcS}0Eb7$YYMZKlb{@c>0?9{+${f;?raDsI7d3#jgqJ!<`2u#FLT(k)A zV0<7wF@{$2V@cY$?#dE#U%5c(r_)#7zNR`B4AV|CXL&}#nknUzE&$CdM%#jrejzUu zNG2-G5bLa$+O-h|yg!dOmlJ8UD~u;0&i0Ryz@x_~&7L?Y)14jjQ`Xl22L;I)nug_@ z%_b2^sDr4sYz)`xzS%a);x%@%ks zer01UFftC=#MeCTbJf4&+kHj>4C{emj+4;7xgJ1V()i~5t~fA^!f=Eazae9qYo?uL z!a<55Afdvc;Q_;Q1hJKS67g>C{JH(mgEkPbV0bj#i?j;(!)L42<)}}t$5K8s6vkQB z`jhp@C0zrn0xe7JohHqCDiy(ZXMuHV)fUEyp&JG4UR_f#1$rKSdUn2Ei^S&OcM%G| ziQxt#Dlwj_!#gVYiPqnSfbauOz8)DVF*6R4t;F9St(LlkLw_<|S?yp{i?fbNVRE|M z7fVWHOm(SL>#h<+lHMR2h>k2$A9f zhiaEU>(gV3Sz0M_07o`<%pEF*_&?}R_ujnU;YbMyXO+~%bGnieAxk>}X{jCw^$Am? zto4yy-fIM$aE}$tcPfzaD)j{kS(SvGsbGAD?81o3kp z_iXs4rSM^k`R4XtjK*7^<4_Ld)J3)riN%oIp>GEMoAc{j=4Y@wh$XQxf%Yq|moMaR z-dYNVS8145xdw|xZ3JYe&YUTf?X%>9MqL~Sfr%3>nxev{!mYf1oULu>@CH&)VFwn&#lS~oB>7)bd9l$70tC^))I zL3jXo_fzdpnNu~7wDvvCpsa>12>KMSv@^nI`KeqMjWkL{^b$HtL+XoZGS@Y#J*WwS z(0>MynIJ78&S6`X)Q6Cw1VkDWp@^BEh*c%7eZsFaxBCK>3KL#E_5Z?IUl`oXvqc!_ zgH}2_cupNi#z|+I8i}w7rV;5oF@_)=2I9{tSrBlt% zQX<_w=u#ui*?uH}`MyPiWJ(z#MZ;ceE_xZsYw9oR+k+y^k8h%5fI$5~^rPi3u?^>t zZw1{c@U8!W{OUQ>yllN_&JgMvW^&l$`tKO^6IonLhaJMd()7r#3}2R>2qR(_Z8Goz z_ms=S`#k!1#?Ujv{^d{Ab1>19!P`Er&H1O{dubd}?0=!wMwgy6Ux6Z5J*mJcTe9Ht zHTdYMV%A zr&HpcWC)32K}2t^CZs&S>kt>NFU$}8sENGdYt60>)WYByqCs;DQqJN)DBjx^2<(UH zNWAy*mgA1NDVEXLh${a1x&&CbX<2;EJby`WP{Xq*%v2GtU8NRv6@F=r-8Y zRy}G5p;t?8ZfNfAT`@dXD`T$BwW1hX1ESXFQ*2b+5aVaGDeL`w4H6FhzEF=wDkYL+ zmRc8)!tY;T&C@-nk3yC4Wf+2X4@~s#vH3;&`auKtLKz^fE+5bVx6h<_auVbCHA3=0 za8JtPuVBqq2jvriCrg7ZG9|0^<)*Jj$aht^lxb2X>Ll@TEUrASRT#X~h!_6{#zCbp zUUvewA7?pT&C7UPE2W1n1O$KRO z?{Y*Cq6h9aTv2;0gvMOg+liO=qzz&{L1OEn(dBQ+Ki~rlJeJ&neE40a1_zipaWPao zJ<&V|xTwM3np*d7z`{Aa_;*RgCjq@l_lXL zpd+g5nPm85Hyi#n)mkrpwF2U3JGwIKx@LnIFm-D~bFUKEdCv`=^={^ps9V>YA@6xJ zw*)!I*q!Kq$B+OGrH$yJb2eq?hlC41hDs?UA3a+^p?7^B^63`yUVi-E@i#75Xml#- z7!MPj=mRd{NP~H*ysyyPO%*u*)teU!GR?K(6p`^Nw+8G-7_!K&Fj2a$A{c$B`$_zk>jS5Vl`TRMz>uobvf@4&-0KOY@bYy@H$ErMg;NplXff&23GQ z`1KmQPXOM<$LpB&NC2x#|K!f6>KLLjo1 z1yy+#^OHmTb@F3@tle&BwOioZDQeo!z==p*B4SPxs4hON)k= z=5pi88aw;0laK`tdBbeuKU_GdTMA+Tv4;XBbfQQLmbFa9>0WHmkwE6}{lp&Owgh^* z%-1h}h(nCdY5|A#I0R9siPM#Ep8M!=FjvbPX0{-DD!F!pwN$`sL@sd15u|p0?6c0; zQ1ssIcs@lJf|KazDU6+@2r7AJej#TesN4u~9+~Bem^)mhVu)i0LD;5HJXIdNG~7=e z3~W5nV43XkB#K67!T6%9!e6|!Rxq~>+bk@yNW3E6oha8C1Ym`7tSc3uP^?ayl~w6= zMI8sWA=1JxcH>m;_Nn(QHtV?>8+1y%7(thX9VkxQj~+d={C7j$nGgDX%5R+1r5c_Q zkPrs*R%IliH?vXM+F&74HpOzw@y_t9zRbL1Mz9qDGuHl1kLn|diUgyqrD=qSX=8)l zrkh6S<^R0{qb(F_JG_DYfv!%_{qfV=c@_AQocp0xSy8mjf1oR23>h9@*}`*&jjaxc zOUMKT5bB8mx)6`Hd}q1z>Wol}KSM^BXm1KDjeB7|u2NAO^&9(%YvZgLc$8TuIx*u) zs#>Gf?Qg8nj;1@q;3N;lbY}k1UkNSG2gxHXXkY&*RUjSkH-IabNZ>5pNRqChf^IbK zPNx-OkW74gS88F4Hci{zIiy-h)BHpHSYz*yU>X)xTfV(HO>aOL7~}F*{6@xAe?L7B zX0m@d<}slw>rIZ3>fjiRc0Yj;HT+o-rRW{PND_xtH8(FUW)QVu$bQs<($OW(vsoLI zZEM#4>KVFwUZEi%sBY!^4G#L$j=VE`wU!@HCHoM;forqbTFwXCa4*iUaC7Ruxj7jo zgj)>PEKex4)+K6|d3iB1`^Rqdj)@wOgAYB?(OH%&&lemQP` z+~LHMd}ng)hqwA#cFO}mLW z6ap$JbF}NI?yJK1ykTYtEGEQT$^>6_3EcX0+U&_03c3L?bwa{;(4!{b^OnRc-~?k< zWQZLurK*y%+}<4ffvlic-})&Q^--a0$qmFl8sV>nJiX#Zo`3F8x(jF#{-s* zSbeQL4@ldD{IBKr$>(_a=U&5Nfu(h4tRci0`7qfm@0Mkr`Fb&f;L6MM;P<~%70-EYEKJ_PPd>kYcgush|VP`9>5SR1jxk!0Jly8>W36z+{xg|25o6rBJYaBfOkAz0OQKb)fo=_3C0M)4>W&r?)ytwt zDAo3S=J@?1i>c+c%s5A2|4?1{Pjtwhg%iC3K{+HPoO|y?TVq{C+ZyjBHRZ;mRllSU zod^|?Ww@w=WGoFjya;qje)i6cwtBOdn{bdCA|bbxYzoL3M;+nLFXyY#e~)R^ zcrzVa^Ra!@LZqqG?ux}bT59jD8ZG?7JNwU~P-;owrsJON;pP%h$KI;e2z1syoU(7j zyz@75^2YhkFpi=0u9t+7_?H(vZEC5N?d&jV_t94y(qtqi}N`SHz=KowZRd1@k(R&66K7Jayd#x$E zEZb%kpjlm!zl5*~s^x4X%LgR^Zl@YI-Z^=XIWY=slFhfl$$GJy6G5 zh@d4Q)FBjigY%{u!0D`7mu%<_;A3x|3m@|Y#HKVuvd#&2zw>)js1U!Y!R(a~#QKKC zD-HGRg$9SozO-V}5_lK)5QJBhB7jqD^67<WL@-tAis z-P>kM;qa3{!Xay>H~`L5SWUTq4-Ck!x?gYf?{#{~GqAppzA48i!tGMpnoE&(Y$SlRO^IYZ@_oYh)RnH& zfYf(`fdZ{j4RkU2ZCN|?CeyQp5`U4COW1%Hrdx7I?)*nTytS(?PHmTJ9b%#|L08*# zj8^!12*qgfv@g^g_>_*^ED_mR6BBt{5gfpq*5vsZe%SrkBw_v{U7w5-vK;gXfep3I zy`UcYWVmqDn;U73?LUC{WC5n?hna)P%fj*eaR>EN9JPx_D8(CF$;c?!n9{;XbfDak^& zm*{ep665Mnn=|#e9hvst2J;ot^dS!##Bgv@UQ9r7m#Uhno5v2Qxd!8qTC{d&-e+lP zO~%C;9kS+S1Psev5uuekwvAx1;52(D5|%%Hsv-Q9A%fFPe1FlVbRk9Qzl2hTnYFx= za3Gx&+znzr^k5k~?Kb|pV^v#r&4kBf-mlL;S%B!e40v0r_I%PGKn4L(%6GtMr)gyk zl~nl9#DVzELSw5j`v3Wm0gcB}(!9>3gUcsv0}z4XO0}Rn_sxg-S6e-h{}@R#T9)xU|O(_B1z z)6^?xnoJVtW^T)BKSim$YEh7_MyF~|EH)Igbx0vQXqb0y@NcJG^ zB&LJ@bEkA5W1W4Ig{N^O|DNBWHgBb@GJw$h?#Ifi@R4ZmNJqmy88CT}ymKKpAZxab zc1{(MmCRP>2XU5AY3m!X`L@PWq3zWvOV_m&j4cle`6eW?FmPZHAZqs%_g4bi{O_lc z?F`@tiyv*`4Jia$?-{T`c3I5w*sj8T_`&%Gqzx%cypu(p#hn$B`>+Bqu1RdBK5q1P z`U(Y9d!VzaH81GLh~JadTpG6s7nkD;kng{_RS4uhR#lkf?Agl zJ@TkidzCja<$bGOw%;bJKQ|F*ed8yP@S_SL|0?m2;5z8e{bPEeeX?eD;1BbFD!Pu$ zTmjV5|AZ_0VB(XiT~6qL7pQC&j`q#LiVjnn2ECIfP;M|LrPPI{(l2$oX{lz7S!bvd z9*Q=oWcEAvMuHu_tCPF(PonN30pv2qL`&)p%p#{cwaQ&>$8S9e56Kym&Opyb#lXma z)RHsN2_v?Mp+ouYHHBmyRTcl0F*C;2I9z=iSJV=MxIa`Op)>aP6>Y%NTZ!M2;RFt+ z_e!MYEZahr8dHgmakqT31D=%Gz$3eZK86}Ebi0wg;&!39}}#*>s{;{ z<@DT)QbxJL{$%OGcO6I$4$UU;5JZpZVXgDAa=13&gC~oTH$52uV08R>h%izC1 zpSahxe3iyPbd!ExKNuNW%|R%ZtVulFgR*{^W#j?CGkI)|W3uQXqU&(f&S{jqZr(PHf&k_HA+CjsOQTqAe z#Aa`z$K=-}DzVc9N{+u}gV{h3!+tfQ3sV+)b^>rV7ze1LvCYAs>0lol3M0W)ld$#% z5_$|7!W-pU@=~3>QPC|3Hx;S$TmWDJ%n|4&c?2La2dmQi3K?9jI`{k_tswXAFdz?% zuv3O*$U;V$1!{AZZgxsk)u9aj<)B{>&!V!xt;#1N&#xwDbA@3m?+B6?yh>#NVh$b z)%AkP*K#DZUudYJ#=b5Z9-^C*OTtb4)0j+)OD1iR$IYJc)jknP>oIqy<5UgawhAR$ z2uGv~GYa}7iQ-;y;HAO&peyPzwp@E91zn+n<{w3RQE@WrYF2!v)Z0t`>faG01nr@Z zS@;~p7nS85Ve?Q5UJA~2J*VP#{m-#BrTg^8^Bs8KbF3UC47 z9l=eB#Nr1E=LF$Wp;+>nUXi7Z>euB|2-BwK{wCi#ZhV&`xNaMz)#S$E^w#x^PLh9n z>PXOL3m3o(mlIJgJzcSjb2}>~Z%4%vgHA{oJ1M&^Z|@4wqCKN)XE;E;HKK<-e8oWm; ze3Vg#k#7;uNnkVheLP0AAz5RU+`Vivl42Tu6=EfvXOt9C4zUpF`ix9UvibC20mImFV))F4heRuP1Fv}xPBz>ud(lG z%}SCir|g9eSjW7bW#!v=c9;ly{R@9iQgEXJei?ZM4DWI_U>eIc_Vla5yzq?X0aWWoqtNDG|Gl@YAFGedukprtg}4-PdzD>WD*3elBC3Bn@CPz++~s z{^HXMOnegX1!W0qChIcTrzR5IHt*f^yE%cb3w%6Yh$66~nm_D-n9oky@=s#ue6Ke! zasfOk3H>9D^6&%GL(=k1!E9evH9ILldYcK2dZ6CM^hVwcpV|;+(yO*|X+Swe9K6Sy z$kmSwODFsMN2oyK-K^>GZq;r@V9SGIE&M1#lQN5qmAj7{^gyP>93CDwR z%N9sG5+@#F%Rr&*3T1_R}&}$U=6S zPAgMFRx#=VkXzpdmjv^k1?U5UAgtkn%zQ`z#he3(UYCrE1|U{ER*~F%!1j+-fvUWn z&M;>??{8~FXcO#YMWG4&9(f;F^2qGp7VH6GlLrJ!ab|tubC);< zKur@q{y{ym0bU8Z_&d!XlN#w;=y<$AxBH@!j35+3K%sxUxrGycn+ zB*3dpp7(J|EEi&=G~rF69*U=x`BD1znLlL>J|D=b8pU~?q|omw=@=jlZ$>}FP1)jW zJxw?4BX@M$0~dK&GFS}=rhZWwqJbLa;PP=F1Qcm_Rc_|S6D+qZS1Uf3ULkX5m->X! zdBOB8B+2cMjQ;d^s&^pLG8SEI6*r;{x*DF$=cgE;28GK!7x^5+od9jv`Y>&(jawaS z-a|Jq0r5ZWEyx2BlT2YH<~3TbE{Y`I9l1b#GZTp}R%_p!DyZ z0l78;EAtOYDrU8D?c2G&y{4hKZ`f6ke#+~Hwbd~_MV;52T26@Fr44W!)Y$GGy;z{vb7 zl-_BuT8!;DzO5?QQ{}l9IKWC@?5+@wU!4@yBTKk{6ekmh9SkI_U=f6_k})gR#J+U}8mm7KOrFsM}wn`nBvC;#iYIGo$T5f&qk!^FZp`C0A z7%*ZtNu%3$v<_b~{l0U$3kF0CZeOz`RhQ0%Jh!#^RaOQLICKVDd3z$PLH% z=ploUw7m>?hr4$_5CeMtBn&JbTVmOIakth1#KQ~hh$nhU>h(( zdak|DzGIuYnZLT}pdQ(}5B`6il1f9;5<7}xACCC8>$Q=-0pN|wfTq_rzFoSdFF)GKK-o7PCRgHj*7l6;T0+93R@pTf)E3q`@nk)C^Ibv@j(&?8hIIoXy&R(lMj0C2FmFRs{A#!ZOW-? zSHZ+eRX+>5PwM#=IQJt8lo~Si3m!wNj4ILL}#`Rp9%)Boqr|3 zota=cvU0{5sRf*ddL4J#(%Pr@LDPx2vzj&RGEZI|t{XI|TOAw5lu?0oUv(TewbtoN z?UpfIfve$~*xj%!#KzbZ+q@{KZyW?>#Qn<2XBnge0oig){kzoYI2*|Q<^DI_s)j^p z6HtBWb~TQZ0MGKQC{5N1QD(o?%qG+NcJjxoIJJ+n4-^j3m}@7 z(MbDJ%bL&idDi71Ouv3QCMpx%;r`st)9l5o(+5RkT-Dyc%eX(p>t-U+Ub7@&{5Qm{ z+zM*g)@L1#H4_Xy>=`{Jbkld3wtsDme@yEVjw{xS$(ND3K74L*FTkag<_IQ{3{}Ly za+Ye#=P!b|9}ug5v+i?GpCP)h7WC17B-qniHae=BmhE43lOGULmU)lRTOgAD>M>_W zR~u$}kZJSq{L-?X5Sp7czd2DLF*((J&gHP^17fTkR~tYL&If61QG`uKN}96ovjgz} zW(OQn`R8xIJN#G^9eZwH)ZM=p&2>lcHV@AmFcP5hY_NGyuFbPVO3P>+SxmO3ay~Pm ztG)$X`QF|Athr(MGa>aXJK-M~Rn=u3eb!>?ax5wnay?VT*O% zAVGl=2O`xPDc1(u2|^dvm{z^B2jm66oWe0&El;HTt3BuS@r zkB@$HLee!fddvfwnKw#XgLf+o`fB&fC?`cs^PnFk*qjT6WE!&PhmJ7B-ut)D$m~B= z^xPxiqf+f~L$#7kUnyhgHGtsXlQLK^bj{WbBiAgM%IpjbdC6fMBuq}m@cM{=LFU@i z8W)8NQJKJ50AM=rAnthpb-)&B(o)#-B(WDVNH(aVZ_;wm={}iKlmzir@zuFvRm>*Sz-nS20>2MwW z>P=X!QL~X|GGt@1RZQej)<=yadG;_y3S!*Ep7g@_lj~A>I?=C}wzsOTI2}Ncwr9+; zu3?ya8T61Ps5;RhU~fQ7_ECwx* zD4Uai^S##Ka?8Ui?Yw~0Eh%ctK};p;?Q2`TykC08Td^ZAdp>a*m&5Z-dL{Q6DS=KA zumALTfWPM@O3ENaU`v4)<-|x>V><3sHP&IvGqHFk#50L+p{^@;XGc^j2-pFXte7q- zTG5vSM5jHzYk<=uloetdT`~fn-Csp854eIrwxaZs$+qFlYT;b5I3kYw2qw)WZ2vWP zJ+kF}flzl|ioyEw=z*(OZqmpdWFvbhFD|Eu8)-XGW96nlrki*l&)#3HQrC-Ul;TN#V{1s5ca29ags`d6 z&3_yzH?{Q&Zk%TmyZ?mO+cgZ|4SM8Xfc|XgM!pk()i1|j`!z2k!S{Y&&v8g^;qxjb z+!-(3w8FVk#ME8!*CfTN;mEyPT+cViDJ^;$@HRSr%XW{dUhdE`ZarZ?gG32^RVZbx zDzzowFKcVi0z{niU-)W_nR-D2Z(+9gzj4-bXi}oiau0J^-gxytZBRn`Ew?j)qF!)a z3@^JTo26snD2sm-!x@W1H@(Re+3ZcuN9RM$jQTY)x*heeRjNORN7(tTJLLqIF}xZO zHKx&=5t31#nESs9NA^{|nk9UQkQ6M&OON%yHhv0&u`Z&2Qx2`G+ND ze%vL>Y#!d+nqK~VFMYXbp`(M^ywEzCnSeeVFT;!f-_JxCB);XIDaZp(W7Zdm26IHcK=gGI*ZR-$a<7bTsS?(#Q2f2(7_Wm4Y$B= zG~u!mUuqfNWyyt31$TZv&rV>+H)tmN@+zV%J&YspWd%0{d&ZDFOamAuR|so+S1>@h z*UAT3-u{%J<>j9zr_6AR;NKEB+af(cyhU6CmR_cn34I&cY${&$-d8NuTJ6qV5JDqw z67ic?!kHWH!?xRSKmX`k0v2MmUw0d~#JVvHGifesp)bJ$_oJ7plX43&9452Do?620 zK^*b&BU}9Z4XYFs5{*sv1_-b!wb*!Qlob*(TpFl!M6M9fUP6ycogQ+l0iMf^$S zcl6wsXl%mMPWpz17Cra=#inff(FUqW_d0Q(st05y4Q(297*4lv*t# z7pee)4bJp&Y*QN&M`xicoh#&Gi08!a0@~G-2pinID&@*M4L&&fgu9HKdUqBGlJaV^ z&VCz3*CNQTKaBo*fimC^ZvcjnsYcm4t4R6dwxv7cv2(ST5&+40Hz^Z#9Esd$akfEa zvCHLui4mEo{p6}er3-8R*1*gmB5d0}Xeq5*A`IOw>>3P}fIUe^8P^$_L*qAPFwS%D zI#zc6ezUas>?Mc8XSIk>=6(68o1&OawJ)Z6dVZymY%ySwt>z}CvX@&j{H3xVcHMY? zTr1kQS@YWoVAP4yR32zvGR@sCQPN<>#REVj+%~XN8S0O5sCI|u2%A4}b3>mCMW)TT2(*`9jJSFk9{*k3!zT`S!|sT{0xJtpC{Q;p8^7$1LR4V$jzdtQ)^s zF1g&LdokbS@p$fB(jc_-AcCT@tOn0I!(vs9gOi9<47+r*vR$}-g+7jS;a)s-=Z;(= z+m!Y7>ULLqWo5`;q(1ANQ}>~f?#G;`v(V9`Fcmg{SXW7#nae0X9)BD{)D0ic&E1dn zrN#PPYVQRLH_I}9UhBq1cC#l4oYE#H2JYr^&m{SByQH>8XVg4l&7!B1V@Wuv-S5xe zPjyl>?=XSeU7PQK&nwK-NGU>Jst!g8fJ|Wv5Ao|#xVW}vBuJXthw|!}VggH2x`ibn zYmLn?A?&HbXa+YK;-~Nhk-ZRaD~dcr`M)^#oh_2E4AWC)xi@^#dc-7{`XO|}N+_K1 zgk-f4qOMe)X+U4yeDgPvpoL2HQz#t*-^~>%cqwly0vk}_7jKk4msYewIL5d-^o=*j z3+#nZMp$>z>WXHsS|p|lUaL)GqGc?vyELCz^^{e~+>G%dEPhq-_EyORt0KCAjim;U zbuVc>9BAhE&Gd-wm&6f!jt&lpT*hLi!@bosltbY4XuYB7tv%y6wfgKmWSmLG4Q_Rc z0(xz@E3sKxc`%&&-5e(*E%JQIynu^?C)_m|fk6H%PT&IV1M1q9^92zb?*ba+a1S`lRV(PjrfAu;G-wedr-kb}_ zK2h9TT_`nR`YB`67o9&fq%-a>pnz297#dJPcjyU<%iWMAWs9+z!3cw&>|EYox;)i; zb=iTkK-|?*yzNh2c-hv-F&LY*cUTw-8~=THEn0eJO1i?5!9#ZKz8c$IeQP#fLlg;*EEkL@fPzpRaZ8Goh6d@5}eO2ILub**>eb|3*zEzWee+5kI<3;zRMy=1E3vr zr2VKT0l7bRA|E4SL;-~$j@5>1nnkey9A|@k0CW&cZ?6x5>Di!G@{kW8C5c~1D3w8?kC=)s?umd|YEM`A&a$I5BM#sh51#^Cy|c2jogDIXv*b1N z@BHRIHH}Z$#HGTN{{2(bSd(Us>gTPaWJ{49IRyY&5n@f(uIc*KE2ZEFDE>uE9o0 z-K|_ub<`F82RS?13%vi_8mSgyNBqHbhu6886SG?KGYcJNACyTRrzBQ_(VfupbKF8z z0V0+CQSHUMyHHA7{PypP`RvtGGi)HhdZpr0# zrcB($70SaP+|@k*wjQ^9E(LN%(yM_QYO)@p*sfxX`OEekH;`Gp|W7vtzAnD zr$eu+%l)JoJ~;B)~SC=pv|EFcNBhy zf|p8`ryx>e9QnVV`2?IY48`-X(+Z$8nvzF++lau2X=3Vt%|@%T^AnvIP>h{E)K1&B zaCY)R{wrpAP?LPd5YRUDGN8UG?y8#dKruJ6KboNDy<_*4nxAV#XfZTjxq*YY-&V(2&ZRMm;!+^E0 z3dlT9%18PNGW+zO0t_o65+_zXO%sF95HT-hiy&bL|NPOH>}uLhADwSXNT=2h;(46K z;1L!(EjA1YX}H=nlZW?+;Pg8Qsg?@*8~>v~!g8OY^1!H_uAMrY$_!pS>5O9f;n!tS z|3O7IunF^KzAFzr(dO0U^wcWfL zJ-7AH55k)TYsekAeqbE&k`Kgy6ROl?xF7`lkDDKB2b0}q zT)Oi3VkPk{vccK%RIG;sHSPj!KLEaI#s!MxsE6^%{|P^%zqqcNmF2~{4BOT4zfY$C zc50U61DIV#r&+5y!G;s!b8qT{SN@1_8W_!gCYtD&&3UX1tGZ6 zpVDI$Tjzx86;goS&r{ol4`%w32;SR9%Z3G6X^kAeX!=m|B3f%(ReMjy(93cyBxKSX z{AgWhxI$fs&aTIyS6d1lu`TsAG0uAb*4}Kyzxf)wPW_{SLkCDcTq?9o1M@3OAa)B+ z+*3z7@+>rGiD2qsU7Ke-;sP=1_(HAK$d8Ceb+d%JrLw@8bc=-z?-<1Ov|9=$xx+x(6k zPm{k-Q{sk^IK64h&vp3jFP9l56G%DXb=C|$tjheRfu1?OfIB&|{bnHH5}}k-Pw7{P_(}3=N=|m)mRPv>9QZf za8{KZ{|F$=_QB=9d?A;)L%bsFaQM7T-*Vq@4o)9XeW}3L>`&?XDqQP{s@)9X%c2&t zm)>zv>iXK>diCIv^}J&$0U?Y^?r4O#zP~%(2AdD?kU`pgjvBUsT>Xn-wSq1(>%bf1S2Znb0?-k^`-L!vLx&ZK?6mAJ<0pu5~ET)oJ9#lZtv2icYLk$Gh3 z=a4UwouFLr*o#6*s_t1epzx9|my!H`X%6Tn0XP@Hv(52?nXLL(p3|?^T<6gG(>oL^ ze$o+v<1a#vcPu+SppY8toG+J19EdC%=ueKs#~2PVt*P)L+f>3ZLl64tM-<+x@SXLC zpv?Ix)~K2x1q}&~9EKKlo#Q!UT@A{vV?3y=s_% zn7Ts~3ilse`c>#otD7WAa)+xDZUZ6p>_xHz{L^Fj`_ljM4{GffL3|(IOgchP1BNDci#W%pm5~07w)Kfkkp1d=z?o zdO(VtxuGMwtYz7kEIo0-iZF{3>)&6QR6|3^5l%~dYj1DT>FjKc(|dHTcxdq-`6MJv zM9IGl5VrK7c$ke`u2bYeX7}wFCN;-1ygT>09JQ5}bn~IeEWmB1aN)|}zBb-kt=~5dAHg}>Ho9poocsnHQ*tcknykj~c)@w=NwE^u068XAh zC2D)BppDmQgWeuh17ml+RH&Y8d@uG&$P3ZixUl&{hc7Ou#bgm(Q202ZE{m67i1sT& zMl2cAxq$aNyfU_n&P@2S9yi`r3rHANG8{ZSNzvbO`gh{OhQCI?^G^_(-I?W6t(fcM z`Bjnp&)I2p)$uf;3_i{yK4N`J;HdR-ig2rZANPmrOP4Q>^Z1YKnI0C7XeYZVNs*V-cDL&ma z(VjbQ9c$@Y5AV0gFuiwn)>^Vw>LD>k=tlhXqQKfKWa!RvrGi>2&q)0Esvg{kg15^K zapje(BtGEx2vfupt6hlQY&76$+a>lFbH%xty^wBd7E_%-ZmUq&9JU}dYA!o_oV`C( z;%6!LLtgnXFhrBc7KkMM)N8(1i&eav_dIw<8%R7Me{fA{g?{3xRt^Le?d4me%seqR z=y2VU%pM8-aO~820-_pQZ9%8vhO5XkJ<@v8x>iM0O+FfyJo*Fho`}*)H&?N^qHk$f zRNR^ExJV(2?PloIx+gJ{&(iKCQ%n zlCBY^MTCb0;9#JSZhF)?kno&{i-xba*+;dbQ&U-l!2FST31}O5Zz_#g?)A?(^|x`f zYf0Sq-8CdKMcfVqT@$DE?1-y|(>}HboH2?hP;tTjr}BO zuVLOkB4_EE#e2IdDU$w4rpS`Mc1Up_9Tb{oa}xt=P!5k7qJ&Z7yS%BM_V}P8Z$(!_eC4HV))jS%VE6)tyGg zRQ0!}D8>dpEZG2CqTX3_)fT0B*;G>XXcEb`S{oOI!-5+`LoL#hvYxI&j3)ap*Qn%T zdEBS>6gUC%%oz!InJ>|aj^MIfESPCca=h@gDgEL~RzWzAprmD+c+w2@P)=;$b0ayN zCmGA{U7{Q4zm3XLknf26R;ov*aFl90qC(*7uZ}h56?8OeInhgNy7638tc=&fW-4f zh*L}a`N9n56T6zWPz=)>(_B=FqF?j% zsGOPA+`qhqJs6eGj?i}7vHM>pz46UeS%ym?V)puCbmllmivQ4tI(_q=fXQLoh;^ls zLlu&Q2!{meW$-b=@RmSJ#6XbX+(K^$C5_8F^K-XJqH5?pd`}OXp;Q(1k7C402UH6C zTWR(`eeDpBq9yKeF9@KVY7#DZ>&*q{hh)s