From 42f1c861299097eaf4b6a988980fb2d1f04f1dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Monta=C3=B1es=20Ojados?= Date: Tue, 6 Jan 2026 16:15:35 +0100 Subject: [PATCH] fix offset mask logic --- Class1.cs | 164 +++++++++++++++--- Textures.cs | 2 +- .../net472/StrategicView-Plus.AssemblyInfo.cs | 2 +- ...trategicView-Plus.AssemblyInfoInputs.cache | 2 +- ...tegicView-Plus.csproj.FileListAbsolute.txt | 6 +- obj/Debug/net472/StrategicView-Plus.dll | Bin 13312 -> 14336 bytes obj/Debug/net472/StrategicView-Plus.pdb | Bin 11988 -> 12672 bytes 7 files changed, 144 insertions(+), 32 deletions(-) diff --git a/Class1.cs b/Class1.cs index 2eca2b0..39aa031 100644 --- a/Class1.cs +++ b/Class1.cs @@ -12,11 +12,13 @@ namespace StrategicMapPlus [BepInPlugin("com.mod.strategicmapplus", "Strategic Map Plus", "28.0.0")] public class StrategicMapMod : BaseUnityPlugin { + public static bool GlobalShowToggle = false; private float timer = 0f; private float interval = 0.5f; private bool texturesLoaded = false; public static Dictionary SpriteCache = new Dictionary(); + public static Dictionary RawTextureCache = new Dictionary(); private HashSet reportedMissingKeys = new HashSet(); void Awake() @@ -26,6 +28,12 @@ namespace StrategicMapPlus void Update() { + // Toggle con Ctrl + V + if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.V)) + { + GlobalShowToggle = !GlobalShowToggle; + } + if (!texturesLoaded && Time.time > 3f) LoadTextures(); timer += Time.deltaTime; @@ -58,6 +66,8 @@ namespace StrategicMapPlus if (textureLookup.ContainsKey(texName)) { Texture2D tex = textureLookup[texName]; + RawTextureCache[logicKey] = tex; // Guardamos la original para Debug + Textures.IconOffset offset = null; if (Textures.IconsOffsets.ContainsKey(logicKey)) offset = Textures.IconsOffsets[logicKey]; @@ -166,7 +176,8 @@ namespace StrategicMapPlus if (SpriteCache.ContainsKey(generatedKey)) { - visualizer.ShowIcon(SpriteCache[generatedKey]); + Texture2D raw = RawTextureCache.ContainsKey(generatedKey) ? RawTextureCache[generatedKey] : null; + visualizer.ShowIcon(SpriteCache[generatedKey], raw); } else { @@ -203,39 +214,75 @@ namespace StrategicMapPlus Texture2D newTexture = new Texture2D(originalTexture.width, originalTexture.height); newTexture.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0); - // 5. MODIFICAR LOS PÍXELES (Aquí ocurre la magia) - Color[] pixels = newTexture.GetPixels(); + // 5. MODIFICAR LOS PÍXELES (Lógica de Re-muestreo / Resampling) + // En lugar de mover la máscara, dejamos la máscara fija en el centro y movemos la textura (Source). + // Esto permite hacer CLAMP (repetir bordes) para evitar cortes rectos. + + Color[] sourcePixels = newTexture.GetPixels(); // Píxeles originales (Source) + Color[] finalPixels = new Color[sourcePixels.Length]; // Píxeles destino (Destination) + float width = newTexture.width; float height = newTexture.height; Vector2 center = new Vector2(width / 2f, height / 2f); - float radius = (Mathf.Min(width, height) / 2f); // Radio máximo + + // Configuración por defecto + float maskRadius = (Mathf.Min(width, height) / 2f); + float shiftX = 0f; + float shiftY = 0f; if (offset != null) { - center += new Vector2(offset.x, offset.y); - if (offset.size > 0) radius = offset.size / 2f; - } + // Size: Escala de la máscara (1.0 = toca bordes) + if (offset.size > 0) maskRadius *= offset.size; - for (int i = 0; i < pixels.Length; i++) + // Offset: Desplazamiento del CONTENIDO (UV Shift) + // Si Offset X > 0 (positivo), queremos ver lo que hay a la derecha, + // por tanto "desplazamos la textura hacia la izquierda" (sumamos al índice de lectura). + shiftX = offset.x * width; + shiftY = offset.y * height; + } else { - // --- Opción A: Máscara Redonda (Matemática) --- - int x = i % newTexture.width; - int y = i / newTexture.width; - float dist = Vector2.Distance(new Vector2(x, y), center); + // Default + offset = new Textures.IconOffset(0.07f, 0, 0.9f); - if (dist > radius) - { - pixels[i] = Color.clear; // Hacemos transparente lo que esté fuera del círculo - } - - // --- Opción B: Quitar el negro (Si prefieres por color) --- - // if (pixels[i].r < 0.1f && pixels[i].g < 0.1f && pixels[i].b < 0.1f) - // { - // pixels[i] = Color.clear; - // } + if (offset.size > 0) maskRadius *= offset.size; + shiftX = offset.x * width; + shiftY = offset.y * height; } - newTexture.SetPixels(pixels); + int w = (int)width; + int h = (int)height; + + for (int i = 0; i < finalPixels.Length; i++) + { + int x = i % w; + int y = i / w; + + // 1. MÁSCARA (Siempre centrada en el output) + float dist = Vector2.Distance(new Vector2(x, y), center); + if (dist > maskRadius) + { + finalPixels[i] = Color.clear; + continue; + } + + // 2. MUESTREO (Sampling) con Offset + // Calculamos qué píxel de la textura original corresponde a esta posición (x,y) + int srcX = (int)(x + shiftX); + int srcY = (int)(y + shiftY); + + // 3. CLAMP (Repetir bordes) + // Si nos salimos de la textura, repetimos el último píxel válido. + // Esto evita el "corte recto" transparente (siempre que el borde tenga color). + srcX = Mathf.Clamp(srcX, 0, w - 1); + srcY = Mathf.Clamp(srcY, 0, h - 1); + + // Leemos del array original + int srcIndex = srcY * w + srcX; + finalPixels[i] = sourcePixels[srcIndex]; + } + + newTexture.SetPixels(finalPixels); newTexture.Apply(); // 6. Limpieza @@ -255,15 +302,71 @@ namespace StrategicMapPlus private bool isInitialized = false; private bool hasContent = false; + // --- ZONA DEBUG EN INSPECTOR --- + public bool DebugMode = false; + public float DebugOffsetX = 0f; + public float DebugOffsetY = 0f; + public float DebugSize = 1f; + + private Texture2D _rawTexture; // La textura original sin recortar + private Texture2D _generatedDebugTex; // Para limpiar memoria + private Sprite _defaultSprite; // Sprite original para restaurar + private float _lastX, _lastY, _lastSize; + private bool _lastDebugMode; + void Update() { if (!isInitialized || displayObj == null) return; - bool shouldShow = hasContent && Input.GetKey(KeyCode.V); + // Lógica de visualización (V o Ctrl+V) + bool shouldShow = hasContent && (StrategicMapMod.GlobalShowToggle || Input.GetKey(KeyCode.V)); if (displayObj.activeSelf != shouldShow) { displayObj.SetActive(shouldShow); } + + // Lógica de DEBUG en tiempo real + if (_rawTexture != null) + { + // Si activamos el modo debug, forzamos actualización + if (DebugMode && !_lastDebugMode) + { + _lastDebugMode = true; + UpdateDebugTexture(); + } + else if (!DebugMode && _lastDebugMode) + { + _lastDebugMode = false; + // AL SALIR DEL DEBUG: Restaurar el sprite original + if (iconImage != null && _defaultSprite != null) iconImage.sprite = _defaultSprite; + } + + if (DebugMode) + { + if (_lastX != DebugOffsetX || _lastY != DebugOffsetY || _lastSize != DebugSize) + { + UpdateDebugTexture(); + } + } + } + } + + private void UpdateDebugTexture() + { + _lastX = DebugOffsetX; + _lastY = DebugOffsetY; + _lastSize = DebugSize; + + if (_generatedDebugTex != null) Destroy(_generatedDebugTex); + + var debugOffset = new Textures.IconOffset(DebugOffsetX, DebugOffsetY, DebugSize); + _generatedDebugTex = StrategicMapMod.MakeTextureTransparent(_rawTexture, debugOffset); + + if (_generatedDebugTex != null) + { + Sprite debugSprite = Sprite.Create(_generatedDebugTex, new Rect(0, 0, _generatedDebugTex.width, _generatedDebugTex.height), new Vector2(0.5f, 0.5f)); + if (iconImage != null) iconImage.sprite = debugSprite; + } } public void Initialize() @@ -325,17 +428,26 @@ namespace StrategicMapPlus if (displayObj != null && displayObj.activeSelf) displayObj.SetActive(false); } - public void ShowIcon(Sprite s) + public void ShowIcon(Sprite s, Texture2D raw = null) { if (!isInitialized) Initialize(); if (!isInitialized) return; + // Guardamos la referencia raw para el debug + _rawTexture = raw; + _defaultSprite = s; // Guardamos el sprite base + // Aseguramos orden de dibujado (Encima de todo) displayObj.transform.SetAsLastSibling(); if (s != null) { - iconImage.sprite = s; + // Solo sobreescribimos visualmente si NO estamos en modo debug + if (!DebugMode) + { + iconImage.sprite = s; + } + iconImage.enabled = true; if (debugText != null) debugText.text = ""; hasContent = true; diff --git a/Textures.cs b/Textures.cs index 0f0aa45..76be280 100644 --- a/Textures.cs +++ b/Textures.cs @@ -39,7 +39,7 @@ namespace StrategicMapPlus }; // ----------------------------------------------------------------------- - static public Dictionary IconsOffsets = new Dictionary() { }; + static public Dictionary IconsOffsets = new Dictionary() {}; public class IconOffset { diff --git a/obj/Debug/net472/StrategicView-Plus.AssemblyInfo.cs b/obj/Debug/net472/StrategicView-Plus.AssemblyInfo.cs index 640548f..e775571 100644 --- a/obj/Debug/net472/StrategicView-Plus.AssemblyInfo.cs +++ b/obj/Debug/net472/StrategicView-Plus.AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("StrategicView-Plus")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9153fd763e579199d54cab0a432ff9090b4c64e9")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+7e598d765a951b2ed1dffae0db08efa1368fa39a")] [assembly: System.Reflection.AssemblyProductAttribute("StrategicView-Plus")] [assembly: System.Reflection.AssemblyTitleAttribute("StrategicView-Plus")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/obj/Debug/net472/StrategicView-Plus.AssemblyInfoInputs.cache b/obj/Debug/net472/StrategicView-Plus.AssemblyInfoInputs.cache index 688dc93..7e2b257 100644 --- a/obj/Debug/net472/StrategicView-Plus.AssemblyInfoInputs.cache +++ b/obj/Debug/net472/StrategicView-Plus.AssemblyInfoInputs.cache @@ -1 +1 @@ -32d9cb21f9105a306e788f865867ce1cabf7e1239b4f80ba170e98b961bae87f +90f7195f387189c7972462dcdf91a73885ae72597aaaeff424f4540350fd7c06 diff --git a/obj/Debug/net472/StrategicView-Plus.csproj.FileListAbsolute.txt b/obj/Debug/net472/StrategicView-Plus.csproj.FileListAbsolute.txt index 9ec2cbe..789b65a 100644 --- a/obj/Debug/net472/StrategicView-Plus.csproj.FileListAbsolute.txt +++ b/obj/Debug/net472/StrategicView-Plus.csproj.FileListAbsolute.txt @@ -11,20 +11,21 @@ D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472 D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Unity.TextMeshPro.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.CoreModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.dll +D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.InputLegacyModule.dll +D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.InputModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.UI.dll +D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.UIModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Utils.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Mono.Cecil.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\MonoMod.Utils.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\MonoMod.RuntimeDetour.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Google.Protobuf.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.UnityWebRequestModule.dll -D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.UIModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.GameCenterModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Zxcvbn.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Facepunch.Steamworks.Win64.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.UnityWebRequestTextureModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.AnimationModule.dll -D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.InputLegacyModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.TextRenderingModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.JSONSerializeModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.IMGUIModule.dll @@ -96,7 +97,6 @@ D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472 D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.WindModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.XRModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.ARModule.dll -D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\UnityEngine.InputModule.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\InAppPurchasing-Claims.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\prefs.dll D:\Downloads\Unity Modding\StrategicMap-Plus\StrategicView-Plus\bin\Debug\net472\Unity.Timeline.dll diff --git a/obj/Debug/net472/StrategicView-Plus.dll b/obj/Debug/net472/StrategicView-Plus.dll index 7d282c7b677f637f202dd49450682fc9fbfbf6d4..e0ef101dc304a066050c2ff149abcc77e64f8d37 100644 GIT binary patch literal 14336 zcmeHOeRLevb-!GaX--=>CkY{KXlO{&B;^2UXiAzUp*e8!dD=A1Ns|=Q z-+eQyUD@f6TSO~5>rmrO4rs_UF@?S z+)cDs1n7O8?$=7vzDH{l)uN3E|B>cluilUE1U@J6A*z#Y#nYP+J{i&d=m5`8fKJ}Z zr2Jp`+wU?8&oB28F>B`g4R*x&&jL{maQ{0%G<^QpoAnb!dd0Yo{+^0{x@es(qCdC^ z0AtctUvKo}lYmxfx8RPUCv`iC1~1fRd@7z@Sgy2dTH-&=K+m0A$CKBfpzRmtVQj*Z2$_0aIrxq>R7;6jAy_gS_L5a=yN=7iyT9arm zwNv5Mr<2QoY!UG)Ewzkp!iX9_Cl>gdlsTBKwnmaz$*Q$5ch@-ul+~eBNJ(PVG*Xl~ zSga-u5FDB3riW1GFsz7AtRKkD`7FX z9C)Z=sEtQrs-cEIXm5TXUPCtluR1F*7}GnS0zp(yuH;^rqTyr{x2n*<0#(JTLq@ga zAFDBHx<1U7F=iEy)!u}JP>m|1*0~6Ms*go(0#{(1)jVz(Mrsk0U`)iQH6lsO(qhYu zWztU)7|WbB7(az?^s7!4)&cU!P6-MZqnlh05UaZ>=*g^eE%Ok}1Be$ImITs1d~?G|uySY!p~wg>Ip592N)%P$G7o!#5@wHJ2-L$LE%|(Ka3pqSr4YeRZ7Pac*gs-Zl_y5M~EV}Ri&?SxU#LPqi_KFc1j5iKz4wm z0~(At)ly0zxfQtTkUIob>mB5Lm9rh7Mz25TiL8Y?uo4<|PGhDn>D>`Ftg}Qs!zo`I z<{8ySb*jlHy5V(*+*^Q*sqt74!5)u=FexA-uoDUsg`F-ijn#Il=py{s^RWmawpdM$ zE%(+XTw`@c9kW14c0G%vBcsmK@ZKe4Gl**;V%d9u*J&q59V}*xe4Msz2puQz!G&om)(0vT!$sIf;Zp6EG`P@FfL{_ZPXiS|T z=upN>Da(!JuPTU`l8kvYdt5fmC~YGG6Q*+P-86A!YPax;54}GKVL-wh#R$DDy%csAr;p7sX#^u z863OVxHwe~)-PhR`(>zYsD>sNJJ}6JNY!9$y|F$OF?9EvY*mlMdeujFdbxLraY?F^ zydtQ}BFQ?|ln}B;UaFO*?8X%1Qr@kQwJq4f=0aS_bf*sktXR@Wrdmro+xJ-|-Cd(V z^i?2mu&-B@=k%j@32B&(O%D7vQU=Mzx$zV}jcEJ}KBz_ViDA#-#6iU{Nb!qNtx=oO zQL;N%V?>elSCQ2>zN#^KHTYL4TJjo}n%oOmttAJzQ%PCa2TYB=mW4>5d1YLysN(Us zv!Cbb&LF;Ou?OA0hT~M#J=$1M_o!o96t#}o>^f#>-glARUs6Qol zG}Q0|FpDdMp+jNhaLT}LZA6npz(2%(YPp&xgpb&$7WJo$Dl{66c-*LNJetH&k&8%U z+^8w_P&bU~>x}r3*mC9*HkLogTqG+ff^z^iLPPzaeNN>{aoGqqOx;kOgJ6XvI>cWg zZ=tp1VTp`IT2NRw{$1s3P(UZ&k?O8kMg{Y`M5k*6|O^X0g@Cj!A;k1|^r!QedO{ea@bosv8W75no|W)$SnLQjQboozIl)1 z2WK0yu&fW_(~b5eyrH0;Y(pDfLp;RixnOvVJk}{hkX$~l6I?d562{jR{F%o?-~pGE zVhUvel(@dZ4qO0bodOO)q_n(CQRg`ol)yYE`~|KEET+Uk%;a3hOk4)JIPu~J7V7}_ z8l8gY4qlLo$Tz$tk|$!PC`lTnb$sVl=nV9Q8{Uq-2QJXCGR=^=ev-v6)C5{%kTnY| z(P87S;c8yulE>roY^T3ha4qwjT*$b&uydZPn39}fOE#`mlBZ<@zE|nLU<*G57*)02 zokG009|myFGR=DT8AiNXf!G;14^d!5<&^sv@fbjf$9LtF3Pg(vik$!@3Z%@mdshYG zDMtKL1>zTsFoNYNm!s_tRUmF*#Jv@WFEZlgMZ^NGYHDE?W-Z`0r*6E__X8o8_>_Xk z;uDGzoaYk_LX*0OuI?7R(s&Ttbb3p=E#1-9(TMMr|q=v9;j)F?sEP=uaUHYgG5qYX+F zGM|B-cSxRw9Q|f!gQC%bc6BI1R|J`|M`z36Ee7c#8lj(pPZFFpdM>yI8g_|k?0|PeN`&?ahD~zr z&*a=6Nqs)6vh=UZb~Q=4L6-F-FcErG(tldgA5$5#RZ9F4vBZb;p9U|Y6Cs9GfD!sz zN%Kk2v$t`>#KRFIu+|Cjq0rXF-VgK-g)HoxVL7%U^r6rcEeDl?PXLQHMJutkar(4S z0)lpHLBMaR41a*#u1bkLq189l$fPbNH1PsZ!H|k12qhn}mZmzNklrQKEzpQisz7wN@?vyYiX%1m-oK|bw0o~9}aCk*$KKFzf9sq+4H39w6?u8X7N(Nj%yI-*!z%_f`*m4I)x$_ z5cKH~x4$CWUzYF{Kn0%TH(iI+Fx{gGY#eOk3cxDb09Z%u5_U5`b%_! zxJP@L48WhF8vUvAbJ`;5o9SL%7f;bmSe*x`Nvsv7I0YRZp!%>b9-zKpQalE^t>O{L z-HdjV*e0H!UHTQk@LX=60sQySyFuT9_VeKX9>5QWZwD0WX21qziaEpWwkg2kNs#IH9A^us(E2iiQ z-=sW%(K>p<_uGK}5#I1s6Jovo9N-r9n}EL&-v;Hw1WH;!{Xvh9|5kT`v6<$$ABFaP}A5cB7i;A z1bB_a4*~YjG1{+QN?lYVy2bP2gi=&)ReqrSL@CmJ^jGv0y@(`xTBr-0Yn9Ktu>D~( zU3~sq`5V~|0^7Ja@(gnE{O9i_qos4V%4)9gxpwhslbxkf2Ny@nji2*IectnLavJNh z9u?W5d11@XpDQ*!j?Y(F-X60sIb;=2wo`w;*s+`DoOLA)QyDohT#&Ow|& zsMi{unbfw$O#zzYFjaILfE1EQc-jq3E<HVmcCS53 zQ-v|d&7pCXYfewvV>C2dC|XnL9w(QBrck?(zRJp5E`~DMEb&id(6X@CF|$@y%CPe0 zXbx?=&=19JGY6Sj>a(pJ!+e%-tTKz%ggrK3PQzOGqfj*SV-^jV`57~}*O?e{W?c05 z*jbC6*MlDEcqM>QmE?QnYbH+SnQUC7z z%#`J_iqsFu(@sIQufo~Q%neOCXNH}L2@F*Q6Zx2XBYVCEF2_l^{pYtwXyzYuGBwZ<+GMs>W#RI zcC$BOlSRYs?4aq&hI!iJhR2qATnpT#a%U#t9a_TcfMsS6v(soKYmJ*TxuWMoFMOms zz37@?w`GbrB9G31I#VcEQ=_@rVY^s~9yVQgp%1?`TW1{i)P?kYcFsBk^$=MX4)*8A z9e2u<*^+xhsvajlZcof0sFpD4ai*s2oJ1b5a^_jtDqJW8d6bcEganv)1GhkftJrCkj?_le(6UIkv7VPS5pvoW5r?D%oli(Y1(vAjLLnUhC<6Sp5Ffv}omCGxR;>r4rl8NF+Jvnn~ zT9S_CEYp=OUPa3#4m6kG5~MjA!_Hpk48GYbSPZnJp0Wjt9IrnnTcr|*eT75OFL>Nb z^IiiezXqJV(``+fr)^Z*QoS#fT-Ixw6M3glw8s`vrTFm@%W{Vh3pSjMg)GQ|UGOUd z!ij5if%;0NumFFVS-)KI1T#BmpS5xYR?u%DZ2cAzx@g+@MZx7ID@gBUa`r@i3emD( zE=z%Uh#(WZX03N|H&lz`kQ@4wN1T1&jLkVt>U+1bYbfnB9kTxbMG1#Fw}S!rJ?dzH5w1f`S-SF$JN`f(e^@E5D& zm8|~!9vh6@vB_D=Oi$-#sm(usAbJW#*O}#gxpYE;>ya4+7!L1XmSkA&IMXA$Z@`%W zg_zLp&s(Kle_`KDF1O#^JvEInDBi zjX&V&q{}4E0fy;p`Z?u+X~S9B`=m+CAEbWT1nOQofD@quzME(-_(37?@_IJj3D~mT z2iXp|6hUu;Du><#_-~>M^*RI!3vVblRd7DwYt20HVk(>gzbSr$g!joF=QR3k-55<$ z8aNA-SwL=~N&r{D=u!`y_9dmEl||!nP64n-+Q8bf+)6$aE?G;}Q=noAc!y^6K&p*a z)|X5M>#+nQsDbrk9c&tvKEnP7Te4Dblc@TT^vn!+QuTh&dHPeB=Sb|bIjq1u-W$!~ zzC91B5$Qh@M z7yX)aD7Gq^X^3_yk!VIoQ;%j8rNQV|B9R7T05B3!qM2wtK07e8PSC20NUajlOvs;w zpQV-P!ejUk@*^sEL!?k*6iO%}MlqpD!bnwun6HPC0wiXjgkfQ709vG87>YzN4chER3%S|xfgdKCXoFob?)kVN!a<{v%E z;2}`k?N;5!na}bVV6GbzA$3U|VUx7$O4)8iPM0aD+7!`@M zgqorYH}ij)RmQ@t{Hdvdp|D%mS+t_)x{kIEMic}gn#RJHj0L;`Rz!3jm>^-{Z|2v2 z+=0_Tf{=j6bX`jj^Mp#^h!tes_zzQng$^KvzlC6;>QI>7As=Wj6nIQTcZ5U1Xg%Dp zgX0Mz9;*w5&|SDYdM$&6k0}~t!uyix3s_Kyejx~FE!^#O-YYw|dmZQk*&gaH5A_mD ztMS?|s}Ry0zz+?fP*AF(KYru!Lo2p?@4fOBnxY{(YjiKxqB}~Bj0Ozc8qlKGs#FkVu3Y=M(#1_@pq;-KIf!2Znlw?w`N) zAKT9j_WX79saI|(?C4`2y_X&5t8ET9wZd_ExlZ63m&N_)_@aNHp}g6bF^jjXy z$ECxL=dI$F?VDeRCOw@UrJ+5U&0DvTufovfz6vmN<>|}=C%;1n2M@|x*MgEnZvwPg&1aLRb_(M3k?x%g|_XGBM|JMb5Uj2`A z9v_cai6{OZRz6%VI5sPvUUUSw@_DWg=an2z4E;D4jbqp6=VJLLe;A{tJR#@sT?8GU zm%ZmvmH!4)Kqv2}kjFjgLQbEOG;KI3djGcIM#16Vhl~*N1dTUKQpPMSGI2MuBzupm zcOLg{fu-A4>*8sP3HM1pCAoZ}Dd2p{H<#%p`o3L$Z76kO(T+pl$9J-_-R-!awJm;F zek17Fb9`TQ@y&O}vL$avZW^b>9RBf>#7YU=jri`%ocL@$jr${8G=ZBM?lMRbjtZ8` zw-LtkiI%BLe&C+x$=_DKw=RR=%eSc+__A1G4f(76*6Z?a+=>NOs*=z7-YomFg|@@u zt+)+zLh5$fhPH{`R-DmCaZ9j(ZO3OE|4j7S(B?SmM4K^u7ukj$w>vP;gog-yUds&D qkI%zXn301g6Y$;ARW0kmYx_GqyS%?y*;`7u-+{&dPx<}z!2bbz-n1V8 delta 6046 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 O1BE;=#~AeE-qFA3g>JL} delta 1714 zcmYjRYfMyE5S}@E@7=vD?6NE>AmA?GE-12~plDk0K_u2RwgrqLq6qkC5O9Git+*Fh z(3U>LleB45qpeo#Bes=jYSRZcwf)hiX^gM_sM>~FO)ZH{O#d{o-`T7QcXz%!-<+8< z=ggUNt)|PH4wcr|XhgaDi3)Y1Qw+VjE4;I9dne(!Y!G3Xa%-#UI`pTMURArg67PIF z(MLh>6|L=C!L2pVFYh_?$=c||;Kcfi*CUrhcW;gyN=tWR%mXnYdmuf0MkCmZ;(Y;0+FD~prGNP?BGn# zHW+O9aV!_nPI-i9`On0y2CO5{-;Z+#_*v*t`72lO2Qo`^Mhryf$D^ZIu;Rsv+5@O9t`;AL_D+nD1KUy89Nrbx_C4u|6yTmhpK0gK}S z3&9ho@ImmTDO?rVHHA+HPeyeg#s35DnZmQd)$;>{=?!2+P&pFoGz2v1J(v>cCFo8h zQpuFv6|07udZ8!NJ=lrXLbuV&&@?&*U5{1Spi1a=asi3PAvj*3pkAPj27nq(1L~yO z&WK>GDgYgZQc8rmVtaSf4(Q3G+AoD308?ouEYqkCdK#fsD4kR@W~ee!7R?7{QyVOP zngczDwnHb95T-wXf@T42bPcG{0-#P2J6sJq4`Qbqz{J=gB+)_GU9m%PQv-COFi_A& zppBjZ*Ju)`qdU}t7M>+y?-zpV9tGjm!9jTKvMqyGif;?>zRv<4@gD=8$Q>trHvOIF zW1YHZF9WU$YytKJEa26^F<@b==jFJ*Kt9w@I68LjZE5YKu)JXS<)jhzbna;HZf&mK z(Y}Ym?cHt7HFCc_Am6c%)>bu)+!;T8rLZHjYqH|G)(aupb}jSVseW&CV&d+1uQxbr zTK0Bzhg&*}nmXAbvK7kt=c`m|HhXE{+}B&L+^gu zE{`}yeHYL6?{YWkd2ijRcdslQ|Ec257k`}i&0WM@@~gSKo#NFetxGzFt0JhDm45Zj-;%;k{6=-yjS704JwU|7mAzD`frEGo7 z{lh$v!%;s+YdPA_(J_ub5XsY73@#Oer+G-{p~rmEd%L%9otBMleWhIBQ!;@Ui~