From 9a7eae8ace6dfdb9e7fc59434b3aeaebb5d3fc11 Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 21 Jul 2015 18:43:57 +0300 Subject: [PATCH] stairs fix, wraptext fix, moved drawing sprites from GUIFrame to GUIComponent, server name and "welcome text" in netlobby --- .../Characters/HumanoidAnimController.cs | 7 +-- Subsurface/Characters/Limb.cs | 5 ++ Subsurface/Characters/Ragdoll.cs | 10 +++- Subsurface/Content/UI/style.xml | 6 +-- Subsurface/GUI/GUIComponent.cs | 18 +++++++ Subsurface/GUI/GUIFrame.cs | 17 +------ Subsurface/GUI/GUITextBlock.cs | 18 ++++--- Subsurface/GUI/GUITextBox.cs | 15 ++++-- Subsurface/Map/Location.cs | 2 +- Subsurface/Map/LocationType.cs | 2 +- Subsurface/Map/Map.cs | 3 +- Subsurface/Map/Structure.cs | 22 +++++++- Subsurface/Screens/NetLobbyScreen.cs | 45 +++++++++++++---- Subsurface/Utils/ToolBox.cs | 47 ++++++++++++++---- Subsurface_Solution.v12.suo | Bin 439808 -> 518144 bytes 15 files changed, 158 insertions(+), 59 deletions(-) diff --git a/Subsurface/Characters/HumanoidAnimController.cs b/Subsurface/Characters/HumanoidAnimController.cs index d11ea22d3..13f22e6db 100644 --- a/Subsurface/Characters/HumanoidAnimController.cs +++ b/Subsurface/Characters/HumanoidAnimController.cs @@ -48,7 +48,8 @@ namespace Subsurface } break; case Physics.CollisionPlatform: - if (IgnorePlatforms || stairs != null) return -1; + Structure platform = fixture.Body.UserData as Structure; + if (IgnorePlatforms || LowestLimb.Position.Y < platform.Rect.Y) return -1; break; case Physics.CollisionWall: break; @@ -353,7 +354,7 @@ namespace Subsurface Limb head = GetLimb(LimbType.Head); - if (currentHull != null && currentHull.Volume < currentHull.FullVolume && !head.inWater) + if (currentHull != null && (currentHull.Rect.Y - currentHull.Surface > 50.0f) && !head.inWater) { surfaceLimiter = (ConvertUnits.ToDisplayUnits(head.SimPosition.Y)-surfaceY); surfaceLimiter = Math.Max(1.0f, surfaceLimiter); @@ -399,7 +400,7 @@ namespace Subsurface movement = MathUtils.SmoothStep(movement, TargetMovement, 0.3f); //dont try to move upwards if head is already out of water - if (surfaceLimiter > 1.0f) + if (surfaceLimiter > 1.0f && TargetMovement.Y > 0.0f) { if (TargetMovement.X == 0.0f) { diff --git a/Subsurface/Characters/Limb.cs b/Subsurface/Characters/Limb.cs index 06ab52c59..6c6ce7fcf 100644 --- a/Subsurface/Characters/Limb.cs +++ b/Subsurface/Characters/Limb.cs @@ -74,6 +74,11 @@ namespace Subsurface get { return doesFlip; } } + public Vector2 Position + { + get { return ConvertUnits.ToDisplayUnits(body.Position); } + } + public Vector2 SimPosition { get { return body.Position; } diff --git a/Subsurface/Characters/Ragdoll.cs b/Subsurface/Characters/Ragdoll.cs index 281c328f5..abdc11695 100644 --- a/Subsurface/Characters/Ragdoll.cs +++ b/Subsurface/Characters/Ragdoll.cs @@ -268,11 +268,17 @@ namespace Subsurface if (ignorePlatforms) return false; //the collision is ignored if the lowest limb is under the platform - if (lowestLimb==null || lowestLimb.SimPosition.Y < f2.Body.Position.Y) return false; + if (lowestLimb==null || lowestLimb.Position.Y < structure.Rect.Y) return false; } else if (structure.StairDirection!=Direction.None) { - if (inWater || !(targetMovement.Y>Math.Abs(targetMovement.X/2.0f)) && lowestLimb.body.Position.Y < ConvertUnits.ToSimUnits(structure.Rect.Y - structure.Rect.Height) + 0.5f) + if (inWater || !(targetMovement.Y>Math.Abs(targetMovement.X/2.0f)) && lowestLimb.Position.Y < structure.Rect.Y - structure.Rect.Height + 50.0f) + { + stairs = null; + return false; + } + + if (targetMovement.Y >= 0.0f && lowestLimb.SimPosition.Y > ConvertUnits.ToSimUnits(structure.Rect.Y - Submarine.GridSize.Y * 8.0f)) { stairs = null; return false; diff --git a/Subsurface/Content/UI/style.xml b/Subsurface/Content/UI/style.xml index 53f89f74b..73b0c7357 100644 --- a/Subsurface/Content/UI/style.xml +++ b/Subsurface/Content/UI/style.xml @@ -47,11 +47,11 @@ - + 0) + if (Wrap && rect.Width>0) { - text = text.Replace("\n"," "); + //text = text.Replace("\n"," "); text = ToolBox.WrapText(text, rect.Width, Font); Vector2 newSize = MeasureText(); - Rectangle newRect = rect; + //Rectangle newRect = rect; //newRect.Width += (int)(newSize.X-size.X); - newRect.Height += (int)(newSize.Y - size.Y); + //newRect.Height += (int)(newSize.Y - size.Y); - Rect = newRect; + //Rect = newRect; size = newSize; } @@ -184,6 +186,8 @@ namespace Subsurface GUI.DrawRectangle(spriteBatch, rect, currColor*(currColor.A/255.0f), true); + base.Draw(spriteBatch); + if (TextGetter != null) text = TextGetter(); if (!string.IsNullOrEmpty(text)) diff --git a/Subsurface/GUI/GUITextBox.cs b/Subsurface/GUI/GUITextBox.cs index 3ee6794e4..00cbbda46 100644 --- a/Subsurface/GUI/GUITextBox.cs +++ b/Subsurface/GUI/GUITextBox.cs @@ -24,6 +24,12 @@ namespace Subsurface public delegate bool OnTextChangedHandler(GUITextBox textBox, string text); public OnTextChangedHandler OnTextChanged; + public bool Wrap + { + get { return textBlock.Wrap; } + set { textBlock.Wrap = value; } + } + public bool Enabled { get; @@ -74,9 +80,9 @@ namespace Subsurface textBlock.Text = filtered; - if (Font.MeasureString(textBlock.Text).X > rect.Width) + if (!Wrap && Font.MeasureString(textBlock.Text).X > rect.Width) { - //recursion to ensure that text cannot be larger than the box + //ensure that text cannot be larger than the box Text = textBlock.Text.Substring(0, textBlock.Text.Length - 1); } } @@ -111,7 +117,7 @@ namespace Subsurface if (parent != null) parent.AddChild(this); - textBlock = new GUITextBlock(new Rectangle(0,0,0,0), "", color, textColor, textAlignment, null, this); + textBlock = new GUITextBlock(new Rectangle(0,0,0,0), "", color, textColor, textAlignment, style, this); textBlock.Padding = new Vector4(10.0f, 0.0f, 10.0f, 0.0f); if (style != null) style.Apply(textBlock, this); @@ -121,6 +127,7 @@ namespace Subsurface public void Select() { + Selected = true; keyboardDispatcher.Subscriber = this; if (Clicked != null) Clicked(this); } @@ -172,7 +179,7 @@ namespace Subsurface { GUI.DrawLine(spriteBatch, new Vector2((int)caretPos.X + 2, caretPos.Y + 3), - new Vector2((int)caretPos.X + 2, caretPos.Y + rect.Height - 3), + new Vector2((int)caretPos.X + 2, caretPos.Y + Font.MeasureString(Text).Y - 3), textBlock.TextColor * (textBlock.TextColor.A / 255.0f)); } diff --git a/Subsurface/Map/Location.cs b/Subsurface/Map/Location.cs index 016cd05ea..0eb31e44d 100644 --- a/Subsurface/Map/Location.cs +++ b/Subsurface/Map/Location.cs @@ -44,7 +44,7 @@ namespace Subsurface private string RandomName(LocationType type) { string name = ToolBox.GetRandomLine("Content/Map/locationNames.txt"); - int nameFormatIndex = Rand.Int(type.NameFormats.Count); + int nameFormatIndex = Rand.Int(type.NameFormats.Count, false); return type.NameFormats[nameFormatIndex].Replace("[name]", name); } } diff --git a/Subsurface/Map/LocationType.cs b/Subsurface/Map/LocationType.cs index 877cf1c29..453e23dff 100644 --- a/Subsurface/Map/LocationType.cs +++ b/Subsurface/Map/LocationType.cs @@ -47,7 +47,7 @@ namespace Subsurface { Debug.Assert(list.Count > 0, "LocationType.list.Count == 0, you probably need to initialize LocationTypes"); - int randInt = Rand.Int(totalWeight); + int randInt = Rand.Int(totalWeight, false); foreach (LocationType type in list) { diff --git a/Subsurface/Map/Map.cs b/Subsurface/Map/Map.cs index c189bd182..e48c16ab4 100644 --- a/Subsurface/Map/Map.cs +++ b/Subsurface/Map/Map.cs @@ -64,8 +64,7 @@ namespace Subsurface iceTexture = Game1.TextureLoader.FromFile("Content/Map/iceSurface.png"); iceCraters = Game1.TextureLoader.FromFile("Content/Map/iceCraters.png"); iceCrack = Game1.TextureLoader.FromFile("Content/Map/iceCrack.png"); - - + Rand.SetSyncedSeed(this.seed); GenerateLocations(); diff --git a/Subsurface/Map/Structure.cs b/Subsurface/Map/Structure.cs index 7fd09c742..3976ade8f 100644 --- a/Subsurface/Map/Structure.cs +++ b/Subsurface/Map/Structure.cs @@ -208,7 +208,7 @@ namespace Subsurface bodies = new List(); Body newBody = BodyFactory.CreateRectangle(Game1.World, - ConvertUnits.ToSimUnits(rect.Width * Math.Sqrt(2.0) - Submarine.GridSize.X), + ConvertUnits.ToSimUnits(rect.Width * Math.Sqrt(2.0) + Submarine.GridSize.X*3.0f), ConvertUnits.ToSimUnits(10), 1.5f); @@ -218,7 +218,6 @@ namespace Subsurface (StairDirection == Direction.Right) ? -Submarine.GridSize.X*1.5f : Submarine.GridSize.X*1.5f, - Submarine.GridSize.Y*2.0f); - newBody.Position = ConvertUnits.ToSimUnits(stairPos); newBody.Rotation = (StairDirection == Direction.Right) ? MathHelper.PiOver4 : -MathHelper.PiOver4; newBody.Friction = 0.8f; @@ -228,6 +227,25 @@ namespace Subsurface newBody.UserData = this; bodies.Add(newBody); + //newBody = BodyFactory.CreateRectangle(Game1.World, + // ConvertUnits.ToSimUnits(Submarine.GridSize.X*2), + // ConvertUnits.ToSimUnits(10.0f), + // 1.5f); + + //newBody.BodyType = BodyType.Static; + ////newBody.IsSensor = true; + + //newBody.Position = ConvertUnits.ToSimUnits( + // new Vector2(Position.X + (rect.Width/2 + Submarine.GridSize.X) * ((StairDirection == Direction.Right) ? -1.0f : 1.0f), rect.Y + 5.0f)); + ////newBody.Rotation = (StairDirection == Direction.Right) ? MathHelper.PiOver4 : -MathHelper.PiOver4; + ////newBody.Friction = 0.8f; + + //newBody.CollisionCategories = Physics.CollisionStairs; + + //newBody.UserData = this; + + //bodies.Add(newBody); + } } diff --git a/Subsurface/Screens/NetLobbyScreen.cs b/Subsurface/Screens/NetLobbyScreen.cs index ec592915f..6acb63cf7 100644 --- a/Subsurface/Screens/NetLobbyScreen.cs +++ b/Subsurface/Screens/NetLobbyScreen.cs @@ -32,6 +32,7 @@ namespace Subsurface private float camAngle; public bool IsServer; + public string ServerName, ServerMessage; public Submarine SelectedMap { @@ -44,6 +45,16 @@ namespace Subsurface get { return modeList.SelectedData as GameModePreset; } } + //for guitextblock delegate + public string GetServerName() + { + return ServerName; + } + public string GetServerMessage() + { + return ServerMessage; + } + public TimeSpan GameDuration { get @@ -145,8 +156,8 @@ namespace Subsurface textBox.Select(); - new GUITextBlock(new Rectangle(0, 30, 0, 30), "Selected submarine:", GUI.style, infoFrame); - subList = new GUIListBox(new Rectangle(0, 60, 200, 200), Color.White, GUI.style, infoFrame); + new GUITextBlock(new Rectangle(0, 110, 0, 30), "Selected submarine:", GUI.style, infoFrame); + subList = new GUIListBox(new Rectangle(0, 140, 200, 200), Color.White, GUI.style, infoFrame); subList.OnSelected = SelectMap; subList.Enabled = (Game1.Server != null); @@ -169,8 +180,8 @@ namespace Subsurface return; } - new GUITextBlock(new Rectangle(220, 30, 0, 30), "Selected game mode: ", GUI.style, infoFrame); - modeList = new GUIListBox(new Rectangle(220, 60, 200, 200), GUI.style, infoFrame); + new GUITextBlock(new Rectangle(220, 110, 0, 30), "Selected game mode: ", GUI.style, infoFrame); + modeList = new GUIListBox(new Rectangle(220, 140, 200, 200), GUI.style, infoFrame); modeList.Enabled = (Game1.Server != null); foreach (GameModePreset mode in GameModePreset.list) @@ -186,29 +197,39 @@ namespace Subsurface textBlock.UserData = mode; } - GUITextBlock durationText = new GUITextBlock(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 30, 100, 20), + GUITextBlock durationText = new GUITextBlock(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 110, 100, 20), "Game duration: ", GUI.style, Alignment.Left, Alignment.TopLeft, infoFrame); durationText.TextGetter = DurationText; - durationBar = new GUIScrollBar(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 60, 180, 20), + durationBar = new GUIScrollBar(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 140, 180, 20), GUI.style, 0.1f, infoFrame); durationBar.BarSize = 0.1f; durationBar.Enabled = (Game1.Server != null); - new GUITextBlock(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 100, 100, 20), + new GUITextBlock(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 180, 100, 20), "Level Seed: ", GUI.style, Alignment.Left, Alignment.TopLeft, infoFrame); - seedBox = new GUITextBox(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 130, 180, 20), + seedBox = new GUITextBox(new Rectangle((int)(modeList.Rect.Right + 20 - 80), 210, 180, 20), Alignment.TopLeft, GUI.style, infoFrame); seedBox.OnEnter = SelectSeed; seedBox.Enabled = (Game1.Server != null); LevelSeed = ToolBox.RandomSeed(8); + var serverName = new GUITextBlock(new Rectangle(0, 0, 200, 30), + "Server: ", GUI.style, Alignment.Left, Alignment.TopLeft, infoFrame); + serverName.TextGetter = GetServerName; + + var serverMessage = new GUITextBox(new Rectangle(0, 30, 360, 70),null,null, Alignment.TopLeft, Alignment.TopLeft, GUI.style, infoFrame); + serverMessage.Enabled = false; + serverMessage.Wrap = true; + if (IsServer && Game1.Server != null) { - GUIButton startButton = new GUIButton(new Rectangle(0, 0, 200, 30), "Start", GUI.style, infoFrame); + GUIButton startButton = new GUIButton(new Rectangle(0, 0, 200, 30), "Start", Alignment.TopRight, GUI.style, infoFrame); startButton.OnClicked = Game1.Server.StartGame; + serverMessage.Enabled = true; + //mapList.OnSelected = new GUIListBox.OnSelectedHandler(Game1.server.UpdateNetLobby); modeList.OnSelected = Game1.Server.UpdateNetLobby; durationBar.OnMoved = Game1.Server.UpdateNetLobby; @@ -517,6 +538,8 @@ namespace Subsurface msg.Write(selectedMap.Hash.Hash); } + msg.Write(ServerName); + msg.Write(modeList.SelectedIndex-1); msg.Write(durationBar.BarScroll); msg.Write(LevelSeed); @@ -538,7 +561,9 @@ namespace Subsurface string mapName = msg.ReadString(); string md5Hash = msg.ReadString(); - TrySelectMap(mapName, md5Hash); + TrySelectMap(mapName, md5Hash); + + ServerName = msg.ReadString(); //mapList.Select(msg.ReadInt32()); modeList.Select(msg.ReadInt32()); diff --git a/Subsurface/Utils/ToolBox.cs b/Subsurface/Utils/ToolBox.cs index 0d3918a26..24f412f47 100644 --- a/Subsurface/Utils/ToolBox.cs +++ b/Subsurface/Utils/ToolBox.cs @@ -256,27 +256,56 @@ namespace Subsurface .ToArray()); } - public static string WrapText(string text, float lineWidth, SpriteFont font) + public static string WrapText(string text, float lineLength, SpriteFont font) { - if (GUI.Font.MeasureString(text).X < lineWidth) return text; + if (font.MeasureString(text).X < lineLength) return text; + + string[] words = text.Split(' ', '\n'); - string[] words = text.Split(' '); StringBuilder wrappedText = new StringBuilder(); - float linewidth = 0f; + float linePos = 0f; float spaceWidth = font.MeasureString(" ").X; for (int i = 0; i < words.Length; ++i) { - Vector2 size = font.MeasureString(words[i]); - if (linewidth + size.X < lineWidth) + if (string.IsNullOrWhiteSpace(words[i])) continue; + + Vector2 size; + string tempWord = words[i]; + string prevWord = words[i]; + while ((size = font.MeasureString(tempWord)).X > lineLength) { - linewidth += size.X + spaceWidth; + tempWord = tempWord.Remove(tempWord.Length - 1, 1); + + + } + words[i] = tempWord; + if (prevWord.Length> tempWord.Length) + { + wrappedText.Append(words[i]); + wrappedText.Append(" \n"); + wrappedText.Append(prevWord.Remove(0, tempWord.Length)); + linePos = lineLength*2.0f; + continue; + + } + + if (linePos + size.X < lineLength) + { + wrappedText.Append(words[i]); + linePos += size.X + spaceWidth; } else { + //if (i>0)wrappedText.Remove(wrappedText.Length - 1, 1); wrappedText.Append("\n"); - linewidth = size.X + spaceWidth; + wrappedText.Append(words[i]); + + + + + linePos = size.X + spaceWidth; } - wrappedText.Append(words[i]); + if (inUrs?0UJd~d5EPFPgCHsrQSk^-ON=OZ1w|2!N20GJCaIc4 zd<~B#)&mKiQ50okngdCi+MH;P8WRm#n|eCA*M+Q#OSClntQN~LX0dp}fBDLlD>4{f%Tdr86oU^D@DVr;q8QE2 z;y(JU#o7aGHP81rw{QEWuf1Hydg8)l#{#~Hjjj5YN3o6?0ubSqUU2^gHyG|nFbn8l zC>Y~NQM##b;pl{8t`e@u>mBQr2#*B_8V1JUks};$Dyg9|aUBpc2MC1v!OaIAU@lnX zh*y2oLL41%q^oI5KF3iA_yF7kazUN2So*>34-$Yc=nEbM$%r!&sK5^Y-C!qp0tA8} z@H%)3yaycMd5{MVfsvL1{4289ECVewEk%wt{4S503Cs3fD;qbq+Qk|##UsTc^Cf>$ z2vSt?_(r1Y!K9dm{11^%BvRWT9Tyz`lyn%f%Ygu$G)q;R?|L%ISgctoc@KACV;pz2 zUZT#&$;&0PLq=#QgI^=YM7X2jevWb*1J?)cIk-_E1m`*ff6x|ug0Onf1IO**zJqIz z!@USnXvAXX<0VDA2Hs5IjmzGnxr*%31#SX3idcStKMk~pe;Zs+ zxU!DKgSPa6jG_P`L*VrVPviIjAfxOBe;khIgF!eR0MdaxH{9teG-3%0clF05-N9w) z-Q)T&Wbue8kKV3?gSFD5=PcGXvVGqTxUuk7yBD!hj=Ao`m2Qa5k=ZxG5eEs6bbRYR zO4)-TIy8y-IqI!Gjv^1c7KIEx*2-~lT(l#?8dR0!Tgyh=ij-YX{4&-5g7~8m?X}_` zAuGW*NX2HP?WV<#d!7Y<0J0*jhwDRZ3iIjt&lJg*QubZ0E(%(0wN=>yIHxiP3v;}} z;~YiSw_Vw0yfQ~r!}stKZ$Teu4`A7bh(F3~A6tDhlSAQoM8_ zn7^y+zv|qD5FT3<_Lq~4?5kNsRm6o$%welmwnSW1sv3}(-YQjM*0 zm&(w9zFuRwY;REpV@n--AM)`Ziwwz(NzH5ESwZtW`0@%DrmXgkaFj>eT(;t}EzR?; z7e%n)%$4mxU`6v2rQ5io-H#NbXS?jdc!mwb+3)yzrKv$n?ybrz5CMM!K^*iU14#Q;>SBs z%~a7&?>&`$=A+xjuxO@y-8}VFG?uN5Nk`%z2T~w8aMN&!JKXa!3`omh9oPkafA{^}TeK0M(oROe6Odl$6ARkd*A;BJEZ3^)u*fEU6(gDVTeQF%VV zuN?xuLcpuwUhps&>^O10?UKnjl1Y0Lt~;)JA8w^H?DudV0w044uncs-HAQf1z!%_q z&>vy%!2K>SP2jDpP5PSqqfRo^3P!CRl z(;^l901nQ8KY~xdpTMW!Gaw%Bj#rib#y*yITUv{y@+WUCITamQz8Md%>M;x1tqJDWJVm?c5w!+EVWd;5RE8LIj8*~Lp=!PPboyJNSHjY30-O;=PwnF&N zQUUe9ZDoRoS_WAPEjj4w@+`5INf>st@n8D+S0D8ErH5Yc!S3>1K%v#FIQXzzv7S(S zaCeF5lpV1yZ4pvoNJ?h+NDFUH?T}ragupgKLS}+iMMR5&6iJ~-QL0d%Dm_e)1T_SZaw92 z&Cikc_CXpkQAFuc7uW}CDd%rnty}M{S!i3E+V#%C+756tB&SZRco>}k>Z&YYW{pCk(dvRV2o&7b~wKx?n% zn*lE@)o%50$1x;l{^-pJZI0`?R9C}0mwtB-?@cx1crweNL*022AGuJ9bTUoYf+Aa_ z@MWzW_HtMv+8DaK2Xn$)GAqp zmA5XvouMnQmG%;QRO_O53F7auijR=9^Nd%A@gf&(G*aQK=nFgZhg@mXKCPZA)47#0 z_iJ@jvr|jaSucJikSg0Sg|&16|9Te?2tAPXwXqB6U0TiptzPc-{Pa|xkdEFXzkK0K zdmlsj^`vrE%ji&u+Eed2nt$SJjY&(1D(-eHw%?)7b8Z`-9&B93GEMWZevI(Y?bEnj zDSeQqI$j>%o#sBsm#`u9Eu2;-@#I}?87*4I?{B4;y67mG(~)YPQX^@?ok}}BcNSmY z>Lzro`aXVv@hpx0az9_J%|<_S)|(bC<`>yCn!5y#o}z!dgu5xL&q584K@F={@gmN* zSZLmAewlBE>%fhhkQf(>e(_p7|Tk|ltYkfF6_Z61-DrNJ0|SMA)4ZuasqWplZY%#WfY-|ty z`^L7M#rsKP8)6PLr;|(UA=Q;)4YNu^Q)x16x2jcpAtF zfUQ8z0c{6zQeY?81)c%B!5&Zv_JVz&3hW05KsC_8v)~|j4*VKC4_*K-f|o!IvrMrZ z!a*%~8N33116~Ec1&6`!z-!=j@CJAjyanC{b>Ij%3f={>$$1a%```noUxr<5D2jrB zOU_`17F(Wb_?2!GcHhm;qLIZ^?mX7lY~U-=Ebri_VAX6Bi>&gjL@I!E^_3fV5vy>A ziL;U`oRoe1m|~o$-^XpNw36SaY{KKnUdij&_cVJS?_FZgrZanaQ1yOZ!}OYiqJLlg zl~;M+_IgrVrPf*5BLdF;Y0w3huxrFKDFUMoaTsvpF> z15Fct7R<8(%XEw5mmO!e!kR@~^J}86z9tqn?i|CQd$Mo%g}fK*SpU>fsjYEG$yn8g zPFC~fln^Sc9>}2alWQj(=+J5ILr?15o$7jsAleivy81|?G96=x0xS%~!ZySay&WnX z0&NsAuJ&$~);}XX7@nmMs2!;OUM1KFX)i-ID}nT)ssz!hFS#OQu4X?e;;C+#h%hdS zZ3szTBRU%)=vwJiH!Z~QU|N}8dPZqW!#XLRRR5Z)8Nu>l4Z&tSZ4t7$lNw{3ZUfJW zp=t-iBlCP}n(zsgse}j3v^g%4<0DgO&C(xAMZMH^#*N;%@%7$nxZ#O_rz8#K(fLl{ zZG?122=X$@@W^xyeNE{?ncpIt==U9)=Y`X`wyLLb+6$*gOi@A&k1srL4;N8}2aPoy zc|z@Gc*2bPVw%PTMyMYyIW<;vQe`qdX>+(}OQqq$lghG%fBX;>@&e05lui!RBNsD2 z(@^lU;44B&O*K@YDVOruU(Zs^XG>3qO{(cJ1eoCzpiFPb>#CVvd8Xj6iYeO0LS13i zg3R1H1rbk+=dmy&#qy4lXa#eEGnD{Jeir8;ATFiRB+VH8@Tb|m}fim!~sg({~y ziytzeBgd80rmWvBIvE}r#pV<>gw7q}N_(l5Y0i?2Z&r@-s+{Q}&|!Z;>tsj_7v2G3 zOv8HH91L$p;-;ApRFhDofcN}bF`oi6k>V8v1?^A*jOWTMA9_~pX?Q&0ao^0^H=YUY zthOavnG)Ps^mJsa=;k^H)i@(v3NmH5Fa;^^HN-OOpknGV6otB-P~(l*+~C=hrTWq7 zcX+b!fp6#-(a|^+BJbQFZlir2h0O!vZOReN`WrJntFdv^FE0MIr_K&Eq1*O9~JvYE~j~ z9eH4f>&w+CWy+a|N^Gr!Qg1UdFV$spwzHj(0%TjA${z|(L-T5-klVOXZxlmK zx(TC6CQ`!|LhdPf~%c#u~})o5$XO53sFdO1g6Tp}|M^)|Ir zmLOCW)BcN8Pe(=VXKXzixGn?i4QZJO`S}TQL}1xC}x6Wc0+&d z%&t^_FAvqvxKS1{)YFHo4q-Jy4DFWvOWiDCw$BYAq3M{rmy;KA`XUESVLpzU6je4T zkb~Kvgqxn8^x9Izj92RMh+wouyGN*Ih)icgC*?~MqMOu^zDZQfX22O~ProcYOIDhu z=SdZNDNhY-R`aCdKvzPV15&3NWM&g>bcW%oDO%ab zp~q<(-}GbzVOv5D8vks#xt5-m!A7;6+AMXlzbUy(nEj26{lu-#*o_W+nR=_KmY80m zuQx(TzX}s}EW{Lqi+CYRWyx}93nDAakwSGixxb1k9d|-$oUGZwNP4TqbDa3ZdtXexccQbOg4d zTl0W#j`NO`6fG*K@&p!keUpTLsfW<$;&C2C=Q=lp?++FMX4v%G8p3dGq#2gct0C;@ z37#m%N)e0`qv)$x;V;rG8ALiCNb6&Tm6Ey%mr*%LU#_JGHlO6-{}?EJJVJWnC;@I9 z=3ipqPQ>{*F`WLraUt^JScq@!SN&90Q+BQM{3oI7oaFj`|>^yAjsIsGzqX zrG0Sb7UN8wr8lkUCiY7Cx%fzln~jUK<)%sdn?63lV}w*wuhF8%6XncCwx<-QgtHSH zBzHMVBx4rKtB=-$vQF|O8hMg?)5?!g3>Q0zTC;c}5>X6sF2a{ip5)dW2wIx5G`pI| zlae5OuO|ZLLn+fWbY=yrl_pw+@3qO3#@`boScq}@y6J+Q;}m;%GqFPpbJ3XR8!Ju2 zFe&CN5W3qc+KPXJHitLU=EjH1m6>MYlw%csRNBpywM)P2loCc5GNrN;GSiPn1iN-* z$h9TYZ=W+J!l!tp+%B{Xc^75jOH@ZTSjwEgR5yw)iRoE z8O^nf=6;uKbUU=B}T;meHK$ zf5~Vrp8{;cm*@ATSeuw>te&jcf~Ak()4ZL0358DBuoh)M&BNr7FVXGF6%5od>YQkq zZp_Qj`^$y3M=ZLt`2aJ?nDdy4dHhM3=b3BFLCA@XBKYK}bTTM3j&iA6sK5@HP>Xh^jk^pzEBC)7wRg9a@Da=lUyMg_ViE z$c&uKkP|!s^zLbF6f*{^k=?{B3P=!#>D&n(q+`I{SYy9Na z%(2cedE9_=Uwrj$9?d9W4`$8r!j2L!0y!HAMgh5sdk5SsKx6ibKE{rl$<8yheh<&3 z)zKo0lH)`)CG`+}ZkXmXJ;bqej-4PfO#-e0RG@)Yzy-L1*1#Re>pb9kf;PYkynr|G zqx8var?M1>`gfC=3oES_Yn3Pt@A_(yi+y|hcr-=t6VDn8(R5~?cvtxvr|J1BfxSQi zlYOhya0=Vc$FqU7bU*LsHs)=)0BXEpL^&Nqd&>MHZ&#Wuq8&TJ{TbeG_*m^kQxEVl zt(@Bn_1_*8xAdXY(bzUvmmt1iTWf3aF3G;$;&$@vC0umR-eNZbUxAg-KSs>cyWb*~ zGrjf=p5&(|d5A0)a2!*3KmLu0n&;*S<-U52r$~0Avfg4GdCF&CzGF3`vV1HHe&vA~ z&cp45rykc%)Cnq%7R7qfZ6b+brbD6iHqn>P2Z{Z3@G(3eXUu3DkdY6O0Q?wo*yB@M&3KZ&_f+uv6j}dz}~XJ{xdJI`{>8Q#IE*^2@i~}$i#}~sv)ojeb*>oFh|^? zM9NGTnx0&))U=}HjjA_g`(eAm%uxu8-K`uIrFV#IJ-b>d7gU=i?7IDV#V*KNro`!S zwMre{ADSQ%^n_QHHyF))6?UiZYlxW&Yq|G-YE567}mip5wj$=3R$m6{5KeODQM&1jR`IPt;_tYQyNLeUc^DH*Z55!t}(&w=v zuyM!5|F5Z|kY)@1jjQ<0rjDrOE5%3mu2;Td0$XPO=j;h+H3dWMR7;|M<&+{g`JUjL z9Mmc8IDd%^U2prq z&$9pExmGt^!M}FbLA|)q#kySX=M{0P^5gYzI{%;;O|gqHpq-kat`$v7}fW$=XSaqjOKGnm%=ax|VG{X2aOtyPGmVA23LL zo>A8i&Nd>o^-94sB(21rWtmT*F(w!BwwA{u zUQ|3uiPR%=RXopou{vHqx?WH(8SG3ANewCv_4_7 zx~V*u5r_g9#vLqrGHhBwo=94jn;Um14{C_~|3ZOH^_Y5ArQ+jI zi?}MKj#K4gVb!hADfkeU^^ZJ~aM+sSYLw@wcBzQfW7nuh1;y{s`s#g)wO3fhTD7$! z`5kqgkvO=z!*8XOZ(wbIM5(A+)N$>Pk_kRfllF2Xtl+^3{)=R);ZmJ9SG%RyU%d z37mo(<;Th73o&!>&v?Dbl5I(By2f=1qMnAZq^2eo9<-nXKMESGn$>MW>M?GYOm74ICwu*?OgGR>Phw;Y8a(lQiENPA>&7<;vkqk z7gev)o$6>>>Z^4v4bf`c&cejSZeV2oDLQpY%_Wz3tq&`g$9aB}3iI-2&dHvcSCn5c zapHnGhM&ANeCTw=4{DyOz?Of??d z213J!2rn050ZqacaA!W%xsJZ(J0Yo7BF z_=?nqB=23o>uy5iVK z{|%JE(+&3zf@_Ede#PIK~^dDD5c?D%+^#kghY%g87KCvr&W%$&_(YLA(~^ z|8TSDN^#s147h>Dxwjsg+jB7V5Aj8r@ePGiIs;8X`ZvbcwFYl`S>&f82K@bsdgrfL zr@%>h*`u758LE~cE3@f0qkgk7YNh659OGSa%YYl#J~vmRCdSU6ksm{cmTIByD5Az7 z3ht%(d*P)E=g(Fnb3TPO#%W*pX^qOiDi5!M84&j z8KNcWtNUm(6}=`&vvcaMs+;h7yEb8KvZe{DiPn-?nIk1;iR0*_=w%Km=jq&su*KY8 zQBG3W05zGCJ85<{h?pl!CYy(Gx`%>cJY$w8}Pof z;U?3Ou4qf`Yc+)iOvm>SCoIr{>GpZ5XZlDyRlWi|)Y+5d;DbYXmS}u`KM&)hbfa@B zKwl$YWuEe*t87N-Bn!R-fsfyKjnX!YER5shW7HJ7l%)E*p1}zh@F}H?T+ETA?Kqdq8`M_AJHfb7rMB z8{fV|vG${y_L`jzRcbY*9kd#K>0a#$WBFV0)kaP!`?VUfhv7eV0O#?gN;-5v>qo!Z zrn!>qI6jEpiqHyWWy8MO0!!0ZC^M+GA8f+2hZTQD)6-OM-TMqy&Pun607p`tP4C0i z!}!v}V@d_Bs^d2O)c`fogC-0UiB$8x+D;#xsO}PUE(aD;+&xMny^*Y5x_R@3?8)L3 zok|uV?#*o&VyD%E|0YAl`^WYXbSwCbYV+6t8OdUmOl`DoP)FrU)G2?E1~QIBwuLpb zs0v}hbk2qjn^w_v%^ZA%#Ef-t99>CM@1*3xsxNgOtok=uJ7s@XgRgJR+_bIoQ#Q#B zdal23F|ixBr~i3t#+yb8E%|3NX#!!=T;J^a8BLn&JVe@l_;9;?$W56vUe}m3#1Q?p z_K%VLo3Us-uCi#1SR3pK!vwx*gT_c|qu~N`q3cyil}3tb{m7*H6rtXjKbM+iIDn;p zU6aPGnMp&#gx0~mxe-sZ;-Z@Pwt~7t4?EQpQ_rVu~TmvJFsL7V`srq8t|OD->u1fxyHPK zC1W>jni{7~Q`$xA>n7irahf!Aq$57Gfk_&Tx_8xl@mGBAv1HTOJC$$`Y52$t%eQm- z(TGZ|t6OSej{Ktu*^>%$O1o;2%%7Ha!*`TN4%RBw|C1Kc>Z@%k57|XYyH2`UhF!;c zHQH5fqhV9chfRf-RHQ++;D+YZ^-QeBuz-L5Pgq=QfzhqSTDWOZ1(}wYM-fKG*;gA^ zyNb2(SJ`2$AHdYz_+o7sZ7kD5$yTMQG_YK2*Jy!#vt3T>b;9v0TfcO_lfy zIn8V_HiJf#!`{u>t8JGi8SOowb)s2Y@u!E@?bH6$^kr?+MzbBz)=GOW+BDSWS7IvT M?wyDi_F13*0`LuY{Qv*} delta 11248 zcmcIq3w%_?)!&(W@7xV}Z5}`f0hX|a$TJB61pzl9@{&h@fK;OpLV!R>!e)cKS&*v5 zs7V(0P(cl-0TC%Au-8(>75%EM7AT?uMH&#OR;ozRB1QQAbMqh|@YQ~L^ZVz_otZmx z=DhBix$D{2!E-vcJgFbIG+Z`|)LO4XLgGf6+3`Fz=uG4;2=;87{Ev%%bRBH z#s1Ivzl&9Z&)&Xl)5v0E7aizH#Lnd*CUc4e&jr@h<2ZKmg(B`x-!1 ztkU~U|V{X4prXF z{tj;vw|d=eH$QK$=C$_dy8mW9ADBT-iUXwIz}f9Eu}WK|Cy0q$DZdj_EmG1&+QrQeJeWI>)s2>lY^5X z(%JPArH*fFot}>`i!tIu_)+GY#2kiWEORh*=GF6!V`Z4EHh$yLTl{BPCuYm~uzX;< zWvf3rTC*{J!lS>6rFG#fnuh$7{kCSGy;ZIK5}0y%G-s{zvp`VyVVF)D-IJg>z}*-< z0D2bq9*_a-*T80=g1RqZty@Z+KL^Oi?g1SKyhXoQ!aAjfAU=GC+rxm4k#>V7fmVUO z0z3xD$0AVoIm#ITZC%1*TFU6~CGLI?JP14jjHXX8-_naH%7^|0D)8V(pj&}4D1Qtp zAN?z6H4u-wc7Pk@{lID9J76L30q_nG4kqhBp9Q453`PGK;C*wV2AVg|+olI01Y_W%=tUjX+4_W{|! z{lEjjBw#X-155#OfvG?qFb$Xv%mDI%nZPWd0FdK1q8Rscgyjy43xyKE4U__Nf%(8Z zKz3dLx)4|dEC!YUO97AYF7YQk@3^3P6Mh|AJMgTZg+7IP8L;Jbn9?fPkR3zWt4j45 z#(gR)54i>6NB}wm##)t4WtGps_^s@SQtjuwI*he2-K&xvWtF|+H^j%X7T)!V@z#xy z;qyRKlrY>OY%~ipt*5$qLomnKi|bjSV=>}I!9dqW(U z_%YrPD!oC@WqJd#4J>LY?tU@{kYior0N2>R#j+PH^n{dZLCYX+?^4$C7ypSv^ua?v z&LJ$85tQ~XcBkR&!j5-0;uo<5rv9V3D#^W=l~v!%LWW75O7;hVtxJH0`=g*;(Y+0@ z9_5t)Ls|CQj&d0K{29~+x)d}LG>V4#m6ug%*2a0iVr8^xE)S>7mOP9CPiwKpZ8O;C zQML9L>ev`L&hPMCKa80LYQ^(XJIhf%19S#Dpsfqgs$t$!sCy4^0c`;l&-@GY0x-lo zCL}82VU$(@nLs3-65i5~&IA5}yK}%g;8xV?c&;yKDxjeJZ`2O~+TwmA=s$o6)XSK* z&wD7ObA?A8*&3B;sCW_dAwVubGCTrx(SW?q0F^nwNYM0#x+M*L_cT!1uN77JSO>2kV+*v|GDsWWy~1=A!It6+_&S-Q(76JhX`PJ$X93M7 zo6XCJ&sS5aZWKIZ)Is(Lvpp7ko|jKLF>u!LOZG|Cd;7~wq-E!E*lkR~#s~JFgKQ_y z(!-LAP03XM&bqz>BEEmD|I<6e*qm_cxQQ*djTz+}n2|R6>*VE+S+=~KzssoI#745} zS6K_+0%kYtvAm8|zs;h(o=>H4_z_lp7*^PxbGDq8&0s}F@ljSD!DdjJhh-6NqK$k% zBUWwaoW`uuIvbtOu|t}fLY+FwXvzT|Ys6k;r|8IPM(;&q?PwC+NU40Bg%&z(DZmUtJA%DPTO7i!N%{^ z;Rj8v8oSC^I;-x(WBoO(C9}o18yopr?K|B*{_CvqU$mRtkc9TFW%tq}XPJYHS~kqT zn+;>ONo<7wUd#B+3yS{wPVL-xR@A4fv)^J~S{B7x(wPI$bMGvED%w_A_42x-D}P^O zpZwm2xSWcI%$Zpxu`sxhC!c#%Q~D>D=T7UpZrg1$_pZwQ`0cm5HJ5%dxBj2+2`^Us zBi|E*_e25jUB8#F@OXR=b2odIN+0HXq}Q;uRQd=XZIx=hqq*=y*5Ix&7pj~B6JEgg zG5$XqeY=n^5#K@mSvFd*h+kk+sB|%3$|f7%Eat(guaFOtTL)}MN()gvlD+}akHA(| zJZhnZMI3KMmOe)$n7?U>lXo%)gm0Vs_a%2kVtI7j!C+2TTK|1GKhQnd*CuFEW!F^1KEk zYuhm5?R4UG9*5L`)SdjGdOPH1)a~SU=HJBwjGV74(LwUCN^WK>^vWL5$sgdWCdPa% z&q1!aUY)ll+}n{y8-W-lJAx9|C^nwip8Bm(3hC{hYJcj}Rk0bie(D)UyKYkuXeX$Z zh^A+GiV^*|Hk?u54W4Ku?hzAN*m_JDj0r%5CE7b@a5Rz}lhW2w{m!7QJmiwumXZ$) z=GHEE_bpRrP~95UY81bqm1|Tyh_$E8Ls}R;F%rRS_-5@$oKf=!?Qk^A$`c|*b+!4> zKMfYM&68Rml^c^dbZd&rMd0RoQ5l<(4P{3)4rQ!j=Ezd$at5lZRVLFaKTD*f8E;Rz-r7Ym^d66Mw1289kP(`xS~m3Dd0`ufCWVZ<)^IPPS5LX>yXNLR{{z^^jV<-Iz8?JRMANHCij9l}r3x^VU6% z*U%DCr%>Q?t-aBHg*YBW1OEzPj;a%z>C^$y&38-;SMIQ+(ZB1&7&>@N45SNnaM`n~ zwFD#K32|7Xq+?k87L`X*;&IXMwv^P=l%({&$=&-5%IMoYHRG;c-TS6xWOPp%oHFRP zyQBi-H6o|9Fn30tE4#5k6(>cjh=RuIX+^Ht$vtvQC~#b4wMibF-X}eM@uJ4gS3MO) z&QFDhGS+A*6f+-+^2`%`jH*>)a$B#{ljwUxv@!O9MA@0%y1q?x{|X!S2UqiCNP1?z^5hRQ?8 zMq5mg1Ex^jexY)BlzG$d&mxXq{IiImC;p(dr#I&6<0<_^1gb3`iWc>z7WR?ovH_+R zHarXIm(0LgSbQv_UlRTn-dq7U6=kcIO$sQ^$(@xmJ#ThSVa{|~`nl-tT=O$eAQlaV z($~_u(_$)J{zCM1KKWD3XuGl`SJ8A=&TLxtx#;Sw{3*r`YZ}|MS99e0Wvr=RM$rjz zyYum%YbyHUq{y@7yYpt3WXu1>uDoeEQ%o+{YLkH$#jc{_JeNB^ucW@(XI5KF^4#wH z!s+#u}(CT?Zdo&P4wSZ59wH9My`yTt7(&2^W$@|rJm zgW29DcSepYC)b_lD#@N%G{yYa(Cf{=i@xk;i&3qXj4MXh&j?%;9!`Cq(8sotfvWLJ zLLmgm@X8q{j)Di{2y)+@QGajO$?g2PolkAioXN6?My@24Tv;e^MvRZhE-9T-QtFzP zlbe@4y-7Qobx6)^bAz4o)LId`!=ned$dl2vBaPWA+GuEoBDZ}j+NkB&k9pI&FNGbL zS6o2m*EljgBl53rX0wACAao~V-OQ0~vZ*BdN(Xb2R`)dwjxPj(`6%B8 zWSE-l%qGf%04ME9Q(}xmR(%7biqFJAJ|oA6>Q*;Uvh?V%kl{sBn%L+q=Z}rKVissD z$!_XV&xbteufMtl3Q>>;IT@yfX8L0o!vT|Ir65I#u_h|;^1)&o(EAmOc_Ns zt7+hdmUdvnDNwA~jaz%`t(l{t-V$SBcx82OytQ--+=+4lkYV~=wh`!~dsyp68^|px zbmtYif9Qv{@RI!Lg*gQ>YLxVtH@kqA_1A~U7fI8Fxw7j8ur^JJqx<{n&znoVz7+&F zvjUp)wP<$()lX>}-xerFS@NH8{a6(qn%NY*Agu&bS}m^BnL6}#;?cZ8XTDa<*#`2F zUpnirGjG(OAdhA;ZWaPsMvX%-EXd0=!`w)OIm~yvIbU1p8{_gyO7e>ev#;qzb54uc zHZ2?G!so|;Jdur-v#mqOM}nvaXv|5GbHnfzA33fus5Mz`&%63%k85({d9>^WHjQja z$RFnq(1!#!Ya>r8kEU&__1F$gJj4Z3QN9I`VFAK0FN)~R6RnN87p3*){b=`bF_z}k zi1u{%4&>0tp#mEMpX!{}M`FuT{wXrOvFAl0dD5|p{SMxPzC14~eVjYV^PLFz6z<#* zct%$YXCm@eUx=Q757f)T^{&R)5PggCL$~M}`a|QlHX6UF%m{g`R)0AHqfr=0N52uL z$2T%=fx*k5EbTPoXM3wASY;j}!()f5RMC`lW}EFM$K%Jl6fxhb0dD6 zcck(!MceU>$Ew)21!BOo9mx2(Gtqi6$2RB2WV=a>$v2Sqjh|?ecT*wb#@TJcRa>T; zXYAKcZ@b7iDU)3YyW@?RZAgdZd;dxR0e_Kzj2_J*h%qTve}x&&HM&QW4)0_Qc~bg% z;io=b#PIqP{3{6tdAgvNnM=^wFg}^=T}51QfhFIf){B5T3axK_w%`xZxiGj*zZC3` z)UCFlchN;U`MX9$y#AF={C=DlR3(ZkI`W);LNaiX2fMJ-Y8)#EW6`-=6&rp;q*7Km z?-nG3hCD(xGl7mYxi=S7+*R0E0lhhqXZyBjHt)=ZQT{G^y2>&rCrjx~Rj0Jb&}=*; zmo8~4{W(PMieCz)#p`X_4Z;3Se(Orc*RCt&M9Zz{sZvBseLlGc=%a}B=51(yD({@} z6aAzr2H%U^+dN6ke=qki+h?P1iyV1z)|2-P-SD0vLhhpSG(Cx>$`@9{Lbqnn0^3%v8x=xQC)Y}>lEEnsUKTbbrrOn~`gi!fXkc*Wxrhc)D%*9fcO^+qVM>up_ z8Lzj1v|aeAjLXu^VyB!i9;MhVd6X8Xe?n(I!MRSxE&3&MNITiWv_3)d{8NtGiJ-xr zY$c6etF$IZm=hbb$V;+q2T-mD{nAJLSxripu-*kss?8