From d6bd9627689c5720308d05b86b9fc951bf3f0441 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Wed, 11 Sep 2013 13:53:24 -0700 Subject: [PATCH] Added in dynamic servermanager updating. Added updating of bungeeServers/servers list. Combined all bungee plugins to Mineplexer Fixed arcade bug on player quit. Fixed ServersUI page errors. --- Plugins/BuildFiles/common.xml | 16 +- .../Mineplex.Bungee.DynamicServer/plugin.yml | 4 - .../ReloadServerListCommand.java | 24 --- .../Mineplex.Bungee.LobbyBalancer/.classpath | 7 - .../.settings/org.eclipse.jdt.core.prefs | 11 - .../Mineplex.Bungee.LobbyBalancer/plugin.yml | 5 - .../ReloadLobbyServerListCommand.java | 24 --- .../.classpath | 2 + .../.externalToolBuilders/Mineplexer.launch | 17 ++ .../.settings/org.eclipse.jdt.core.prefs | 0 Plugins/Mineplex.Bungee.Mineplexer/plugin.yml | 4 + .../src/mineplex/bungee/Mineplexer.java | 33 +++ .../bungee/bungeeSigns}/BungeeSigns.java | 17 +- .../bungee/dynamicServer/DynamicServer.java | 14 +- .../bungee/lobbyBalancer/LobbyBalancer.java | 150 ++++++++------ .../bungee/playerCount}/PlayerCount.java | 73 +++++-- .../src/mineplex/bungee/updater/Updater.java | 188 ++++++++++++++++++ .../Mineplex.Bungee.PlayerCount/.classpath | 7 - .../.settings/org.eclipse.jdt.core.prefs | 11 - .../Mineplex.Bungee.PlayerCount/plugin.yml | 4 - .../ReloadPlayerCountListCommand.java | 24 --- Plugins/Mineplex.Hub/.classpath | 1 + .../mineplex/hub/server/ServerManager.java | 46 ++++- .../hub/server/ServerManagerUpdater.java | 177 +++++++++++++++++ .../src/mineplex/hub/server/ServerSorter.java | 2 +- .../mineplex/hub/server/ui/ServerNpcPage.java | 18 +- .../game/arcade/managers/GameFlagManager.java | 3 +- Website/LOCWebsite.suo | Bin 474624 -> 474624 bytes 28 files changed, 647 insertions(+), 235 deletions(-) delete mode 100644 Plugins/Mineplex.Bungee.DynamicServer/plugin.yml delete mode 100644 Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/ReloadServerListCommand.java delete mode 100644 Plugins/Mineplex.Bungee.LobbyBalancer/.classpath delete mode 100644 Plugins/Mineplex.Bungee.LobbyBalancer/.settings/org.eclipse.jdt.core.prefs delete mode 100644 Plugins/Mineplex.Bungee.LobbyBalancer/plugin.yml delete mode 100644 Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/ReloadLobbyServerListCommand.java rename Plugins/{Mineplex.Bungee.DynamicServer => Mineplex.Bungee.Mineplexer}/.classpath (68%) create mode 100644 Plugins/Mineplex.Bungee.Mineplexer/.externalToolBuilders/Mineplexer.launch rename Plugins/{Mineplex.Bungee.DynamicServer => Mineplex.Bungee.Mineplexer}/.settings/org.eclipse.jdt.core.prefs (100%) create mode 100644 Plugins/Mineplex.Bungee.Mineplexer/plugin.yml create mode 100644 Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java rename Plugins/{BungeeSigns/src/mineplex/bungee/BungeeSigns => Mineplex.Bungee.Mineplexer/src/mineplex/bungee/bungeeSigns}/BungeeSigns.java (93%) rename Plugins/{Mineplex.Bungee.DynamicServer => Mineplex.Bungee.Mineplexer}/src/mineplex/bungee/dynamicServer/DynamicServer.java (79%) rename Plugins/{Mineplex.Bungee.LobbyBalancer => Mineplex.Bungee.Mineplexer}/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java (67%) rename Plugins/{Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount => Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerCount}/PlayerCount.java (79%) create mode 100644 Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/updater/Updater.java delete mode 100644 Plugins/Mineplex.Bungee.PlayerCount/.classpath delete mode 100644 Plugins/Mineplex.Bungee.PlayerCount/.settings/org.eclipse.jdt.core.prefs delete mode 100644 Plugins/Mineplex.Bungee.PlayerCount/plugin.yml delete mode 100644 Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/ReloadPlayerCountListCommand.java create mode 100644 Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManagerUpdater.java diff --git a/Plugins/BuildFiles/common.xml b/Plugins/BuildFiles/common.xml index 13b582c81..8beee32bc 100644 --- a/Plugins/BuildFiles/common.xml +++ b/Plugins/BuildFiles/common.xml @@ -251,5 +251,19 @@ - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plugins/Mineplex.Bungee.DynamicServer/plugin.yml b/Plugins/Mineplex.Bungee.DynamicServer/plugin.yml deleted file mode 100644 index e3bb9f3ea..000000000 --- a/Plugins/Mineplex.Bungee.DynamicServer/plugin.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: DynamicServer -main: mineplex.bungee.dynamicServer.DynamicServer -version: 1 -author: defek7 diff --git a/Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/ReloadServerListCommand.java b/Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/ReloadServerListCommand.java deleted file mode 100644 index 9e69ed8e6..000000000 --- a/Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/ReloadServerListCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package mineplex.bungee.dynamicServer; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.plugin.Command; - -public class ReloadServerListCommand extends Command -{ - private DynamicServer _plugin; - - public ReloadServerListCommand(DynamicServer plugin) - { - super( "reloaddynamicserver", "bungeecord.command.reloadserverlist" ); - - _plugin = plugin; - } - - @Override - public void execute(CommandSender sender, String[] arg1) - { - _plugin.LoadServers(); - sender.sendMessage(ChatColor.BLUE + "DynamicServer>" + ChatColor.GRAY + " Reloaded server list."); - } -} diff --git a/Plugins/Mineplex.Bungee.LobbyBalancer/.classpath b/Plugins/Mineplex.Bungee.LobbyBalancer/.classpath deleted file mode 100644 index fbeb69b51..000000000 --- a/Plugins/Mineplex.Bungee.LobbyBalancer/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Plugins/Mineplex.Bungee.LobbyBalancer/.settings/org.eclipse.jdt.core.prefs b/Plugins/Mineplex.Bungee.LobbyBalancer/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 7341ab168..000000000 --- a/Plugins/Mineplex.Bungee.LobbyBalancer/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 diff --git a/Plugins/Mineplex.Bungee.LobbyBalancer/plugin.yml b/Plugins/Mineplex.Bungee.LobbyBalancer/plugin.yml deleted file mode 100644 index df2221356..000000000 --- a/Plugins/Mineplex.Bungee.LobbyBalancer/plugin.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: LobbyBalancer -main: mineplex.bungee.lobbyBalancer.LobbyBalancer -version: 1 -author: defek7 -depends: [DynamicServer] diff --git a/Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/ReloadLobbyServerListCommand.java b/Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/ReloadLobbyServerListCommand.java deleted file mode 100644 index 855e8e2f3..000000000 --- a/Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/ReloadLobbyServerListCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package mineplex.bungee.lobbyBalancer; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.plugin.Command; - -public class ReloadLobbyServerListCommand extends Command -{ - private LobbyBalancer _plugin; - - public ReloadLobbyServerListCommand(LobbyBalancer plugin) - { - super( "reloadlobbybalancer", "bungeecord.command.reloadserverlist" ); - - _plugin = plugin; - } - - @Override - public void execute(CommandSender sender, String[] arg1) - { - _plugin.loadLobbyServers(); - sender.sendMessage(ChatColor.BLUE + "LobbyBalancer>" + ChatColor.GRAY + " Reloaded lobby server list."); - } -} diff --git a/Plugins/Mineplex.Bungee.DynamicServer/.classpath b/Plugins/Mineplex.Bungee.Mineplexer/.classpath similarity index 68% rename from Plugins/Mineplex.Bungee.DynamicServer/.classpath rename to Plugins/Mineplex.Bungee.Mineplexer/.classpath index fbeb69b51..8ae052756 100644 --- a/Plugins/Mineplex.Bungee.DynamicServer/.classpath +++ b/Plugins/Mineplex.Bungee.Mineplexer/.classpath @@ -3,5 +3,7 @@ + + diff --git a/Plugins/Mineplex.Bungee.Mineplexer/.externalToolBuilders/Mineplexer.launch b/Plugins/Mineplex.Bungee.Mineplexer/.externalToolBuilders/Mineplexer.launch new file mode 100644 index 000000000..3921867d6 --- /dev/null +++ b/Plugins/Mineplex.Bungee.Mineplexer/.externalToolBuilders/Mineplexer.launch @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/Plugins/Mineplex.Bungee.DynamicServer/.settings/org.eclipse.jdt.core.prefs b/Plugins/Mineplex.Bungee.Mineplexer/.settings/org.eclipse.jdt.core.prefs similarity index 100% rename from Plugins/Mineplex.Bungee.DynamicServer/.settings/org.eclipse.jdt.core.prefs rename to Plugins/Mineplex.Bungee.Mineplexer/.settings/org.eclipse.jdt.core.prefs diff --git a/Plugins/Mineplex.Bungee.Mineplexer/plugin.yml b/Plugins/Mineplex.Bungee.Mineplexer/plugin.yml new file mode 100644 index 000000000..e2beec573 --- /dev/null +++ b/Plugins/Mineplex.Bungee.Mineplexer/plugin.yml @@ -0,0 +1,4 @@ +name: Mineplexer +main: mineplex.bungee.Mineplexer +version: 1 +author: defek7 diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java new file mode 100644 index 000000000..e0f3f26ab --- /dev/null +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java @@ -0,0 +1,33 @@ +package mineplex.bungee; + +import mineplex.bungee.bungeeSigns.BungeeSigns; +import mineplex.bungee.dynamicServer.DynamicServer; +import mineplex.bungee.lobbyBalancer.LobbyBalancer; +import mineplex.bungee.playerCount.PlayerCount; +import mineplex.bungee.updater.Updater; +import net.md_5.bungee.api.plugin.Plugin; + +public class Mineplexer extends Plugin +{ + private DynamicServer _dynamicServers; + private LobbyBalancer _lobbyBalancer; + private PlayerCount _playerCount; + + @Override + public void onEnable() + { + new BungeeSigns(this); + new Updater(this); + + _dynamicServers = new DynamicServer(this); + _lobbyBalancer = new LobbyBalancer(this); + _playerCount = new PlayerCount(this); + } + + public void ReloadServerLists() + { + _dynamicServers.LoadServers(); + _lobbyBalancer.loadLobbyServers(); + _playerCount.LoadBungeeServers(); + } +} diff --git a/Plugins/BungeeSigns/src/mineplex/bungee/BungeeSigns/BungeeSigns.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/bungeeSigns/BungeeSigns.java similarity index 93% rename from Plugins/BungeeSigns/src/mineplex/bungee/BungeeSigns/BungeeSigns.java rename to Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/bungeeSigns/BungeeSigns.java index 47d5bcbe5..0b83dc262 100644 --- a/Plugins/BungeeSigns/src/mineplex/bungee/BungeeSigns/BungeeSigns.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/bungeeSigns/BungeeSigns.java @@ -1,4 +1,4 @@ -package mineplex.bungee.BungeeSigns; +package mineplex.bungee.bungeeSigns; import java.io.ByteArrayInputStream; import java.io.DataInput; @@ -21,13 +21,16 @@ import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.protocol.packet.PacketFAPluginMessage; -public class BungeeSigns extends Plugin implements Listener +public class BungeeSigns implements Listener { - @Override - public void onEnable() + private Plugin _plugin; + + public BungeeSigns(Plugin plugin) { - getProxy().getPluginManager().registerListener(this, this); - getProxy().registerChannel("BungeeSigns"); + _plugin = plugin; + + _plugin.getProxy().getPluginManager().registerListener(_plugin, this); + _plugin.getProxy().registerChannel("BungeeSigns"); } @EventHandler @@ -40,7 +43,7 @@ public class BungeeSigns extends Plugin implements Listener try { in = new DataInputStream(new ByteArrayInputStream(event.getData())); - final ServerInfo serverInfo = getProxy().getServerInfo(in.readUTF()); + final ServerInfo serverInfo = _plugin.getProxy().getServerInfo(in.readUTF()); in.close(); diff --git a/Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/DynamicServer.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/dynamicServer/DynamicServer.java similarity index 79% rename from Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/DynamicServer.java rename to Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/dynamicServer/DynamicServer.java index c876dc0a8..6263418e8 100644 --- a/Plugins/Mineplex.Bungee.DynamicServer/src/mineplex/bungee/dynamicServer/DynamicServer.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/dynamicServer/DynamicServer.java @@ -10,15 +10,17 @@ import java.net.InetSocketAddress; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; -public class DynamicServer extends Plugin implements Listener +public class DynamicServer implements Listener { - @Override - public void onEnable() + private Plugin _plugin; + + public DynamicServer(Plugin plugin) { + _plugin = plugin; + LoadServers(); - getProxy().getPluginManager().registerListener(this, this); - getProxy().getPluginManager().registerCommand(this, new ReloadServerListCommand(this)); + _plugin.getProxy().getPluginManager().registerListener(_plugin, this); } public void LoadServers() @@ -44,7 +46,7 @@ public class DynamicServer extends Plugin implements Listener Integer port = Integer.parseInt(line.split(",")[1].split(":")[1]); InetSocketAddress socketAddress = new InetSocketAddress(address, port); - getProxy().getServers().put(name, getProxy().constructServerInfo(name, socketAddress, "DynamicServer", false)); + _plugin.getProxy().getServers().put(name, _plugin.getProxy().constructServerInfo(name, socketAddress, "DynamicServer", false)); line = br.readLine(); } } diff --git a/Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java similarity index 67% rename from Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java rename to Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java index 1acc87b23..5ba8a066c 100644 --- a/Plugins/Mineplex.Bungee.LobbyBalancer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/lobbyBalancer/LobbyBalancer.java @@ -18,19 +18,23 @@ import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.event.EventHandler; -public class LobbyBalancer extends Plugin implements Listener, Runnable +public class LobbyBalancer implements Listener, Runnable { + private Plugin _plugin; private HashMap _lobbyServers = new HashMap(); - - @Override - public void onEnable() + + private String _bestServer = "Lobby"; + + private static Object _serverLock = new Object(); + + public LobbyBalancer(Plugin plugin) { + _plugin = plugin; + loadLobbyServers(); - getProxy().getPluginManager().registerListener(this, this); - getProxy().getScheduler().schedule(this, this, 1L, 1L, TimeUnit.SECONDS); - - getProxy().getPluginManager().registerCommand(this, new ReloadLobbyServerListCommand(this)); + _plugin.getProxy().getPluginManager().registerListener(_plugin, this); + _plugin.getProxy().getScheduler().schedule(_plugin, this, 1L, 1L, TimeUnit.SECONDS); } @EventHandler @@ -39,54 +43,59 @@ public class LobbyBalancer extends Plugin implements Listener, Runnable if (!event.getTarget().getName().equalsIgnoreCase("Lobby")) return; - String bestServer = null; - Entry leastPlayerServer = null; - - for (Entry entry : _lobbyServers.entrySet()) - { - if (entry.getValue() == 999) - continue; - - if (bestServer == null) - { - bestServer = entry.getKey(); - leastPlayerServer = entry; - } - else if (entry.getValue() > _lobbyServers.get(bestServer) && entry.getValue() < 80) - bestServer = entry.getKey(); - - if (entry.getValue() < leastPlayerServer.getValue()) - { - leastPlayerServer = entry; - } - } - - if (_lobbyServers.get(bestServer) > 80) - { - bestServer = leastPlayerServer.getKey(); - } - - event.setTarget(getProxy().getServerInfo(bestServer)); + event.setTarget(_plugin.getProxy().getServerInfo(_bestServer)); } public void run() { - for (String name : _lobbyServers.keySet()) - { - try - { - UpdateServerCount(name); - } - catch (IOException e) - { - e.printStackTrace(); - } - } + synchronized (_serverLock) + { + for (String name : _lobbyServers.keySet()) + { + try + { + UpdateServerCount(name); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + String bestServer = null; + Entry leastPlayerServer = null; + + for (Entry entry : _lobbyServers.entrySet()) + { + if (entry.getValue() == 999) + continue; + + if (bestServer == null) + { + bestServer = entry.getKey(); + leastPlayerServer = entry; + } + else if (entry.getValue() > _lobbyServers.get(bestServer) && entry.getValue() < 80) + bestServer = entry.getKey(); + + if (entry.getValue() < leastPlayerServer.getValue()) + { + leastPlayerServer = entry; + } + } + + if (_lobbyServers.get(bestServer) > 80) + { + bestServer = leastPlayerServer.getKey(); + } + + _bestServer = bestServer; + } } protected void UpdateServerCount(String name) throws IOException { - InetSocketAddress address = getProxy().getServerInfo(name).getAddress(); + InetSocketAddress address = _plugin.getProxy().getServerInfo(name).getAddress(); Socket socket = null; DataInputStream dataInputStream = null; @@ -125,24 +134,36 @@ public class LobbyBalancer extends Plugin implements Listener, Runnable { var27 = var6.substring(1).split("\u0000"); - if (var27[3].contains("Restarting")) - _lobbyServers.put(name, 999); - else - _lobbyServers.put(name, Integer.parseInt(var27[4])); + synchronized (_serverLock) + { + if (var27[3].contains("Restarting")) + _lobbyServers.put(name, 999); + else + _lobbyServers.put(name, Integer.parseInt(var27[4])); + } } } catch (SocketTimeoutException e) { - _lobbyServers.put(name, 999); + synchronized (_serverLock) + { + _lobbyServers.put(name, 999); + } } catch (ConnectException e) { - _lobbyServers.put(name, 999); + synchronized (_serverLock) + { + _lobbyServers.put(name, 999); + } } catch (IOException e) { System.out.println("[LobbyBalancer IOException] Error pinging " + address.getHostString() + ":" + address.getPort()); - _lobbyServers.put(name, 999); + synchronized (_serverLock) + { + _lobbyServers.put(name, 999); + } throw e; } finally @@ -225,14 +246,17 @@ public class LobbyBalancer extends Plugin implements Listener, Runnable public void loadLobbyServers() { - _lobbyServers.clear(); + synchronized (_serverLock) + { + _lobbyServers.clear(); - for (String key : getProxy().getServers().keySet()) - { - if (key.toUpperCase().contains("LOBBY")) - { - _lobbyServers.put(key, 0); - } - } + for (String key : _plugin.getProxy().getServers().keySet()) + { + if (key.toUpperCase().contains("LOBBY")) + { + _lobbyServers.put(key, 0); + } + } + } } } diff --git a/Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/PlayerCount.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerCount/PlayerCount.java similarity index 79% rename from Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/PlayerCount.java rename to Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerCount/PlayerCount.java index b46b7ae6a..4b38f4d18 100644 --- a/Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/PlayerCount.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerCount/PlayerCount.java @@ -1,4 +1,4 @@ -package mineplex.bungee.PlayerCount; +package mineplex.bungee.playerCount; import java.io.BufferedReader; import java.io.DataInput; @@ -22,8 +22,10 @@ import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.event.EventHandler; -public class PlayerCount extends Plugin implements Listener, Runnable +public class PlayerCount implements Listener, Runnable { + private Plugin _plugin; + private HashMap _otherBungeeInstances; private int _totalPlayers; private int _totalMaxPlayers; @@ -31,38 +33,41 @@ public class PlayerCount extends Plugin implements Listener, Runnable private int _tempPlayers; private int _tempMaxPlayers; - @Override - public void onEnable() + private static Object _serverLock = new Object(); + + public PlayerCount(Plugin plugin) { + _plugin = plugin; _otherBungeeInstances = new HashMap(); LoadBungeeServers(); - getProxy().getScheduler().schedule(this, this, 1L, 1L, TimeUnit.SECONDS); - getProxy().getPluginManager().registerListener(this, this); - - getProxy().getPluginManager().registerCommand(this, new ReloadPlayerCountListCommand(this)); + _plugin.getProxy().getScheduler().schedule(_plugin, this, 1L, 1L, TimeUnit.SECONDS); + _plugin.getProxy().getPluginManager().registerListener(_plugin, this); } public void run() { - _tempPlayers = getProxy().getOnlineCount(); + _tempPlayers = _plugin.getProxy().getOnlineCount(); _tempMaxPlayers = 0; - for(ListenerInfo li : getProxy().getConfigurationAdapter().getListeners()) + for(ListenerInfo li : _plugin.getProxy().getConfigurationAdapter().getListeners()) { _tempMaxPlayers += li.getMaxPlayers(); } - for (InetSocketAddress address : _otherBungeeInstances.values()) + synchronized (_serverLock) { - try - { - UpdateServerCount(address); - } catch (IOException e) - { - e.printStackTrace(); - } + for (InetSocketAddress address : _otherBungeeInstances.values()) + { + try + { + UpdateServerCount(address); + } catch (IOException e) + { + e.printStackTrace(); + } + } } _totalPlayers = _tempPlayers; @@ -96,17 +101,18 @@ public class PlayerCount extends Plugin implements Listener, Runnable dataOutputStream = new DataOutputStream(socket.getOutputStream()); dataOutputStream.writeByte(254); + dataOutputStream.writeByte(1); dataOutputStream.writeByte(254); writeString("MC|PingHost", dataOutputStream); dataOutputStream.writeShort(3 + 2 * address.getAddress().getHostName().length() + 4); - dataOutputStream.writeByte(73); + dataOutputStream.writeByte(74); writeString(address.getAddress().getHostName(), dataOutputStream); dataOutputStream.writeInt(address.getPort()); if (dataInputStream.read() != 255) { - System.out.println("not 255"); + System.out.println("Bad message"); return; } @@ -132,7 +138,7 @@ public class PlayerCount extends Plugin implements Listener, Runnable } catch (IOException e) { - System.out.println("[BungeeSigns] Error pinging " + address.getHostString() + ":" + address.getPort()); + System.out.println("[PlayerCount] Error pinging " + address.getHostName() + ":" + address.getPort()); throw e; } finally @@ -215,6 +221,11 @@ public class PlayerCount extends Plugin implements Listener, Runnable public void LoadBungeeServers() { + synchronized (_serverLock) + { + _otherBungeeInstances.clear(); + } + FileInputStream fstream = null; BufferedReader br = null; @@ -234,7 +245,25 @@ public class PlayerCount extends Plugin implements Listener, Runnable String address = line.split(":")[0]; Integer port = Integer.parseInt(line.split(":")[1]); InetSocketAddress socketAddress = new InetSocketAddress(address, port); - _otherBungeeInstances.put(socketAddress.getAddress().getHostAddress(), socketAddress); + + boolean addAddress = true; + + for (ListenerInfo listenerInfo : _plugin.getProxy().getConfigurationAdapter().getListeners()) + { + if (address.equalsIgnoreCase(listenerInfo.getHost().getAddress().getHostAddress())) + { + addAddress = false; + break; + } + } + + if (addAddress) + { + synchronized (_serverLock) + { + _otherBungeeInstances.put(socketAddress.getAddress().getHostAddress(), socketAddress); + } + } line = br.readLine(); } diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/updater/Updater.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/updater/Updater.java new file mode 100644 index 000000000..716b94342 --- /dev/null +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/updater/Updater.java @@ -0,0 +1,188 @@ +package mineplex.bungee.updater; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FileUtils; + +import mineplex.bungee.Mineplexer; + +public class Updater implements Runnable +{ + private Mineplexer _plugin; + private HashMap _jarMd5Map = new HashMap(); + private File _updateDirectory; + + private boolean _needUpdate = false; + + public Updater(Mineplexer plugin) + { + _plugin = plugin; + _jarMd5Map = new HashMap(); + + getCurrentMd5s(); + + boolean windows = System.getProperty("os.name").startsWith("Windows"); + + _updateDirectory = new File((windows ? "C:" : File.separator + "home" + File.separator + "mineplex") + File.separator + "update" + File.separator + "bungee"); + + _updateDirectory.mkdirs(); + + _plugin.getProxy().getScheduler().schedule(_plugin, this, 1L, 1L, TimeUnit.SECONDS); + } + + private void getCurrentMd5s() + { + File currentDir = new File("."); + + FilenameFilter statsFilter = new FilenameFilter() + { + public boolean accept(File paramFile, String paramString) + { + if (paramString.endsWith("dat")) + { + return true; + } + + return false; + } + }; + + for (File f : currentDir.listFiles(statsFilter)) + { + FileInputStream fis = null; + + try + { + fis = new FileInputStream(f); + _jarMd5Map.put(f.getName(), DigestUtils.md5Hex(fis)); + } + catch (Exception ex) + { + System.out.println("Updater: Error parsing dat md5's"); + ex.printStackTrace(); + } + finally + { + if (fis != null) + { + try + { + fis.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + } + } + + @Override + public void run() + { + FilenameFilter statsFilter = new FilenameFilter() + { + public boolean accept(File paramFile, String paramString) + { + if (paramString.endsWith("dat")) + { + return true; + } + + return false; + } + }; + + for (File f : _updateDirectory.listFiles(statsFilter)) + { + FileInputStream fis = null; + + try + { + if (_jarMd5Map.containsKey(f.getName())) + { + fis = new FileInputStream(f); + String md5 = DigestUtils.md5Hex(fis); + + if (!md5.equals(_jarMd5Map.get(f.getName()))) + { + _needUpdate = true; + } + } + } + catch (Exception ex) + { + System.out.println("Updater: Error parsing dat md5's"); + ex.printStackTrace(); + } + finally + { + if (fis != null) + { + try + { + fis.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + } + + if (_needUpdate) + { + updateFiles(); + } + } + + private void updateFiles() + { + _needUpdate = false; + + boolean windows = System.getProperty("os.name").startsWith("Windows"); + + File updateDir = new File((windows ? "C:" : File.separator + "home" + File.separator + "mineplex") + File.separator + "update" + File.separator + "bungee"); + File currentDir = new File("."); + + updateDir.mkdirs(); + + FilenameFilter statsFilter = new FilenameFilter() + { + public boolean accept(File paramFile, String paramString) + { + if (paramString.endsWith("dat")) + { + return true; + } + + return false; + } + }; + + for (File f : updateDir.listFiles(statsFilter)) + { + try + { + FileUtils.copyFileToDirectory(f, currentDir); + } + catch (Exception ex) + { + System.out.println("Updater: Error updating dats"); + ex.printStackTrace(); + } + } + + getCurrentMd5s(); + _plugin.ReloadServerLists(); + System.out.println("Updater: Updated with new dat files."); + } +} diff --git a/Plugins/Mineplex.Bungee.PlayerCount/.classpath b/Plugins/Mineplex.Bungee.PlayerCount/.classpath deleted file mode 100644 index fbeb69b51..000000000 --- a/Plugins/Mineplex.Bungee.PlayerCount/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Plugins/Mineplex.Bungee.PlayerCount/.settings/org.eclipse.jdt.core.prefs b/Plugins/Mineplex.Bungee.PlayerCount/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 7341ab168..000000000 --- a/Plugins/Mineplex.Bungee.PlayerCount/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 diff --git a/Plugins/Mineplex.Bungee.PlayerCount/plugin.yml b/Plugins/Mineplex.Bungee.PlayerCount/plugin.yml deleted file mode 100644 index 18b6810c7..000000000 --- a/Plugins/Mineplex.Bungee.PlayerCount/plugin.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: PlayerCount -main: mineplex.bungee.PlayerCount.PlayerCount -version: 1 -author: defek7 diff --git a/Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/ReloadPlayerCountListCommand.java b/Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/ReloadPlayerCountListCommand.java deleted file mode 100644 index 84e377e03..000000000 --- a/Plugins/Mineplex.Bungee.PlayerCount/src/mineplex/bungee/PlayerCount/ReloadPlayerCountListCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package mineplex.bungee.PlayerCount; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.plugin.Command; - -public class ReloadPlayerCountListCommand extends Command -{ - private PlayerCount _plugin; - - public ReloadPlayerCountListCommand(PlayerCount plugin) - { - super( "reloadplayercount", "bungeecord.command.reloadserverlist" ); - - _plugin = plugin; - } - - @Override - public void execute(CommandSender sender, String[] arg1) - { - _plugin.LoadBungeeServers(); - sender.sendMessage(ChatColor.BLUE + "PlayerCount>" + ChatColor.GRAY + " Reloaded player count server list."); - } -} diff --git a/Plugins/Mineplex.Hub/.classpath b/Plugins/Mineplex.Hub/.classpath index 3028e8700..8147b149b 100644 --- a/Plugins/Mineplex.Hub/.classpath +++ b/Plugins/Mineplex.Hub/.classpath @@ -10,5 +10,6 @@ + diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java index 32add05cf..5cab47ba6 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java @@ -11,8 +11,8 @@ import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.HashSet; import java.util.Set; import org.bukkit.Bukkit; @@ -47,7 +47,7 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener private Portal _portal; private PartyManager _partyManager; - private NautHashMap> _serverNpcMap = new NautHashMap>(); + private NautHashMap> _serverNpcMap = new NautHashMap>(); private NautHashMap _serverNpcShopMap = new NautHashMap(); private NautHashMap _serverInfoMap = new NautHashMap(); private NautHashMap _serverUpdate = new NautHashMap(); @@ -69,6 +69,8 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, "BungeeSigns", this); LoadServers(); + + new ServerManagerUpdater(this); } public void AddCommands() @@ -81,14 +83,16 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener ServerInfo serverInfo = new ServerInfo(); serverInfo.Name = serverName; - _serverNpcMap.get(serverNpcName).add(serverInfo); - - if (!_serverInfoMap.containsKey(serverName)) + if (_serverInfoMap.containsKey(serverName)) { - _serverInfoMap.put(serverName, serverInfo); - _serverUpdate.put(serverName, System.currentTimeMillis()); + _serverInfoMap.remove(serverName); + _serverUpdate.remove(serverName); } + _serverNpcMap.get(serverNpcName).add(serverInfo); + _serverInfoMap.put(serverName, serverInfo); + _serverUpdate.put(serverName, System.currentTimeMillis()); + SaveServers(); } @@ -104,13 +108,13 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener public void AddServerNpc(String serverNpcName) { - _serverNpcMap.put(serverNpcName, new ArrayList()); + _serverNpcMap.put(serverNpcName, new HashSet()); _serverNpcShopMap.put(serverNpcName, new ServerNpcShop(this, _clientManager, _donationManager, serverNpcName)); } public void RemoveServerNpc(String serverNpcName) { - List mappedServers = _serverNpcMap.remove(serverNpcName); + Set mappedServers = _serverNpcMap.remove(serverNpcName); _serverNpcShopMap.remove(serverNpcName); if (mappedServers != null) @@ -140,7 +144,7 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener } } - public List GetServerList(String serverNpcName) + public Collection GetServerList(String serverNpcName) { return _serverNpcMap.get(serverNpcName); } @@ -434,11 +438,21 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener public void LoadServers() { + _serverInfoMap.clear(); + _serverUpdate.clear(); + + for (String npcName : _serverNpcMap.keySet()) + { + _serverNpcMap.get(npcName).clear(); + } + _loading = true; FileInputStream fstream = null; BufferedReader br = null; + HashSet npcNames = new HashSet(); + try { File npcFile = new File("ServerManager.dat"); @@ -461,6 +475,7 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener } AddServer(serverNpcName, server); + npcNames.add(serverNpcName); line = br.readLine(); } @@ -498,6 +513,15 @@ public class ServerManager extends MiniPlugin implements PluginMessageListener _loading = false; } + + for (String npcName : npcNames) + { + if (!_serverNpcShopMap.containsKey(npcName)) + _serverNpcShopMap.remove(npcName); + + if (!_serverNpcMap.containsKey(npcName)) + _serverNpcMap.remove(npcName); + } } public int GetRequiredSlots(Player player, String serverType) diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManagerUpdater.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManagerUpdater.java new file mode 100644 index 000000000..d01653872 --- /dev/null +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManagerUpdater.java @@ -0,0 +1,177 @@ +package mineplex.hub.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FileUtils; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import mineplex.core.common.util.NautHashMap; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; + +public class ServerManagerUpdater implements Listener +{ + private ServerManager _plugin; + private NautHashMap _jarMd5Map = new NautHashMap(); + private File _updateDirectory; + + private boolean _needUpdate = false; + + public ServerManagerUpdater(ServerManager plugin) + { + _plugin = plugin; + + getCurrentMd5s(); + + boolean windows = System.getProperty("os.name").startsWith("Windows"); + + _updateDirectory = new File((windows ? "C:" : File.separator + "home" + File.separator + "mineplex") + File.separator + "update" + File.separator + "lobby"); + + _updateDirectory.mkdirs(); + + plugin.GetPluginManager().registerEvents(this, plugin.GetPlugin()); + } + + private void getCurrentMd5s() + { + File serverManagerDat = new File("ServerManager.dat"); + + FileInputStream fis = null; + + try + { + fis = new FileInputStream(serverManagerDat); + _jarMd5Map.put(serverManagerDat.getName(), DigestUtils.md5Hex(fis)); + } + catch (Exception ex) + { + System.out.println("ServerManagerUpdater: Error parsing ServerManager dat md5's"); + ex.printStackTrace(); + } + finally + { + if (fis != null) + { + try + { + fis.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + } + + @EventHandler + public void checkForNewFiles(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + return; + + FilenameFilter statsFilter = new FilenameFilter() + { + public boolean accept(File paramFile, String paramString) + { + if (paramString.endsWith("dat")) + { + return true; + } + + return false; + } + }; + + for (File f : _updateDirectory.listFiles(statsFilter)) + { + FileInputStream fis = null; + + try + { + if (_jarMd5Map.containsKey(f.getName())) + { + fis = new FileInputStream(f); + String md5 = DigestUtils.md5Hex(fis); + + if (!md5.equals(_jarMd5Map.get(f.getName()))) + { + _needUpdate = true; + } + } + } + catch (Exception ex) + { + System.out.println("ServerManagerUpdater: Error parsing dat md5's"); + ex.printStackTrace(); + } + finally + { + if (fis != null) + { + try + { + fis.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + } + } + + if (_needUpdate) + { + updateFiles(); + } + } + + private void updateFiles() + { + _needUpdate = false; + + boolean windows = System.getProperty("os.name").startsWith("Windows"); + + File updateDir = new File((windows ? "C:" : File.separator + "home" + File.separator + "mineplex") + File.separator + "update" + File.separator + "lobby"); + File currentDir = new File("."); + + updateDir.mkdirs(); + + FilenameFilter statsFilter = new FilenameFilter() + { + public boolean accept(File paramFile, String paramString) + { + if (paramString.endsWith("dat")) + { + return true; + } + + return false; + } + }; + + for (File f : updateDir.listFiles(statsFilter)) + { + try + { + FileUtils.copyFileToDirectory(f, currentDir); + } + catch (Exception ex) + { + System.out.println("ServerManagerUpdater: Error updating dats"); + ex.printStackTrace(); + } + } + + getCurrentMd5s(); + _plugin.LoadServers(); + System.out.println("ServerManagerUpdater: Updated with new dat file."); + } + +} diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerSorter.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerSorter.java index 330862997..01a9aaeb0 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerSorter.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerSorter.java @@ -22,7 +22,7 @@ public class ServerSorter implements Comparator if ((a.MOTD.contains("Recruiting") || a.MOTD.contains("Waiting") || a.MOTD.contains("Starting") || a.MOTD.contains("Cup")) && !b.MOTD.contains("Recruiting") && !b.MOTD.contains("Waiting") && !b.MOTD.contains("Starting") && !b.MOTD.contains("Cup")) return -1; - if ((b.MOTD.contains("Recruiting") || b.MOTD.contains("Waiting") || a.MOTD.contains("Starting") || b.MOTD.contains("Cup")) && !a.MOTD.contains("Recruiting") && !a.MOTD.contains("Waiting") && !a.MOTD.contains("Starting") && !a.MOTD.contains("Cup")) + if ((b.MOTD.contains("Recruiting") || b.MOTD.contains("Waiting") || b.MOTD.contains("Starting") || b.MOTD.contains("Cup")) && !a.MOTD.contains("Recruiting") && !a.MOTD.contains("Waiting") && !a.MOTD.contains("Starting") && !a.MOTD.contains("Cup")) return 1; if (a.MaxPlayers - a.CurrentPlayers < _requiredSlots && b.MaxPlayers - b.CurrentPlayers >= _requiredSlots) diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/ServerNpcPage.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/ServerNpcPage.java index 4f01ada8c..ac49e3179 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/ServerNpcPage.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/ServerNpcPage.java @@ -7,6 +7,7 @@ import java.util.List; import mineplex.core.account.CoreClientManager; import mineplex.core.common.Rank; import mineplex.core.common.util.C; +import mineplex.core.common.util.F; import mineplex.core.donation.DonationManager; import mineplex.core.shop.item.ShopItem; import mineplex.core.shop.page.ShopPageBase; @@ -34,7 +35,7 @@ public class ServerNpcPage extends ShopPageBase @Override protected void BuildPage() { - List serverList = Plugin.GetServerList(_serverNpcKey); + List serverList = new ArrayList(Plugin.GetServerList(_serverNpcKey)); int slots = 1; @@ -43,7 +44,19 @@ public class ServerNpcPage extends ShopPageBase slots = Plugin.GetRequiredSlots(Player, serverList.get(0).ServerType); } - Collections.sort(serverList, new ServerSorter(slots)); + try + { + Collections.sort(serverList, new ServerSorter(slots)); + } + catch (Exception exception) + { + exception.printStackTrace(); + + for (ServerInfo serverInfo : serverList) + { + System.out.println(F.main("ServerNpcPage", ChatColor.YELLOW + serverInfo.Name + ": " + serverInfo.MOTD + " " + serverInfo.CurrentPlayers + "/" + serverInfo.MaxPlayers)); + } + } int slot = 9; int greenCount = 0; @@ -151,6 +164,7 @@ public class ServerNpcPage extends ShopPageBase { ButtonMap.clear(); BuildPage(); + System.out.println("Updated " + Player.getName() + "'s page."); } public void SelectServer(Player player, ServerInfo serverInfo) diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java index 66fc5fead..b9db5a440 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameFlagManager.java @@ -587,7 +587,8 @@ public class GameFlagManager implements Listener GameTeam team = game.GetTeam(event.getPlayer()); - team.SetPlayerState(event.getPlayer(), PlayerState.OUT); + if (team != null) + team.SetPlayerState(event.getPlayer(), PlayerState.OUT); } @EventHandler diff --git a/Website/LOCWebsite.suo b/Website/LOCWebsite.suo index c2101b0a3e0a4a44ff728cdf2568e3788b0e937e..2c8849e172fa1659b02e00a8b42ac9f538c3bca5 100644 GIT binary patch delta 12185 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 delta 12433 zcmbVyeO#1P{`Q=6pL;|k9A=Sl!f_;ISwb8Mjfik$4UrH=M0_I}UsE$3k<8R|G*eSE z^dR4ATYsYw+l%W`v`%ZR;mh_Z*WAh4?aigpHQUUL%wDz(pX=N=p!@slc^>z3x6D2F z+~=I{`MzA&^*w>hNrB5r%>j+gmTR5Bf0?m4ZhG;v!bS(^@V?mxW}bv?Ig`<1C-S}ygg)hKN;PizVFKO&-ZJn)O|hx8%%Yps0H zd4)$s%jE;dngeUy-#>F{pkRwzzP+(erd*qCmjxXOR5OveWycJ=Z2lsFGRs7Ye0p<= z47SY0udb&!!TM3%R5n`9xsWOwzbvKX6j3hgN`%}ww@QYGWwt~r&RC7<$9E6Ya%tLr z#+J&L?kbZz?~17;DGHdU_tGL3DdgS**087^{S!kgvz))#5? zWtRT(#<`3ow#<8!Vq{IxTv^x}OJ^>#Dhixt(ei0Zq*<$30eOfyWDKRVD#^|dmF{2K z}S`_ zhBY!_mnB$u9o8^`B5kZ(SS(XGbxdP3DDpNh#K&Qryl?RrM89ba#_RV~R z40lG$vZZcWeb`FtDnuT=wv$CubzhOdrpZqZZj-xf3d#F#Hi!JjL{>}tk>p;|f5=Jk zKQKGFHi-(_*Us#H7GRr}7}I!-4h|9hsJWi4BJX+;+sk4(#VnS3I(3GvpwB9GbB}cS`s7PAoKDHl4_& z`1w48d;>&2{VJcU*&T=N%4yI#b{hrX=T`aV+X+-XLra$Kw=1dsPL?Ixj+N4kUkf|= zIjfWljwQ>NKi?f{>ab2_xH5uld%@D=d}*NAc>N zpIK?=<1Cr{l4UBh!(o0Yhn*$XHG$?)!Y0$s#;E8jpth+jp0*yu4`2N>g${iPyL9+@ zigbUPq2^;eV58$ti!8jyN7K*oJIGb972{Ja?OLQwq_!w6MJ_#G+!d%^nnl7c-JRvK z=!;agiQcjD>ExNGr^)tnRw>rElkZ7w1dOtYTP&~AsL!>>sM9N~rTomqPf-+~qSoTbKc}5{iV1J-f72+Op-Nka*3$&&} z+)kw{d5moT!J%H*Wh2{tnoTbJAzhg*XZMeswp(H3DW7r|wnk$Oukn1OoEYi*K8?!% z!4~wyQncK2hXc<@PQkxv@l^K-o3o>X*(iQ6w%bO`L(RWn8F*r~;j!@zPl!_4b|qWd zuawg1+k^_B0*V({!@q`dJ1qAh-01-ATE!R3V?USE+M!~q^v!b1Kz0;`qhQ1OUhD<- zDs9^=7Lnhl7tz*U%t|SzkqF$x(kYK&B14C3Rtj731;RDUFnPyjo~&QQ+n=LB+u5Q9 zojK_!>?ThiEGGXPmP>6qLf5J8V?rybzzRFNr)w2-USnxw*H|svOKWCpt10jck%^s) zqQ@Eg8_oKLO(pLmESryl9R_QoP0w@mVHw0fgd@5h5;ofJ5{dLeG;`2XhHdJ{ zAz=i2vqBXob_(w2CGvHdMAf}9@gt2YY?HMbn#*{SK23R)+_kwMogT-E=|ZKRBXdSp zlJ}rqA%hVSa$m>7HY!-pms5C{NW=8LHOfdsFD;+?j^_y!4r?~rI*?hr!{xG*C9!H` z;IYaf6Idz@%F+7Cj<*qSevv|{cJ2t}yI6rB`y4$NMa3FwOJSbgv>+MDG$V&sVr$>E zP}_&xL*bvegMzDhEbZyT(pWo9cW5ukI!`Kjk7-tH?My6To!qs4Fa-kY?K{=m-K;

>I$(-u`5_21&R=U$qTe%s$0Sn$(9LU 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