From 94e34c0ed9bab3bfc5ba61272d2593bd9fe49832 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sun, 14 Feb 2016 19:05:03 +0200 Subject: [PATCH] Molochs can damage characters, server log UI, stun weapons have a longer stun time, characters can't breathe when wearing a diving suit with no oxygen tank --- .../Content/Characters/Moloch/moloch.xml | 2 +- .../Content/Items/Diving/divinggear.xml | 6 +- Subsurface/Content/Items/Weapons/weapons.xml | 6 +- .../Source/Characters/AI/EnemyAIController.cs | 11 ++- Subsurface/Source/Characters/Character.cs | 8 +- Subsurface/Source/Events/Quests/Quest.cs | 2 +- .../Source/GameSession/GameModes/QuestMode.cs | 4 +- Subsurface/Source/Items/CharacterInventory.cs | 4 +- .../Items/Components/Holdable/Holdable.cs | 4 +- .../Source/Items/Components/Machines/Pump.cs | 4 +- .../Items/Components/Machines/Reactor.cs | 8 +- .../Components/Signal/ConnectionPanel.cs | 4 +- Subsurface/Source/Items/Item.cs | 2 +- Subsurface/Source/Networking/GameServer.cs | 83 ++++++++++++------ .../Source/Networking/GameServerSettings.cs | 3 +- Subsurface/Source/Networking/NetworkMember.cs | 4 +- Subsurface/Source/Networking/ServerLog.cs | 49 +++++++++-- Subsurface_Solution.v12.suo | Bin 846336 -> 846336 bytes 18 files changed, 136 insertions(+), 68 deletions(-) diff --git a/Subsurface/Content/Characters/Moloch/moloch.xml b/Subsurface/Content/Characters/Moloch/moloch.xml index 17f78f8f3..765e02224 100644 --- a/Subsurface/Content/Characters/Moloch/moloch.xml +++ b/Subsurface/Content/Characters/Moloch/moloch.xml @@ -11,7 +11,7 @@ - + diff --git a/Subsurface/Content/Items/Diving/divinggear.xml b/Subsurface/Content/Items/Diving/divinggear.xml index fda2d77d4..804ede07f 100644 --- a/Subsurface/Content/Items/Diving/divinggear.xml +++ b/Subsurface/Content/Items/Diving/divinggear.xml @@ -86,12 +86,10 @@ - + - - - + diff --git a/Subsurface/Content/Items/Weapons/weapons.xml b/Subsurface/Content/Items/Weapons/weapons.xml index 97cf6e072..6a2794628 100644 --- a/Subsurface/Content/Items/Weapons/weapons.xml +++ b/Subsurface/Content/Items/Weapons/weapons.xml @@ -66,7 +66,7 @@ - + @@ -109,11 +109,11 @@ - + - + diff --git a/Subsurface/Source/Characters/AI/EnemyAIController.cs b/Subsurface/Source/Characters/AI/EnemyAIController.cs index 0a14ac5bc..233f6e223 100644 --- a/Subsurface/Source/Characters/AI/EnemyAIController.cs +++ b/Subsurface/Source/Characters/AI/EnemyAIController.cs @@ -311,6 +311,8 @@ namespace Barotrauma { IDamageable damageTarget = null; + float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(limb.SimPosition, attackPosition)); + switch (limb.attack.Type) { case AttackType.PinchCW: @@ -328,7 +330,6 @@ namespace Barotrauma break; } - float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(limb.SimPosition, attackPosition)); if (dist < limb.attack.Range * 0.5f) { attackTimer += deltaTime; @@ -361,10 +362,16 @@ namespace Barotrauma break; } - if (ConvertUnits.ToDisplayUnits(Vector2.Distance(limb.SimPosition, attackPosition)) < limb.attack.Range) + + if (dist < limb.attack.Range) { attackTimer += deltaTime; limb.body.ApplyForce(limb.Mass * limb.attack.Force * Vector2.Normalize(attackPosition - limb.SimPosition)); + + if (damageTarget is Character && dist c.Connection == message.SenderConnection); if (sender != null) { - Networking.GameServer.Log("Pump settings adjusted by " + sender.name); - Networking.GameServer.Log("Active: " + (IsActive ? "yes" : "no ") + " Pumping speed: " + (int)flowPercentage + " %"); + Networking.GameServer.Log("Pump settings adjusted by " + sender.name, Color.Orange); + Networking.GameServer.Log("Active: " + (IsActive ? "yes" : "no ") + " Pumping speed: " + (int)flowPercentage + " %", Color.Orange); } } } diff --git a/Subsurface/Source/Items/Components/Machines/Reactor.cs b/Subsurface/Source/Items/Components/Machines/Reactor.cs index 51f610e27..a0845745d 100644 --- a/Subsurface/Source/Items/Components/Machines/Reactor.cs +++ b/Subsurface/Source/Items/Components/Machines/Reactor.cs @@ -226,7 +226,7 @@ namespace Barotrauma.Items.Components fissionRate = Math.Min(fissionRate, AvailableFuel); float heat = 100 * fissionRate * (AvailableFuel/2000.0f); - float heatDissipation = 50 * coolingRate + ExtraCooling; + float heatDissipation = 50 * coolingRate + Math.Max(ExtraCooling, 5.0f); float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f; Temperature = temperature + deltaTemp; @@ -362,7 +362,7 @@ namespace Barotrauma.Items.Components { if (item.Condition <= 0.0f) return; - GameServer.Log("Reactor meltdown!"); + GameServer.Log("Reactor meltdown!", Color.Red); new RepairTask(item, 60.0f, "Reactor meltdown!"); item.Condition = 0.0f; @@ -583,8 +583,8 @@ namespace Barotrauma.Items.Components var sender = GameMain.Server.ConnectedClients.Find(c => c.Connection == message.SenderConnection); if (sender != null) { - Networking.GameServer.Log("Reactor settings adjusted by " + sender.name); - Networking.GameServer.Log("Autotemp: " +(autoTemp ? "ON " : "OFF") + " Shutdown temp: "+shutDownTemp+" Cooling rate: "+coolingRate+" Fission rate: "+fissionRate); + Networking.GameServer.Log("Reactor settings adjusted by " + sender.name+": ", Color.Orange); + Networking.GameServer.Log("Autotemp: " +(autoTemp ? "ON " : "OFF") + " Shutdown temp: "+shutDownTemp+" Cooling rate: "+(int)coolingRate+" Fission rate: "+(int)fissionRate, Color.Orange); } } diff --git a/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs b/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs index 5e0f15b23..b22bfa69c 100644 --- a/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs +++ b/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs @@ -146,7 +146,7 @@ namespace Barotrauma.Items.Components var sender = GameMain.Server.ConnectedClients.Find(c => c.Connection == message.SenderConnection); if (sender != null) { - Networking.GameServer.Log(item.Name + " rewired by " + sender.name); + Networking.GameServer.Log(item.Name + " rewired by " + sender.name, Color.Orange); } } @@ -172,7 +172,7 @@ namespace Barotrauma.Items.Components wireComponent.Connect(c, false); var otherConnection = c.Wires[i].OtherConnection(c); - Networking.GameServer.Log(c.Name + " -> " + (otherConnection == null ? "none" : otherConnection.Name)); + Networking.GameServer.Log(c.Name + " -> " + (otherConnection == null ? "none" : otherConnection.Name), Color.Orange); } c.UpdateRecipients(); } diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index ebc309689..494816aa1 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -1125,7 +1125,7 @@ namespace Barotrauma // new NetworkEvent(NetworkEventType.DropItem, ID, true); - if (dropper != null) GameServer.Log(dropper.Name + " dropped " + Name); + if (dropper != null) GameServer.Log(dropper.Name + " dropped " + Name, Color.Orange); foreach (ItemComponent ic in components) ic.Drop(dropper); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 89982fd94..d4b9647db 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -33,18 +33,12 @@ namespace Barotrauma.Networking private bool masterServerResponded; private ServerLog log; + private GUIButton showLogButton; public TraitorManager TraitorManager; public GameServer(string name, int port, bool isPublic = false, string password = "", bool attemptUPnP = false, int maxPlayers = 10) { - var endRoundButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 170, 20, 150, 25), "End round", Alignment.TopLeft, GUI.Style, inGameHUD); - endRoundButton.OnClicked = EndButtonHit; - - banList = new BanList(); - - log = new ServerLog(name); - this.name = name; this.password = password; @@ -74,6 +68,31 @@ namespace Barotrauma.Networking NetIncomingMessageType.UnconnectedData); config.EnableMessageType(NetIncomingMessageType.ConnectionApproval); + + //---------------------------------------- + + var endRoundButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 170, 20, 150, 20), "End round", Alignment.TopLeft, GUI.Style, inGameHUD); + endRoundButton.OnClicked = EndButtonHit; + + log = new ServerLog(name); + showLogButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 170 - 170, 20, 150, 20), "Server Log", Alignment.TopLeft, GUI.Style, inGameHUD); + showLogButton.OnClicked = (GUIButton button, object userData) => + { + if (log.LogFrame == null) + { + log.CreateLogFrame(); + } + else + { + log.LogFrame = null; + } + return true; + }; + + banList = new BanList(); + + //---------------------------------------- + CoroutineManager.StartCoroutine(StartServer(isPublic)); } @@ -82,14 +101,14 @@ namespace Barotrauma.Networking { try { - Log("Starting the server..."); + Log("Starting the server...", Color.Cyan); server = new NetServer(config); netPeer = server; server.Start(); } catch (Exception e) { - Log("Error while starting the server ("+e.Message+")"); + Log("Error while starting the server ("+e.Message+")", Color.Red); DebugConsole.ThrowError("Couldn't start the server", e); } @@ -173,7 +192,7 @@ namespace Barotrauma.Networking request.AddParameter("gamestarted", gameStarted ? 1 : 0); request.AddParameter("playercount", PlayerCountToByte(ConnectedClients.Count, config.MaximumConnections)); - Log("Refreshing connection with master server..."); + Log("Refreshing connection with master server...", Color.Cyan); var sw = new Stopwatch(); sw.Start(); @@ -189,7 +208,7 @@ namespace Barotrauma.Networking restRequestHandle.Abort(); DebugConsole.NewMessage("Couldn't connect to master server (request timed out)", Color.Red); - Log("Couldn't connect to master server (request timed out)"); + Log("Couldn't connect to master server (request timed out)", Color.Red); break; //registeredToMaster = false; @@ -210,24 +229,25 @@ namespace Barotrauma.Networking if (response.ErrorException != null) { DebugConsole.NewMessage("Error while registering to master server (" + response.ErrorException + ")", Color.Red); - Log("Error while registering to master server (" + response.ErrorException + ")"); + Log("Error while registering to master server (" + response.ErrorException + ")", Color.Red); return; } if (response.StatusCode != System.Net.HttpStatusCode.OK) { DebugConsole.NewMessage("Error while reporting to master server (" + response.StatusCode + ": " + response.StatusDescription + ")", Color.Red); - Log("Error while reporting to master server (" + response.StatusCode + ": " + response.StatusDescription + ")"); + Log("Error while reporting to master server (" + response.StatusCode + ": " + response.StatusDescription + ")", Color.Red); return; } - Log("Master server responded"); + Log("Master server responded", Color.Cyan); } public override void Update(float deltaTime) { if (ShowNetStats) netStats.Update(deltaTime); if (settingsFrame != null) settingsFrame.Update(deltaTime); + if (log.LogFrame != null) log.LogFrame.Update(deltaTime); if (!started) return; @@ -248,11 +268,11 @@ namespace Barotrauma.Networking { if (AutoRestart && isCrewDead) { - Log("Ending round (entire crew dead)"); + Log("Ending round (entire crew dead)", Color.Cyan); } else { - Log("Ending round (submarine reached the end of the level)"); + Log("Ending round (submarine reached the end of the level)", Color.Cyan); } EndButtonHit(null, null); @@ -499,7 +519,7 @@ namespace Barotrauma.Networking if (Voting.AllowEndVoting && EndVoteMax > 0 && ((float)EndVoteCount / (float)EndVoteMax) >= EndVoteRequiredRatio) { - Log("Ending round by votes ("+EndVoteCount+"/"+(EndVoteMax-EndVoteCount)+")"); + Log("Ending round by votes ("+EndVoteCount+"/"+(EndVoteMax-EndVoteCount)+")", Color.Cyan); EndButtonHit(null,null); } break; @@ -791,10 +811,10 @@ namespace Barotrauma.Networking GameMain.GameSession = new GameSession(selectedSub, "", selectedMode); GameMain.GameSession.StartShift(GameMain.NetLobbyScreen.LevelSeed); - GameServer.Log("Starting a new round..."); - GameServer.Log("Submarine: " + selectedSub.Name); - GameServer.Log("Game mode: " + selectedMode.Name); - GameServer.Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed); + GameServer.Log("Starting a new round...", Color.Cyan); + GameServer.Log("Submarine: " + selectedSub.Name, Color.Cyan); + GameServer.Log("Game mode: " + selectedMode.Name, Color.Cyan); + GameServer.Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, Color.Cyan); yield return CoroutineStatus.Running; @@ -1007,7 +1027,7 @@ namespace Barotrauma.Networking if (string.IsNullOrWhiteSpace(msg)) msg = client.name + " has left the server"; if (string.IsNullOrWhiteSpace(targetmsg)) targetmsg = "You have left the server"; - Log(msg); + Log(msg, messageColor[(int)ChatMessageType.Server]); NetOutgoingMessage outmsg = server.CreateMessage(); outmsg.Write((byte)PacketTypes.KickedOut); @@ -1115,7 +1135,7 @@ namespace Barotrauma.Networking return; } - Log(traitor.Info.Name + " is the traitor and the target is " + target.Info.Name); + Log(traitor.Info.Name + " is the traitor and the target is " + target.Info.Name, Color.Cyan); Client traitorClient = null; foreach (Client c in ConnectedClients) @@ -1138,7 +1158,14 @@ namespace Barotrauma.Networking { base.Draw(spriteBatch); - if (settingsFrame != null) settingsFrame.Draw(spriteBatch); + if (settingsFrame != null) + { + settingsFrame.Draw(spriteBatch); + } + else if (log.LogFrame!=null) + { + log.LogFrame.Draw(spriteBatch); + } if (!ShowNetStats) return; @@ -1428,11 +1455,11 @@ namespace Barotrauma.Networking return preferredClient; } - public static void Log(string line) + public static void Log(string line, Color? color) { - if (GameMain.Server == null || GameMain.Server.saveServerLogs) return; + if (GameMain.Server == null || !GameMain.Server.saveServerLogs) return; - GameMain.Server.log.WriteLine(line); + GameMain.Server.log.WriteLine(line, color); } /// @@ -1478,7 +1505,7 @@ namespace Barotrauma.Networking if (saveServerLogs) { - Log("Shutting down server..."); + Log("Shutting down server...", Color.Cyan); log.Save(); } diff --git a/Subsurface/Source/Networking/GameServerSettings.cs b/Subsurface/Source/Networking/GameServerSettings.cs index 4a1af6c77..e945fe803 100644 --- a/Subsurface/Source/Networking/GameServerSettings.cs +++ b/Subsurface/Source/Networking/GameServerSettings.cs @@ -167,8 +167,9 @@ namespace Barotrauma.Networking saveLogsBox.OnSelected = (GUITickBox) => { saveServerLogs = GUITickBox.Selected; + showLogButton.Visible = saveServerLogs; return true; - }; ; + }; var closeButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Close", Alignment.BottomRight, GUI.Style, innerFrame); closeButton.OnClicked = ToggleSettingsFrame; diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index 1c6916fe7..cb1b2c633 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -59,7 +59,7 @@ namespace Barotrauma.Networking protected GUIFrame inGameHUD; protected GUIListBox chatBox; protected GUITextBox chatMsgBox; - + public int EndVoteCount, EndVoteMax; //private GUITextBlock endVoteText; @@ -186,7 +186,7 @@ namespace Barotrauma.Networking { GameMain.NetLobbyScreen.NewChatMessage(message, messageColor[(int)messageType]); - GameServer.Log(message); + GameServer.Log(message, messageColor[(int)messageType]); while (chatBox.CountChildren > 20) { diff --git a/Subsurface/Source/Networking/ServerLog.cs b/Subsurface/Source/Networking/ServerLog.cs index 7d1c5cb7b..dc9a8881d 100644 --- a/Subsurface/Source/Networking/ServerLog.cs +++ b/Subsurface/Source/Networking/ServerLog.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Xna.Framework; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -14,20 +15,24 @@ namespace Barotrauma.Networking private string serverName; - private Queue lines; + public GUIFrame LogFrame; + + private Queue lines; public ServerLog(string serverName) { this.serverName = serverName; - lines = new Queue(); + lines = new Queue(); } - public void WriteLine(string line) + public void WriteLine(string line, Color? color) { string logLine = "[" + DateTime.Now.ToLongTimeString() + "] " + line; - lines.Enqueue(logLine); + lines.Enqueue(new ColoredText(logLine, color == null ? Color.White : (Color)color)); + + if (LogFrame != null) CreateLogFrame(); if (lines.Count>=LinesPerFile) { @@ -35,6 +40,36 @@ namespace Barotrauma.Networking } } + public void CreateLogFrame() + { + LogFrame = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.5f); + + GUIFrame innerFrame = new GUIFrame(new Rectangle(0,0,400, 400), null, Alignment.Center, GUI.Style, LogFrame); + innerFrame.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f); + + GUIListBox listBox = new GUIListBox(new Rectangle(0,0,0,355), GUI.Style, innerFrame); + + var currLines = lines.ToList(); + + foreach (ColoredText line in currLines) + { + var textBlock = new GUITextBlock(new Rectangle(0, 0, 0, 0), line.Text, GUI.Style, Alignment.TopLeft, Alignment.TopLeft, listBox, true, GUI.SmallFont); + //textBlock.Rect = new Rectangle(textBlock.Rect.X, textBlock.Rect.Y, textBlock.Rect.Width, (line.Text.Count(c => c == '\n') + 1) * 15); + + textBlock.TextColor = line.Color; + textBlock.CanBeFocused = false; + } + + listBox.BarScroll = 1.0f; + + GUIButton closeButton = new GUIButton(new Rectangle(0,0,100, 15), "Close", Alignment.BottomRight, GUI.Style, innerFrame); + closeButton.OnClicked = (GUIButton button, object userData) => + { + LogFrame = null; + return true; + }; + } + public void Save() { if (!Directory.Exists(SavePath)) @@ -55,10 +90,10 @@ namespace Barotrauma.Networking fileName = fileName.Replace(":", ""); string filePath = Path.Combine(SavePath, fileName); - + try { - File.WriteAllLines(filePath, lines); + File.WriteAllLines(filePath, lines.Select(l => l.Text)); } catch (Exception e) { diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 0bdc51fffdedab324a10066fb3b3604231c05ef2..24f2594e4a96c781b48a950c90db38ff7fd574ba 100644 GIT binary patch delta 4772 zcmdUx3shBA8prQ`+$SIxydWT4uNM?VM8HSt2=Xvr5g?hOV!rZ4gqqI)<*HF;TF8OB z$!x;1L#3H;)#KzNd_PjtatIBP%B9wr;}R>T7@7Y8nq{q~)lAK-HFvGw`hWY|-`@M% z&wCu_`#8?`DT*SR_0gSuiAJO80`#C9g-5AIlT0e7nW*-bZs@q-uKBcun6>b30l|p+ zdrM1;rWw@Ru%WU(jlbX9Xm==Ia_spqj(Os3-$Sq2-5sRQp%wGoAchD%JK3`o)o5myE$W zXD-dOrenonG zCG1?V5rl#f@T~_A0RgNSV<1!l)u<1Iegg8qV4#D~2dW_&(eop26n*n(2v@TbnRzrU zdOF&Nq22;Uf*I{O-+(U>m3fEQ6719oUN zn$hq(Gl<<~_pWE^LXmVaDVKKAs%IlWJef=Tv@S~w;{KP*g4BLk7NaH<$+oVDx;FGS z5fk!g_|L9P9-7^|GGo#5$1Bt0SFen;EVY}o`I|sjoZrDv%SiP61XzR~Goh70vY10c zUWUUCn&8+8UI7`PCsz6)Xug_4rg^aYH5gCAaTimOHk)nf9*9VX<0d!?hJ$B78T^ld zx6vR2S`6Pxa0cvzZymX<7vFwxeh%j;a1{27(6vO$ z^0JdN(mJm{kk6zOUcuh#zJ8DDe(2K%eOoInKhj;2s{^Dsi_SGPaqqMLg{e~yDjhY) zSk+CvcQ*dW=C{m7?eE945qHnA?yitC&0Q;O>4ds$w;MW1j#Rs1f0W!MQu#)%gt(Jt zFUjTyD;&NGyN#F>`yh6gD7FaFK#FrhTp_2LiDdIfNEE3HYU^MEMF%z?_|izT8mny} zPBXI!n~TCZhTQdZ*>9=6%p~fd{us1BttX=DsG+~Goiq6W|UjRv!lxSj0RN{$U7N=Q@dK)XqUryNIVaTt0$NiKI*ND6NuZ6Vi5 zo#(C^YNv|*J5rzEjN>E3_ir+b$c*D*Btj{S<9P^u4!s>GbwoUI#WYqK8&BVAUzWkh z5bbSLv1QT*4|Iw_ns_~N4kb3J{5#C7n%5CIhq}wYjLP}cSKfwvr|vMuDzPQ>koG4- zelMoR@s3Ja9G^|(jnrFSj_B$PI!Tlt)LWIj?eytx3dzQQQ*j>*RZHu;$~PD#xgx=r z#E4r5O?^d5fzG1jHPb?^yn#}gGxvhMI4b*bV246`Sod~VMKhd7v#At~` z;Wh$Npo5@OprW=n36s4UFV4a0A7+<{Li||kX+k-W)f08YioeErv9da&oQ*vXXF6ez zG$bp@?tBLkpM?_Z`f`&J7Q!-&QWEja*katL@4RX7$=%+&OjK zes1S(V=BMf&Z);k+_Q5X?%laOji`wvqkd`M)FglFzNvlu4*NEg*`1@fy~3W&sbZha z>Y03oQZavkAxH_zVV?)f0k}#l#fl3oNfhnV`HB5i`VhrY!W=&G8cxONefmyf%5jrf z3Ej#ruwCW6n&@Nx+HFwI9e45R9^xbFHt`U-igEIkNLa%riPUTs<{8od#?{05wVSuD ze!s%%MOAE>e!Nais26ac> zFlZN)V?Z3x0}d#774>!aP}01LpgG_KNJd2!^bn}TBX%Fk7O}}hIu*Qu_}Ae6BM5|h zIZ*HI*YFRA?S%S3pMu6hzk_nbs>j9ydJcRIl2HBz>aE&{c^w)9!r(s%odsrqktn|e z9Rn>UngY!n80saR27MY8ZqRw47r2Y^5YQ8(gXQ1~$N-a3KO5}Ce7vBGz-IVoLDwJw zwa>FC7lIM+RUs}5x({WwuI(4v(vk_MT8M6Mw5nZIUt@dlc|q{s>h(f>YE{pkW1bE?2BR@%Z7n4|WfHLrl#i7UiQT){8jLQ2e(~#O2H3 zb#CJ60_rI|xAFz%bsiXpCXc*V z-YE_Kwr8)vwwRX!`3yoH6$!K45|l&--)|HNCCp#=dvm*a^pUG&*Ie2AdMry!cs4fe zbn8o_O!4OBL|)4cWU+d?$2y6dO<8i4JxiQ1%%B*YyvZoM`&wnHR>2h!kDhMd`AQe~M41RJ&x4 z-(+n4a_Em0|K|%O-HA_?4q2k5g$Y{~TNQ6$!ZCy38R?H_L^%GWz9_q4s-HH;Sc-_+ zZHQ3vF7iSm@8w)nPS*7@zn6N+wA6iq-dY$u@4}&T?~6@K@dn#sxn3FnC9fb(2Tc$S z+w?Y(Hs0i}JbsW%TIWeV(VR8K>eE=XC4T*wS&t=+9@n!i`GS*t1^K_e^y+c{cQ3u# z=0Cpl>WlGvUwZZB`d61;{en}!1o7eX>n?qE`z=>z`NQw0FMz0AMQw_0Ie&qeUmiL4 zjid)AAB#Qk?)~3#(PLN$|xPd-nsN+BjbU+Ubzz9shO)=EDH+lR6Cn4^n delta 4975 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 LJ)kb|+n|2|V*yer