corrade-vassal – Rev 16

Subversion Repositories:
Rev:
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using OpenMetaverse;
using wasSharp;
using Parallel = System.Threading.Tasks.Parallel;
using Timer = System.Timers.Timer;

namespace Vassal
{
    public partial class Vassal : Form
    {
        public static Timer vassalTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        public static Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        public static Timer residentListTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        public static Timer estateTopTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        public static Timer regionsStateTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        public static Timer estateTexturesTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        public static Image[] groundTextureImages = new Image[4];
        public static volatile int regionsStateCheckIndex;
        public static VassalConfiguration vassalConfiguration = new VassalConfiguration();
        public static Vassal vassalForm;
        public static readonly object ClientInstanceTeleportLock = new object();
        public static readonly object RegionsStateCheckLock = new object();
        public static Web.wasHTTPClient HTTPClient;

        /// <summary>
        ///     Corrade version.
        /// </summary>
        public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();

        /// <summary>
        ///     Corrade's input filter function.
        /// </summary>
        private static readonly Func<string, string> wasInput = o =>
        {
            if (string.IsNullOrEmpty(o)) return string.Empty;

            foreach (var filter in vassalConfiguration.InputFilters)
            {
                switch (filter)
                {
                    case Filter.RFC1738:
                        o = Web.URLUnescapeDataString(o);
                        break;
                    case Filter.RFC3986:
                        o = Web.URIUnescapeDataString(o);
                        break;
                    case Filter.ENIGMA:
                        o = Cryptography.ENIGMA(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
                            vassalConfiguration.ENIGMA.plugs.ToArray(),
                            vassalConfiguration.ENIGMA.reflector);
                        break;
                    case Filter.VIGENERE:
                        o = Cryptography.DecryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
                        break;
                    case Filter.ATBASH:
                        o = Cryptography.ATBASH(o);
                        break;
                    case Filter.BASE64:
                        o = Encoding.UTF8.GetString(Convert.FromBase64String(o));
                        break;
                }
            }
            return o;
        };

        /// <summary>
        ///     Corrade's output filter function.
        /// </summary>
        private static readonly Func<string, string> wasOutput = o =>
        {
            if (string.IsNullOrEmpty(o)) return string.Empty;

            foreach (var filter in vassalConfiguration.OutputFilters)
            {
                switch (filter)
                {
                    case Filter.RFC1738:
                        o = Web.URLEscapeDataString(o);
                        break;
                    case Filter.RFC3986:
                        o = Web.URIEscapeDataString(o);
                        break;
                    case Filter.ENIGMA:
                        o = Cryptography.ENIGMA(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
                            vassalConfiguration.ENIGMA.plugs.ToArray(),
                            vassalConfiguration.ENIGMA.reflector);
                        break;
                    case Filter.VIGENERE:
                        o = Cryptography.EncryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
                        break;
                    case Filter.ATBASH:
                        o = Cryptography.ATBASH(o);
                        break;
                    case Filter.BASE64:
                        o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o));
                        break;
                }
            }
            return o;
        };

        private static readonly Action updateCurrentRegionName = () =>
        {
            try
            {
                var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                    KeyValue.Escape(new Dictionary<string, string>
                    {
                        {"command", "getregiondata"},
                        {"group", vassalConfiguration.Group},
                        {"password", vassalConfiguration.Password},
                        {"data", "Name"}
                    }, wasOutput)).Result);
                bool success;
                if (string.IsNullOrEmpty(result) ||
                    !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                {
                    vassalForm.BeginInvoke(
                        (MethodInvoker)
                            (() => { vassalForm.StatusText.Text = @"Failed to query Corrade for current region."; }));
                    return;
                }
                switch (success)
                {
                    case true:
                        vassalForm.BeginInvoke((MethodInvoker) (() =>
                        {
                            vassalForm.CurrentRegionAt.Visible = true;
                            vassalForm.CurrentRegionName.Visible = true;
                            vassalForm.CurrentRegionName.Text =
                                CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).Last();
                        }));
                        break;
                    default:
                        vassalForm.BeginInvoke((MethodInvoker) (() =>
                        {
                            vassalForm.CurrentRegionAt.Visible = false;
                            vassalForm.CurrentRegionName.Visible = false;
                            vassalForm.StatusText.Text = @"Error getting current region: " +
                                                         wasInput(KeyValue.Get("error", result));
                        }));
                        break;
                }
            }
            catch (Exception ex)
            {
                vassalForm.BeginInvoke((MethodInvoker) (() =>
                {
                    vassalForm.StatusText.Text =
                        @"Error getting current region: " +
                        ex.Message;
                }));
            }
        };

        public Vassal()
        {
            InitializeComponent();
            vassalForm = this;
        }

        private void ShowToolTip(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke(
                (Action)(() =>
                {
                    PictureBox pictureBox = sender as PictureBox;
                    if (pictureBox != null)
                    {
                        toolTip1.Show(toolTip1.GetToolTip(pictureBox), pictureBox);
                    }
                }));
        }

        private void RegionSelected(object sender, EventArgs e)
        {
            new Thread(() =>
            {
                try
                {
                    // Stop timers.
                    vassalTimer.Stop();
                    overviewTabTimer.Stop();
                    regionsStateTabTimer.Stop();
                    residentListTabTimer.Stop();
                    estateTopTabTimer.Stop();
                    estateTexturesTabTimer.Stop();

                    Monitor.Enter(ClientInstanceTeleportLock);

                    var selectedRegionName = string.Empty;
                    var selectedRegionPosition = Vector3.Zero;
                    var startTeleport = false;
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        var listViewItem = LoadedRegionsBox.SelectedItem as ListViewItem;
                        switch (listViewItem != null && LoadedRegionsBox.SelectedIndex != -1)
                        {
                            case true:
                                selectedRegionName = listViewItem.Text;
                                selectedRegionPosition = (Vector3) listViewItem.Tag;
                                startTeleport = true;
                                break;
                            default:
                                startTeleport = false;
                                break;
                        }
                    }));

                    if (!startTeleport) throw new Exception();

                    // Announce teleport.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        vassalForm.RegionTeleportGroup.Enabled = false;
                        vassalForm.StatusProgress.Value = 0;
                        vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
                    }));

                    // Pause for teleport (10 teleports / 15s allowed).
                    Thread.Sleep(700);

                    var elapsedSeconds = 0;
                    var teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
                    teleportTimer.Elapsed += (o, p) =>
                    {
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            vassalForm.StatusProgress.Value =
                                Math.Min(
                                    (int)
                                        (100d*
                                         (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/
                                          vassalConfiguration.TeleportTimeout)), 100);
                        }));
                    };
                    teleportTimer.Start();
                    string result = null;
                    var receivedPOST = new ManualResetEvent(false);
                    new Thread(() =>
                    {
                        result = wasInput(Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "teleport"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"region", selectedRegionName},
                                {"position", selectedRegionPosition.ToString()},
                                {"fly", "True"}
                            }, wasOutput)).Result));
                        receivedPOST.Set();
                    }) {IsBackground = true}.Start();
                    receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false);
                    teleportTimer.Stop();
                    switch (!string.IsNullOrEmpty(result) && KeyValue.Get("success", result) == "True")
                    {
                        case true:
                            vassalForm.Invoke((MethodInvoker) (() =>
                            {
                                vassalForm.StatusText.Text = @"Now at " + selectedRegionName;
                                vassalForm.CurrentRegionName.Text = selectedRegionName;
                            }));
                            break;
                        default:
                            switch (!string.IsNullOrEmpty(result))
                            {
                                case true:
                                    vassalForm.Invoke((MethodInvoker) (() =>
                                    {
                                        vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName +
                                                                     @": " +
                                                                     KeyValue.Get("error", result);
                                    }));
                                    break;
                                default:
                                    vassalForm.Invoke(
                                        (MethodInvoker)
                                            (() =>
                                            {
                                                vassalForm.StatusText.Text = @"Failed teleporting to " +
                                                                             selectedRegionName;
                                            }));
                                    break;
                            }
                            break;
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke(
                        (MethodInvoker)
                            (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message; }));
                }
                finally
                {
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        vassalForm.StatusProgress.Value = 100;
                        vassalForm.RegionTeleportGroup.Enabled = true;
                        // Set the map image to the loading spinner.
                        var thisAssembly = Assembly.GetExecutingAssembly();
                        var file =
                            thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
                        switch (file != null)
                        {
                            case true:
                                vassalForm.Invoke((MethodInvoker) (() =>
                                {
                                    RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
                                    RegionAvatarsMap.Image = Image.FromStream(file);
                                    RegionAvatarsMap.Refresh();
                                }));
                                break;
                        }
                        // Clear the resident list table.
                        ResidentListGridView.Rows.Clear();
                        // Clear the top scripts table.
                        TopScriptsGridView.Rows.Clear();
                        // Clear the top colliders table.
                        TopCollidersGridView.Rows.Clear();
                        // Clear the estate list table.
                        EstateListGridView.Rows.Clear();
                        // Clear the estate list selection box.
                        EstateListSelectBox.SelectedIndex = -1;
                        // Invalidate data for overview tab.
                        vassalForm.CurrentRegionAt.Visible = false;
                        vassalForm.CurrentRegionName.Visible = false;
                        Agents.Text = string.Empty;
                        Agents.Enabled = false;
                        LastLag.Text = string.Empty;
                        LastLag.Enabled = false;
                        Dilation.Text = string.Empty;
                        Dilation.Enabled = false;
                        FPS.Text = string.Empty;
                        FPS.Enabled = false;
                        PhysicsFPS.Text = string.Empty;
                        PhysicsFPS.Enabled = false;
                        ActiveScripts.Text = string.Empty;
                        ActiveScripts.Enabled = false;
                        ScriptTime.Text = string.Empty;
                        ScriptTime.Enabled = false;
                        FrameTime.Text = string.Empty;
                        FrameTime.Enabled = false;
                        ScriptedObjects.Text = string.Empty;
                        ScriptedObjects.Enabled = false;
                        PhysicsTime.Text = string.Empty;
                        PhysicsTime.Enabled = false;
                        NetTime.Text = string.Empty;
                        NetTime.Enabled = false;
                        Objects.Text = string.Empty;
                        Objects.Enabled = false;
                    }));

                    Monitor.Exit(ClientInstanceTeleportLock);

                    // start timers
                    vassalTimer.Start();
                    overviewTabTimer.Start();
                    regionsStateTabTimer.Start();
                    residentListTabTimer.Start();
                    estateTopTabTimer.Start();
                    estateTexturesTabTimer.Start();
                }
            })
            {IsBackground = true}.Start();
        }

        private void SettingsRequested(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() => { VassalStatusGroup.Enabled = false; }));
            var settingsForm = new SettingsForm {TopMost = true};
            settingsForm.Show();
        }

        private void VassalShown(object sender, EventArgs e)
        {
            // Set the version
            vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION;

            // Disable estate manager tabs since we will enable these dynamically.
            EstateTopTab.Enabled = false;
            EstateListsTab.Enabled = false;
            ResidentListBanGroup.Enabled = false;
            ResidentListTeleportHomeGroup.Enabled = false;
            EstateTerrainDownloadUploadGroup.Enabled = false;
            EstateVariablesGroup.Enabled = false;
            // Estate textures
            RegionTexturesLowUUIDApplyBox.Enabled = false;
            RegionTexturesLowUUIDApplyButton.Enabled = false;
            RegionTexturesMiddleLowUUIDApplyBox.Enabled = false;
            RegionTexturesMiddleLowUUIDApplyButton.Enabled = false;
            RegionTexturesMiddleHighUUIDApplyBox.Enabled = false;
            RegionTexturesMiddleHighUUIDApplyButton.Enabled = false;
            RegionTexturesHighUUIDApplyBox.Enabled = false;
            RegionTexturesHighUUIDApplyButton.Enabled = false;

            // Get the configuration file settings if it exists.
            if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE))
            {
                // Load the configuration.
                VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration);
                // Apply settings
                RegionRestartDelayBox.Text = vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture);
                // HTTP
                string mediaType;
                switch (vassalConfiguration.InputFilters.LastOrDefault())
                {
                    case Filter.RFC1738:
                        mediaType = @"application/x-www-form-urlencoded";
                        break;
                    default:
                        mediaType = @"text/plain";
                        break;
                }
                // Create HTTP Client
                Vassal.HTTPClient = new Web.wasHTTPClient(new ProductInfoHeaderValue(@"Vassal",
                    Vassal.VASSAL_VERSION), new CookieContainer(), mediaType, vassalConfiguration.ServicesTimeout);
            }

            // Get all the regions if they exist.
            if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS))
            {
                Vector3 localPosition;
                var ConfiguredRegions = new List<KeyValuePair<string, Vector3>>(
                    File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS)
                        .Select(o => new List<string>(CSV.ToEnumerable(o)))
                        .Where(o => o.Count == 2)
                        .ToDictionary(o => o.First(),
                            p =>
                                Vector3.TryParse(p.Last(), out localPosition)
                                    ? localPosition
                                    : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value));
                // Populate the loaded regions.
                LoadedRegionsBox.Items.Clear();
                LoadedRegionsBox.Items.AddRange(
                    ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value})
                        .ToArray());
                // Populate the batch restart grid view.
                BatchRestartGridView.Rows.Clear();
                foreach (var data in ConfiguredRegions)
                {
                    BatchRestartGridView.Rows.Add(data.Key, data.Value.ToString());
                }
                // Populate the batch covenant grid view.
                BatchSetCovenantGridView.Rows.Clear();
                foreach (var data in ConfiguredRegions)
                {
                    BatchSetCovenantGridView.Rows.Add(data.Key, data.Value.ToString());
                }
                // Populate the regions state grid view.
                foreach (var data in ConfiguredRegions)
                {
                    RegionsStateGridView.Rows.Add(data.Key, "Check pening...");
                }
            }

            // Start the vassal timer.
            vassalTimer.Elapsed += (o, p) =>
            {
                if (!Monitor.TryEnter(ClientInstanceTeleportLock))
                    return;
                try
                {
                    // Check Corrade connection status.
                    var tcpClient = new TcpClient();
                    var uri = new Uri(vassalConfiguration.HTTPServerURL);
                    tcpClient.Connect(uri.Host, uri.Port);
                    // port open
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        vassalForm.CurrentRegionAt.Visible = true;
                        vassalForm.CurrentRegionName.Visible = true;
                        var thisAssembly = Assembly.GetExecutingAssembly();
                        var file =
                            thisAssembly.GetManifestResourceStream("Vassal.img.online.png");
                        switch (file != null)
                        {
                            case true:
                                vassalForm.BeginInvoke((MethodInvoker) (() =>
                                {
                                    ConnectionStatusPictureBox.Image = Image.FromStream(file);
                                    ConnectionStatusPictureBox.Refresh();
                                }));
                                break;
                        }
                        Tabs.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
                catch (Exception)
                {
                    // port closed
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        vassalForm.CurrentRegionAt.Visible = false;
                        vassalForm.CurrentRegionName.Visible = false;
                        var thisAssembly = Assembly.GetExecutingAssembly();
                        var file =
                            thisAssembly.GetManifestResourceStream("Vassal.img.offline.png");
                        switch (file != null)
                        {
                            case true:
                                vassalForm.BeginInvoke((MethodInvoker) (() =>
                                {
                                    ConnectionStatusPictureBox.Image = Image.FromStream(file);
                                    ConnectionStatusPictureBox.Refresh();
                                }));
                                break;
                        }
                        Tabs.Enabled = false;
                        RegionTeleportGroup.Enabled = false;
                    }));
                }

                try
                {
                    // Get the simulator name and if we are an estate manager.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getregiondata"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {
                                "data", CSV.FromEnumerable(new[]
                                {
                                    "Name",
                                    "IsEstateManager"
                                })
                            }
                        }, wasOutput)).Result);

                    bool success;
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    var data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                    if (data.Count.Equals(0))
                        throw new Exception();

                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        // Drop access to features if we are not estate managers.
                        bool isEstateManager;
                        switch (
                            bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
                            isEstateManager)
                        {
                            case true: // we are an estate manager
                                EstateTopTab.Enabled = true;
                                EstateListsTab.Enabled = true;
                                ResidentListBanGroup.Enabled = true;
                                ResidentListTeleportHomeGroup.Enabled = true;
                                EstateTerrainDownloadUploadGroup.Enabled = true;
                                EstateVariablesGroup.Enabled = true;
                                RegionToolsRegionDebugGroup.Enabled = true;
                                RegionToolsRegionInfoGroup.Enabled = true;
                                // Estate textures
                                RegionTexturesLowUUIDApplyBox.Enabled = true;
                                RegionTexturesLowUUIDApplyButton.Enabled = true;
                                RegionTexturesMiddleLowUUIDApplyBox.Enabled = true;
                                RegionTexturesMiddleLowUUIDApplyButton.Enabled = true;
                                RegionTexturesMiddleHighUUIDApplyBox.Enabled = true;
                                RegionTexturesMiddleHighUUIDApplyButton.Enabled = true;
                                RegionTexturesHighUUIDApplyBox.Enabled = true;
                                RegionTexturesHighUUIDApplyButton.Enabled = true;
                                break;
                            default:
                                EstateTopTab.Enabled = false;
                                EstateListsTab.Enabled = false;
                                ResidentListBanGroup.Enabled = false;
                                ResidentListTeleportHomeGroup.Enabled = false;
                                EstateTerrainDownloadUploadGroup.Enabled = false;
                                EstateVariablesGroup.Enabled = false;
                                RegionToolsRegionDebugGroup.Enabled = false;
                                RegionToolsRegionInfoGroup.Enabled = false;
                                // Estate textures
                                RegionTexturesLowUUIDApplyBox.Enabled = false;
                                RegionTexturesLowUUIDApplyButton.Enabled = false;
                                RegionTexturesMiddleLowUUIDApplyBox.Enabled = false;
                                RegionTexturesMiddleLowUUIDApplyButton.Enabled = false;
                                RegionTexturesMiddleHighUUIDApplyBox.Enabled = false;
                                RegionTexturesMiddleHighUUIDApplyButton.Enabled = false;
                                RegionTexturesHighUUIDApplyBox.Enabled = false;
                                RegionTexturesHighUUIDApplyButton.Enabled = false;
                                break;
                        }

                        // Show the region name.
                        vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1];
                        vassalForm.CurrentRegionAt.Visible = true;
                        vassalForm.CurrentRegionName.Visible = true;
                    }));
                }
                catch (Exception)
                {
                }

                Monitor.Exit(ClientInstanceTeleportLock);
            };
            vassalTimer.Start();

            // Start the overview timer.
            overviewTabTimer.Elapsed += (o, p) =>
            {
                // Do not do anything in case the tab is not selected.
                var run = false;
                vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(OverviewTab); }));

                if (!run)
                {
                    overviewTabTimer.Stop();
                    return;
                }

                overviewTabTimer.Stop();

                try
                {
                    // Start measuring the lag to Corrade.
                    var stopWatch = new Stopwatch();
                    stopWatch.Start();
                    // Get the statistics.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getregiondata"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {
                                "data", CSV.FromEnumerable(new[]
                                {
                                    "Agents",
                                    "LastLag",
                                    "Dilation",
                                    "FPS",
                                    "PhysicsFPS",
                                    "ActiveScripts",
                                    "ScriptTime",
                                    "Objects",
                                    "FrameTime",
                                    "ScriptedObjects",
                                    "PhysicsTime",
                                    "NetTime",
                                    "AvatarPositions"
                                })
                            }
                        }, wasOutput)).Result);
                    stopWatch.Stop();

                    bool success;
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    var data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                    if (data.Count.Equals(0))
                        throw new Exception();

                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        // Populate the overview tab.
                        Agents.Text = data[data.IndexOf("Agents") + 1];
                        Agents.Enabled = true;
                        LastLag.Text = data[data.IndexOf("LastLag") + 1];
                        LastLag.Enabled = true;
                        Dilation.Text = data[data.IndexOf("Dilation") + 1];
                        Dilation.Enabled = true;
                        FPS.Text = data[data.IndexOf("FPS") + 1];
                        FPS.Enabled = true;
                        PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1];
                        PhysicsFPS.Enabled = true;
                        ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1];
                        ActiveScripts.Enabled = true;
                        ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1];
                        ScriptTime.Enabled = true;
                        FrameTime.Text = data[data.IndexOf("FrameTime") + 1];
                        FrameTime.Enabled = true;
                        ScriptedObjects.Text = data[data.IndexOf("ScriptedObjects") + 1];
                        ScriptedObjects.Enabled = true;
                        PhysicsTime.Text = data[data.IndexOf("PhysicsTime") + 1];
                        PhysicsTime.Enabled = true;
                        NetTime.Text = data[data.IndexOf("NetTime") + 1];
                        NetTime.Enabled = true;
                        Objects.Text = data[data.IndexOf("Objects") + 1];
                        Objects.Enabled = true;

                        // Show the overview lag time.
                        CorradePollTimeDial.Value =
                            (float) Math.Min(TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds).TotalSeconds,
                                CorradePollTimeDial.MaxValue);
                    }));

                    // Get avatar positions.
                    // Pattern: [...], X, 10, Y, 63, Z, 200, [...], X, 52, Y, 73, Z, 55, [...[...]]
                    float X = 0, Y = 0, Z = 0;
                    var positions = data.Select((x, i) => new {Item = x, Index = i})
                        .Where(x => x.Item.Equals("X") || x.Item.Equals("Y") || x.Item.Equals("Z"))
                        .Select(z => data[z.Index + 1]).Select((x, i) => new {Value = x, Index = i})
                        .GroupBy(x => x.Index/3)
                        .Select(x => x.Select(v => v.Value).ToList())
                        .Where(
                            x =>
                                float.TryParse(x[0], out X) && float.TryParse(x[1], out Y) &&
                                float.TryParse(x[2], out Z))
                        .Select(x => new Vector3(X, Y, Z))
                        .ToList();

                    // Get the map image.
                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getgridregiondata"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"data", "MapImageID"}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                    if (!data.Count.Equals(2))
                        throw new Exception();
                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "download"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"item", data.Last()},
                            {"type", "Texture"},
                            {"format", "Jpeg"}
                        }, wasOutput)).Result);
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();
                    var mapImageBytes = Convert.FromBase64String(wasInput(KeyValue.Get("data", result)));
                    Image mapImage;
                    using (var memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
                    {
                        mapImage = Image.FromStream(memoryStream);
                    }

                    // Draw the avatars onto the map.
                    var mapGraphics = Graphics.FromImage(mapImage);
                    foreach (var position in positions)
                    {
                        mapGraphics.FillEllipse(Brushes.Chartreuse,
                            new Rectangle((int) position.X, (int) position.Y, 4, 4));
                    }
                    mapGraphics.DrawImage(mapImage, new Point(0, 0));

                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage;
                        RegionAvatarsMap.Image = mapImage;
                        RegionAvatarsMap.Refresh();
                    }));
                }
                catch (Exception)
                {
                }

                overviewTabTimer.Start();
            };
            overviewTabTimer.Start();

            regionsStateTabTimer.Elapsed += (o, p) =>
            {
                // Do not do anything in case the tab is not selected.
                var run = false;
                vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(RegionsStateTab); }));

                if (!run)
                {
                    regionsStateTabTimer.Stop();
                    return;
                }

                regionsStateTabTimer.Stop();

                try
                {
                    var regionName = string.Empty;
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        regionName =
                            RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateRegionName"].Value
                                .ToString();
                        RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
                            Color.Gold;
                    }));

                    if (string.IsNullOrEmpty(regionName))
                        throw new Exception();

                    // Get the region status.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getgridregiondata"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"region", regionName},
                            {"data", "Access"}
                        }, wasOutput)).Result);

                    bool success;
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    var data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                    if (!data.Count.Equals(2))
                        throw new Exception();

                    var status = data.Last();
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        switch (status)
                        {
                            case "Unknown":
                            case "Down":
                            case "NonExistent":
                                RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
                                    Color.LightPink;
                                RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastState"].Value =
                                    status;
                                break;
                            default:
                                RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
                                    Color.LightGreen;
                                RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastState"].Value =
                                    "Up";
                                break;
                        }
                        RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastCheck"].Value = DateTime
                            .Now.ToUniversalTime()
                            .ToString(LINDEN_CONSTANTS.LSL.DATE_TIME_STAMP);
                    }));
                }
                catch (Exception)
                {
                }
                finally
                {
                    ++regionsStateCheckIndex;
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        if (regionsStateCheckIndex >= RegionsStateGridView.Rows.Count)
                        {
                            regionsStateCheckIndex = 0;
                        }
                    }));
                }

                regionsStateTabTimer.Start();
            };
            regionsStateTabTimer.Start();

            // Start the top scores timer.
            estateTopTabTimer.Elapsed += (o, p) =>
            {
                // Do not do anything in case the tab is not selected.
                var run = false;
                vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(EstateTopTab); }));

                if (!run)
                {
                    estateTopTabTimer.Stop();
                    return;
                }

                estateTopTabTimer.Stop();

                try
                {
                    // Get the top scripts.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getregiontop"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", "scripts"}
                        }, wasOutput)).Result);

                    bool success;
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    var data =
                        new HashSet<List<string>>(CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                            .Select((x, i) => new {Index = i, Value = x})
                            .GroupBy(x => x.Index/5)
                            .Select(x => x.Select(v => v.Value).ToList()));
                    if (data.Count.Equals(0))
                        throw new Exception();

                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        // Remove rows that are not in the data update.
                        foreach (
                            var index in
                                TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>()
                                    .Where(
                                        topScriptsRow =>
                                            !data.Any(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value)))
                                    .Select(q => q.Index))
                        {
                            TopScriptsGridView.Rows.RemoveAt(index);
                        }
                        // Now update or add new data.
                        foreach (var dataComponents in data.Where(q => q.Count.Equals(5)))
                        {
                            var row =
                                TopScriptsGridView.Rows.AsParallel()
                                    .Cast<DataGridViewRow>()
                                    .FirstOrDefault(q => q.Cells["TopScriptsUUID"].Value.Equals(dataComponents[2]));
                            switch (row != null)
                            {
                                case true: // the row exists, so update it.
                                    row.Cells["TopScriptsScore"].Value = dataComponents[0];
                                    row.Cells["TopScriptsTaskName"].Value = dataComponents[1];
                                    row.Cells["TopScriptsUUID"].Value = dataComponents[2];
                                    row.Cells["TopScriptsOwner"].Value = dataComponents[3];
                                    row.Cells["TopScriptsPosition"].Value = dataComponents[4];
                                    break;
                                case false: // the row dosn't exist, so add it.
                                    TopScriptsGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
                                        dataComponents[3], dataComponents[4]);
                                    break;
                            }
                        }
                    }));

                    // Get the top colliders.
                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getregiontop"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", "colliders"}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    data = new HashSet<List<string>>(CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                        .Select((x, i) => new {Index = i, Value = x})
                        .GroupBy(x => x.Index/5)
                        .Select(x => x.Select(v => v.Value).ToList()));
                    if (data.Count.Equals(0))
                        throw new Exception();

                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        // Remove rows that are not in the data update.
                        foreach (
                            var index in
                                TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>()
                                    .Where(
                                        topCollidersRow =>
                                            !data.Any(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value)))
                                    .Select(q => q.Index))
                        {
                            TopCollidersGridView.Rows.RemoveAt(index);
                        }
                        // Now update or add new data.
                        foreach (var dataComponents in data.Where(q => q.Count.Equals(5)))
                        {
                            var row =
                                TopCollidersGridView.Rows.AsParallel()
                                    .Cast<DataGridViewRow>()
                                    .FirstOrDefault(q => q.Cells["TopCollidersUUID"].Value.Equals(dataComponents[2]));
                            switch (row != null)
                            {
                                case true: // the row exists, so update it.
                                    row.Cells["TopCollidersScore"].Value = dataComponents[0];
                                    row.Cells["TopSCollidersTaskName"].Value = dataComponents[1];
                                    row.Cells["TopCollidersUUID"].Value = dataComponents[2];
                                    row.Cells["TopCollidersOwner"].Value = dataComponents[3];
                                    row.Cells["TopCollidersPosition"].Value = dataComponents[4];
                                    break;
                                case false: // the row dosn't exist, so add it.
                                    TopCollidersGridView.Rows.Add(dataComponents[0], dataComponents[1],
                                        dataComponents[2],
                                        dataComponents[3], dataComponents[4]);
                                    break;
                            }
                        }
                    }));
                }
                catch (Exception)
                {
                }

                estateTopTabTimer.Start();
            };
            estateTopTabTimer.Start();

            // Start the resident list timer.
            residentListTabTimer.Elapsed += (o, p) =>
            {
                // Do not do anything in case the tab is not selected.
                var run = false;
                vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(ResidentListTab); }));

                if (!run)
                {
                    residentListTabTimer.Stop();
                    return;
                }

                residentListTabTimer.Stop();

                try
                {
                    // Get the avatar positions.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getavatarpositions"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"entity", "region"}
                        }, wasOutput)).Result);

                    bool success;
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    var data =
                        new HashSet<List<string>>(CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                            .Select((x, i) => new {Index = i, Value = x})
                            .GroupBy(x => x.Index/3)
                            .Select(x => x.Select(v => v.Value).ToList()));
                    if (data.Count.Equals(0))
                        throw new Exception();

                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        // Remove rows that are not in the data update.
                        foreach (
                            var index in
                                ResidentListGridView.Rows.AsParallel().Cast<DataGridViewRow>()
                                    .Where(
                                        residentListRow =>
                                            !data.Any(q => q[1].Equals(residentListRow.Cells["ResidentListUUID"].Value)))
                                    .Select(q => q.Index))
                        {
                            ResidentListGridView.Rows.RemoveAt(index);
                        }
                        // Now update or add new data.
                        foreach (var dataComponents in data.Where(q => q.Count.Equals(3)))
                        {
                            var row =
                                ResidentListGridView.Rows.AsParallel()
                                    .Cast<DataGridViewRow>()
                                    .FirstOrDefault(q => q.Cells["ResidentListUUID"].Value.Equals(dataComponents[1]));
                            switch (row != null)
                            {
                                case true: // the row exists, so update it.
                                    row.Cells["ResidentListName"].Value = dataComponents[0];
                                    row.Cells["ResidentListUUID"].Value = dataComponents[1];
                                    row.Cells["ResidentListPosition"].Value = dataComponents[2];
                                    break;
                                case false: // the row dosn't exist, so add it.
                                    ResidentListGridView.Rows.Add(dataComponents[0], dataComponents[1],
                                        dataComponents[2]);
                                    break;
                            }
                        }
                    }));
                }
                catch (Exception)
                {
                }

                residentListTabTimer.Start();
            };
            residentListTabTimer.Start();

            estateTexturesTabTimer.Elapsed += (o, p) =>
            {
                // Do not do anything in case the tab is not selected.
                var run = false;
                vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(EstateTexturesTab); }));

                if (!run)
                {
                    estateTexturesTabTimer.Stop();
                    return;
                }

                estateTexturesTabTimer.Stop();

                try
                {
                    // Get the region terrain texture UUIDs.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getregionterraintextures"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password}
                        }, wasOutput)).Result);

                    bool success;
                    if (string.IsNullOrEmpty(result) ||
                        !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception();

                    var data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                    if (!data.Count.Equals(4))
                        throw new Exception();

                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTexturesLowUUIDBox.Text = data[0];
                        if (string.IsNullOrEmpty(RegionTexturesLowUUIDApplyBox.Text))
                        {
                            RegionTexturesLowUUIDApplyBox.Text = data[0];
                        }
                        RegionTexturesMiddleLowUUIDBox.Text = data[1];
                        if (string.IsNullOrEmpty(RegionTexturesMiddleLowUUIDApplyBox.Text))
                        {
                            RegionTexturesMiddleLowUUIDApplyBox.Text = data[1];
                        }
                        RegionTexturesMiddleHighUUIDBox.Text = data[2];
                        if (string.IsNullOrEmpty(RegionTexturesMiddleHighUUIDApplyBox.Text))
                        {
                            RegionTexturesMiddleHighUUIDApplyBox.Text = data[2];
                        }
                        RegionTexturesHighUUIDBox.Text = data[3];
                        if (string.IsNullOrEmpty(RegionTexturesHighUUIDApplyBox.Text))
                        {
                            RegionTexturesHighUUIDApplyBox.Text = data[1];
                        }
                    }));

                    Parallel.ForEach(Enumerable.Range(0, 4), i =>
                    {
                        result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "download"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"item", data[i]},
                                {"type", "Texture"},
                                {"format", "Jpeg"}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result) ||
                            !bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                            return;

                        var mapImageBytes = Convert.FromBase64String(wasInput(KeyValue.Get("data", result)));
                        using (var memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
                        {
                            groundTextureImages[i] = Image.FromStream(memoryStream);
                        }

                        switch (i)
                        {
                            case 0:
                                vassalForm.BeginInvoke(
                                    (MethodInvoker)
                                        (() => { RegionTexturesLowPictureBox.Image = groundTextureImages[0]; }));

                                break;
                            case 1:
                                vassalForm.BeginInvoke(
                                    (MethodInvoker)
                                        (() => { RegionTexturesMiddleLowPictureBox.Image = groundTextureImages[1]; }));

                                break;
                            case 2:
                                vassalForm.BeginInvoke(
                                    (MethodInvoker)
                                        (() => { RegionTexturesMiddleHighPictureBox.Image = groundTextureImages[2]; }));
                                break;
                            case 3:
                                vassalForm.BeginInvoke(
                                    (MethodInvoker)
                                        (() => { RegionTexturesHighPictureBox.Image = groundTextureImages[3]; }));
                                break;
                        }
                    });
                }
                catch (Exception)
                {
                }

                estateTexturesTabTimer.Start();
            };
            estateTexturesTabTimer.Start();
        }

        private void RequestedEditRegions(object sender, EventArgs e)
        {
            // Clear any selection.
            LoadedRegionsBox.SelectedIndex = -1;
            var regionEditForm = new RegionEditForm {TopMost = true};
            regionEditForm.Show();
        }

        private void RequestSelecting(object sender, TabControlCancelEventArgs e)
        {
            e.Cancel = !e.TabPage.Enabled;
        }

        private void RequestExportTopScripts(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                switch (vassalForm.ExportCSVDialog.ShowDialog())
                {
                    case DialogResult.OK:
                        var file = vassalForm.ExportCSVDialog.FileName;
                        new Thread(() =>
                        {
                            vassalForm.BeginInvoke((MethodInvoker) (() =>
                            {
                                try
                                {
                                    vassalForm.StatusText.Text = @"exporting...";
                                    vassalForm.StatusProgress.Value = 0;

                                    using (var streamWriter = new StreamWriter(file, false, Encoding.UTF8))
                                    {
                                        foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows)
                                        {
                                            streamWriter.WriteLine(CSV.FromEnumerable(new[]
                                            {
                                                topScriptsRow.Cells["TopScriptsScore"].Value.ToString(),
                                                topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString(),
                                                topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(),
                                                topScriptsRow.Cells["TopScriptsOwner"].Value.ToString(),
                                                topScriptsRow.Cells["TopScriptsPosition"].Value.ToString()
                                            }));
                                        }
                                    }

                                    vassalForm.StatusText.Text = @"exported";
                                    vassalForm.StatusProgress.Value = 100;
                                }
                                catch (Exception ex)
                                {
                                    vassalForm.StatusText.Text = ex.Message;
                                }
                            }));
                        })
                        {IsBackground = true}.Start();
                        break;
                }
            }));
        }

        private void RequestExportTopColliders(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                switch (vassalForm.ExportCSVDialog.ShowDialog())
                {
                    case DialogResult.OK:
                        var file = vassalForm.ExportCSVDialog.FileName;
                        new Thread(() =>
                        {
                            vassalForm.BeginInvoke((MethodInvoker) (() =>
                            {
                                try
                                {
                                    vassalForm.StatusText.Text = @"exporting...";
                                    vassalForm.StatusProgress.Value = 0;

                                    using (var streamWriter = new StreamWriter(file, false, Encoding.UTF8))
                                    {
                                        foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows)
                                        {
                                            streamWriter.WriteLine(CSV.FromEnumerable(new[]
                                            {
                                                topCollidersRow.Cells["TopCollidersScore"].Value.ToString(),
                                                topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString(),
                                                topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(),
                                                topCollidersRow.Cells["TopCollidersOwner"].Value.ToString(),
                                                topCollidersRow.Cells["TopCollidersPosition"].Value.ToString()
                                            }));
                                        }
                                    }

                                    vassalForm.StatusText.Text = @"exported";
                                    vassalForm.StatusProgress.Value = 100;
                                }
                                catch (Exception ex)
                                {
                                    vassalForm.StatusText.Text = ex.Message;
                                }
                            }));
                        })
                        {IsBackground = true}.Start();
                        break;
                }
            }));
        }

        private void RequestFilterTopScripts(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                Regex topScriptsRowRegex;
                switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
                {
                    case true:
                        topScriptsRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
                        break;
                    default:
                        topScriptsRowRegex = new Regex(@".+?", RegexOptions.Compiled);
                        break;
                }
                foreach (var topScriptsRow in TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>())
                {
                    topScriptsRow.Visible =
                        topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsScore"].Value.ToString()) ||
                        topScriptsRowRegex.IsMatch(
                            topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString()) ||
                        topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString()) ||
                        topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsOwner"].Value.ToString()) ||
                        topScriptsRowRegex.IsMatch(
                            topScriptsRow.Cells["TopScriptsPosition"].Value.ToString());
                }
            }));
        }

        private void RequestFilterTopColliders(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                Regex topCollidersRowRegex;
                switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
                {
                    case true:
                        topCollidersRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
                        break;
                    default:
                        topCollidersRowRegex = new Regex(@".+?", RegexOptions.Compiled);
                        break;
                }
                foreach (
                    var topCollidersRow in TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>())
                {
                    topCollidersRow.Visible =
                        topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersScore"].Value.ToString()) ||
                        topCollidersRowRegex.IsMatch(
                            topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString()) ||
                        topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString()) ||
                        topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersOwner"].Value.ToString()) ||
                        topCollidersRowRegex.IsMatch(
                            topCollidersRow.Cells["TopCollidersPosition"].Value.ToString());
                }
            }));
        }

        private void RequestReturnTopScriptsObjects(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                vassalForm.ReturnTopScriptsButton.Enabled = false;
                RegionTeleportGroup.Enabled = false;
            }));

            // Enqueue all the UUIDs to return.
            var returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                foreach (
                    var topScriptsRow in
                        TopScriptsGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    Vector3 objectPosition;
                    UUID returnUUID;
                    if (!UUID.TryParse(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), out returnUUID) ||
                        !Vector3.TryParse(topScriptsRow.Cells["TopScriptsPosition"].Value.ToString(), out objectPosition))
                        continue;
                    returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (returnUUIDs.Count.Equals(0))
            {
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    vassalForm.ReturnTopScriptsButton.Enabled = true;
                    RegionTeleportGroup.Enabled = true;
                }));
                return;
            }

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 0; }));
                    var totalObjects = returnUUIDs.Count;
                    do
                    {
                        // Dequeue the first object.
                        var objectData = returnUUIDs.Dequeue();

                        vassalForm.Invoke(
                            (MethodInvoker)
                                (() => { vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key; }));

                        var currentRegionName = string.Empty;
                        vassalForm.Invoke((MethodInvoker) (() => { currentRegionName = CurrentRegionName.Text; }));

                        // Teleport to the object.
                        var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "teleport"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"position", objectData.Value.ToString()},
                                {"region", currentRegionName},
                                {"fly", "True"}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result))
                        {
                            vassalForm.Invoke(
                                (MethodInvoker)
                                    (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
                            continue;
                        }

                        // Return the object.
                        result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "derez"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"item", objectData.Key.ToString()},
                                {"range", "32"}, // maximal prim size = 64 - middle bounding box at half
                                {"type", "ReturnToOwner"}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result))
                        {
                            vassalForm.Invoke(
                                (MethodInvoker)
                                    (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
                            continue;
                        }

                        bool success;
                        if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        {
                            vassalForm.Invoke(
                                (MethodInvoker)
                                    (() => { vassalForm.StatusText.Text = @"No success status could be retrieved. "; }));
                            continue;
                        }

                        switch (success)
                        {
                            case true:
                                vassalForm.Invoke((MethodInvoker) (() =>
                                {
                                    vassalForm.StatusText.Text = @"Returned object: " + objectData.Key;
                                    // Remove the row from the grid view.
                                    var row =
                                        TopScriptsGridView.Rows.AsParallel()
                                            .Cast<DataGridViewRow>()
                                            .FirstOrDefault(
                                                o => o.Cells["TopScriptsUUID"].Value.Equals(objectData.Key.ToString()));
                                    if (row == null) return;
                                    var i = row.Index;
                                    TopScriptsGridView.Rows.RemoveAt(i);
                                }));
                                break;
                            case false:
                                vassalForm.Invoke((MethodInvoker) (() =>
                                {
                                    vassalForm.StatusText.Text = @"Could not return object " + objectData.Key +
                                                                 @": " +
                                                                 wasInput(KeyValue.Get("error", result));
                                }));
                                break;
                        }
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            vassalForm.StatusProgress.Value =
                                Math.Min((int) (100d*Math.Abs(returnUUIDs.Count - totalObjects)/totalObjects), 100);
                        }));
                    } while (!returnUUIDs.Count.Equals(0));
                    vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 100; }));
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke(
                        (MethodInvoker) (() => { vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Allow teleports and enable button.
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        vassalForm.ReturnTopScriptsButton.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestReturnTopCollidersObjects(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                vassalForm.ReturnTopCollidersButton.Enabled = false;
                RegionTeleportGroup.Enabled = false;
            }));

            // Enqueue all the UUIDs to return.
            var returnObjectUUIDQueue = new Queue<KeyValuePair<UUID, Vector3>>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                foreach (
                    var topCollidersRow in
                        TopCollidersGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    Vector3 objectPosition;
                    UUID returnUUID;
                    if (!UUID.TryParse(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), out returnUUID) ||
                        !Vector3.TryParse(topCollidersRow.Cells["TopCollidersPosition"].Value.ToString(),
                            out objectPosition))
                        continue;
                    returnObjectUUIDQueue.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (returnObjectUUIDQueue.Count.Equals(0))
            {
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    vassalForm.ReturnTopCollidersButton.Enabled = true;
                    RegionTeleportGroup.Enabled = true;
                }));
                return;
            }

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 0; }));
                    var totalObjects = returnObjectUUIDQueue.Count;
                    do
                    {
                        // Dequeue the first object.
                        var objectData = returnObjectUUIDQueue.Dequeue();

                        vassalForm.Invoke(
                            (MethodInvoker)
                                (() => { vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key; }));

                        var currentRegionName = string.Empty;
                        vassalForm.Invoke((MethodInvoker) (() => { currentRegionName = CurrentRegionName.Text; }));

                        // Teleport to the object.
                        var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "teleport"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"position", objectData.Value.ToString()},
                                {"region", currentRegionName},
                                {"fly", "True"}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result))
                        {
                            vassalForm.Invoke(
                                (MethodInvoker)
                                    (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
                            continue;
                        }

                        // Return the object.
                        result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "derez"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"item", objectData.Key.ToString()},
                                {"range", "32"}, // maximal prim size = 64 - middle bounding box at half
                                {"type", "ReturnToOwner"}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result))
                        {
                            vassalForm.Invoke(
                                (MethodInvoker)
                                    (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
                            continue;
                        }

                        bool success;
                        if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        {
                            vassalForm.Invoke(
                                (MethodInvoker)
                                    (() => { vassalForm.StatusText.Text = @"No success status could be retrieved. "; }));
                            continue;
                        }

                        switch (success)
                        {
                            case true:
                                vassalForm.Invoke((MethodInvoker) (() =>
                                {
                                    vassalForm.StatusText.Text = @"Returned object: " + objectData.Key;
                                    // Remove the row from the grid view.
                                    var row =
                                        TopCollidersGridView.Rows.AsParallel()
                                            .Cast<DataGridViewRow>()
                                            .FirstOrDefault(
                                                o => o.Cells["TopCollidersUUID"].Value.Equals(objectData.Key.ToString()));
                                    if (row == null) return;
                                    var i = row.Index;
                                    TopCollidersGridView.Rows.RemoveAt(i);
                                }));
                                break;
                            case false:
                                vassalForm.Invoke((MethodInvoker) (() =>
                                {
                                    vassalForm.StatusText.Text = @"Could not return object " + objectData.Key +
                                                                 @": " +
                                                                 wasInput(KeyValue.Get("error", result));
                                }));
                                break;
                        }
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            vassalForm.StatusProgress.Value =
                                Math.Min(
                                    (int) (100d*Math.Abs(returnObjectUUIDQueue.Count - totalObjects)/totalObjects), 100);
                        }));
                    } while (!returnObjectUUIDQueue.Count.Equals(0));
                    vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 100; }));
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke(
                        (MethodInvoker) (() => { vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Allow teleports and enable button.
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        vassalForm.ReturnTopScriptsButton.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestBatchRestart(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                vassalForm.BatchRestartButton.Enabled = false;
                vassalForm.RegionRestartDelayBox.Enabled = false;
                RegionTeleportGroup.Enabled = false;
            }));

            // Enqueue all the regions to restart.
            var restartRegionQueue = new Queue<KeyValuePair<string, Vector3>>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                foreach (
                    var topCollidersRow in
                        BatchRestartGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    Vector3 objectPosition;
                    var regionName = topCollidersRow.Cells["BatchRestartRegionName"].Value.ToString();
                    if (string.IsNullOrEmpty(regionName) ||
                        !Vector3.TryParse(topCollidersRow.Cells["BatchRestartPosition"].Value.ToString(),
                            out objectPosition))
                        continue;
                    restartRegionQueue.Enqueue(new KeyValuePair<string, Vector3>(regionName, objectPosition));
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (restartRegionQueue.Count.Equals(0))
            {
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    vassalForm.BatchRestartButton.Enabled = true;
                    vassalForm.RegionRestartDelayBox.Enabled = true;
                    RegionTeleportGroup.Enabled = true;
                }));
                return;
            }

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    do
                    {
                        // Dequeue the first object.
                        var restartRegionData = restartRegionQueue.Dequeue();
                        DataGridViewRow currentDataGridViewRow = null;
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            currentDataGridViewRow = vassalForm.BatchRestartGridView.Rows.AsParallel()
                                .Cast<DataGridViewRow>()
                                .FirstOrDefault(
                                    o =>
                                        o.Cells["BatchRestartRegionName"].Value.ToString()
                                            .Equals(restartRegionData.Key, StringComparison.OrdinalIgnoreCase) &&
                                        o.Cells["BatchRestartPosition"].Value.ToString()
                                            .Equals(restartRegionData.Value.ToString(),
                                                StringComparison.OrdinalIgnoreCase));
                        }));

                        if (currentDataGridViewRow == null) continue;

                        try
                        {
                            var success = false;
                            string result;

                            // Retry to teleport to each region a few times.
                            var teleportRetries = 3;
                            do
                            {
                                vassalForm.Invoke((MethodInvoker) (() =>
                                {
                                    vassalForm.StatusText.Text = @"Attempting to teleport to " + restartRegionData.Key +
                                                                 @" " + @"(" +
                                                                 teleportRetries.ToString(Utils.EnUsCulture) +
                                                                 @")";
                                }));

                                // Teleport to the region.
                                result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                    KeyValue.Escape(new Dictionary<string, string>
                                    {
                                        {"command", "teleport"},
                                        {"group", vassalConfiguration.Group},
                                        {"password", vassalConfiguration.Password},
                                        {"position", restartRegionData.Value.ToString()},
                                        {"region", restartRegionData.Key},
                                        {"fly", "True"}
                                    }, wasOutput)).Result);

                                if (string.IsNullOrEmpty(result))
                                {
                                    vassalForm.Invoke(
                                        (MethodInvoker)
                                            (() =>
                                            {
                                                vassalForm.StatusText.Text = @"Error communicating with Corrade.";
                                            }));
                                    continue;
                                }
                                if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                {
                                    vassalForm.Invoke(
                                        (MethodInvoker)
                                            (() =>
                                            {
                                                vassalForm.StatusText.Text = @"No success status could be retrieved. ";
                                            }));
                                    continue;
                                }
                                switch (success)
                                {
                                    case true:
                                        vassalForm.Invoke(
                                            (MethodInvoker)
                                                (() => { vassalForm.StatusText.Text = @"Teleport succeeded."; }));
                                        break;
                                    default:
                                        // In case the destination is to close (Corrade status code 37559), 
                                        // then we are on the same region so no need to retry.
                                        uint status; //37559
                                        switch (
                                            uint.TryParse(wasInput(KeyValue.Get("status", result)), out status) &&
                                            status.Equals(37559))
                                        {
                                            case true: // We are on the region already!
                                                success = true;
                                                break;
                                            default:
                                                vassalForm.Invoke(
                                                    (MethodInvoker)
                                                        (() => { vassalForm.StatusText.Text = @"Teleport failed."; }));
                                                break;
                                        }
                                        break;
                                }

                                // Pause for teleport (10 teleports / 15s allowed).
                                Thread.Sleep(700);
                            } while (!success && !(--teleportRetries).Equals(0));

                            if (!success)
                                throw new Exception("Failed to teleport to region.");

                            result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "getregiondata"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"data", "IsEstateManager"}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade.");

                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved.");

                            if (!success)
                                throw new Exception("Could not retrieve estate rights.");

                            var data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                            if (!data.Count.Equals(2))
                                throw new Exception("Could not retrieve estate rights.");

                            bool isEstateManager;
                            switch (
                                bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
                                isEstateManager)
                            {
                                case true: // we are an estate manager
                                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                        KeyValue.Escape(new Dictionary<string, string>
                                        {
                                            {"command", "restartregion"},
                                            {"group", vassalConfiguration.Group},
                                            {"password", vassalConfiguration.Password},
                                            {"action", "restart"},
                                            {
                                                "delay",
                                                vassalForm.RegionRestartDelayBox.Text
                                            }
                                        }, wasOutput)).Result);

                                    if (string.IsNullOrEmpty(result))
                                        throw new Exception("Error communicating with Corrade.");

                                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                        throw new Exception("No success status could be retrieved.");

                                    if (!success)
                                        throw new Exception("Could not schedule a region restart.");

                                    vassalForm.Invoke((MethodInvoker) (() =>
                                    {
                                        vassalForm.StatusText.Text = @"Region scheduled for restart.";
                                        currentDataGridViewRow.Selected = false;
                                        currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
                                        foreach (
                                            var cell in
                                                currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                        {
                                            cell.ToolTipText = @"Region scheduled for restart.";
                                        }
                                    }));
                                    break;
                                default:
                                    throw new Exception("No estate manager rights for region restart.");
                            }
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke((MethodInvoker) (() =>
                            {
                                vassalForm.StatusText.Text = ex.Message;
                                currentDataGridViewRow.Selected = false;
                                currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
                                foreach (
                                    var cell in
                                        currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                {
                                    cell.ToolTipText = ex.Message;
                                }
                            }));
                        }
                        finally
                        {
                            // Pause for teleport (10 teleports / 15s allowed).
                            Thread.Sleep(700);
                        }
                    } while (!restartRegionQueue.Count.Equals(0));
                }
                catch (Exception)
                {
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Allow teleports and enable button.
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        vassalForm.BatchRestartButton.Enabled = true;
                        vassalForm.RegionRestartDelayBox.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestFilterResidentList(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                Regex residentListRowRegex;
                switch (!string.IsNullOrEmpty(ResidentListFilter.Text))
                {
                    case true:
                        residentListRowRegex = new Regex(ResidentListFilter.Text, RegexOptions.Compiled);
                        break;
                    default:
                        residentListRowRegex = new Regex(@".+?", RegexOptions.Compiled);
                        break;
                }
                foreach (
                    var residentListRow in ResidentListGridView.Rows.AsParallel().Cast<DataGridViewRow>())
                {
                    residentListRow.Visible =
                        residentListRowRegex.IsMatch(residentListRow.Cells["ResidentListName"].Value.ToString()) ||
                        residentListRowRegex.IsMatch(
                            residentListRow.Cells["ResidentListUUID"].Value.ToString()) ||
                        residentListRowRegex.IsMatch(residentListRow.Cells["ResidentListPosition"].Value.ToString());
                }
            }));
        }

        private void RequestBanAgents(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                ResidentListTeleportHomeGroup.Enabled = false;
                ResidentListBanGroup.Enabled = false;
                RegionTeleportGroup.Enabled = false;
            }));

            // Enqueue all the agents to ban.
            var agentsQueue = new Queue<UUID>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                foreach (
                    var residentListRow in
                        ResidentListGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    UUID agentUUID;
                    if (!UUID.TryParse(residentListRow.Cells["ResidentListUUID"].Value.ToString(), out agentUUID))
                        continue;
                    agentsQueue.Enqueue(agentUUID);
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (agentsQueue.Count.Equals(0))
            {
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    ResidentListBanGroup.Enabled = true;
                    RegionTeleportGroup.Enabled = true;
                }));
                return;
            }

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);
                try
                {
                    do
                    {
                        // Dequeue the first object.
                        var agentUUID = agentsQueue.Dequeue();
                        DataGridViewRow currentDataGridViewRow = null;
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            currentDataGridViewRow = vassalForm.ResidentListGridView.Rows.AsParallel()
                                .Cast<DataGridViewRow>()
                                .FirstOrDefault(
                                    o =>
                                        o.Cells["ResidentListUUID"].Value.ToString()
                                            .Equals(agentUUID.ToString(), StringComparison.OrdinalIgnoreCase));
                        }));

                        if (currentDataGridViewRow == null) continue;

                        try
                        {
                            var alsoBan = false;
                            vassalForm.Invoke(
                                (MethodInvoker) (() => { alsoBan = vassalForm.ResidentBanAllEstatesBox.Checked; }));

                            // Ban the resident.
                            var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "setestatelist"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"type", "ban"},
                                    {"action", "add"},
                                    {"agent", agentUUID.ToString()},
                                    {"all", alsoBan.ToString()}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade.");

                            bool success;
                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved.");

                            switch (success)
                            {
                                case true:
                                    vassalForm.Invoke((MethodInvoker) (() =>
                                    {
                                        vassalForm.StatusText.Text = @"Resident banned.";
                                        currentDataGridViewRow.Selected = false;
                                        currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
                                        foreach (
                                            var cell in
                                                currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                        {
                                            cell.ToolTipText = @"Resident banned.";
                                        }
                                    }));
                                    break;
                                default:
                                    throw new Exception("Unable to ban resident.");
                            }
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke((MethodInvoker) (() =>
                            {
                                vassalForm.StatusText.Text = ex.Message;
                                currentDataGridViewRow.Selected = false;
                                currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
                                foreach (
                                    var cell in
                                        currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                {
                                    cell.ToolTipText = ex.Message;
                                }
                            }));
                        }
                    } while (agentsQueue.Count.Equals(0));
                }
                catch (Exception)
                {
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Allow teleports and enable button.
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        ResidentListTeleportHomeGroup.Enabled = true;
                        ResidentListBanGroup.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestRipTerrain(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                RipTerrainButton.Enabled = false;
            }));

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    // Get the map heights.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getterrainheight"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"entity", "region"}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade.");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved.");

                    if (!success)
                        throw new Exception("Could not get terrain heights.");

                    var heights = new List<double>();
                    foreach (var map in CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))))
                    {
                        double height;
                        if (!double.TryParse(map, out height))
                            continue;
                        heights.Add(height);
                    }
                    if (heights.Count.Equals(0))
                        throw new Exception("Could not get terrain heights.");

                    var maxHeight = heights.Max();
                    using (var bitmap = new Bitmap(256, 256))
                    {
                        foreach (var x in Enumerable.Range(1, 255))
                        {
                            foreach (var y in Enumerable.Range(1, 255))
                            {
                                bitmap.SetPixel(x, 256 - y,
                                    Color.FromArgb(
                                        Math.Max(
                                            (int) Numerics.MapValueToRange(heights[256*x + y], 0, maxHeight, 0, 255), 0),
                                        0, 0));
                            }
                        }
                        var closureBitmap = (Bitmap) bitmap.Clone();
                        vassalForm.BeginInvoke((MethodInvoker) (() =>
                        {
                            switch (vassalForm.SavePNGFileDialog.ShowDialog())
                            {
                                case DialogResult.OK:
                                    var file = vassalForm.SavePNGFileDialog.FileName;
                                    new Thread(() =>
                                    {
                                        vassalForm.BeginInvoke((MethodInvoker) (() =>
                                        {
                                            try
                                            {
                                                vassalForm.StatusText.Text = @"saving terrain...";
                                                vassalForm.StatusProgress.Value = 0;

                                                closureBitmap.Save(file, ImageFormat.Png);

                                                vassalForm.StatusText.Text = @"terrain saved";
                                                vassalForm.StatusProgress.Value = 100;
                                            }
                                            catch (Exception ex)
                                            {
                                                vassalForm.StatusText.Text = ex.Message;
                                            }
                                            finally
                                            {
                                                closureBitmap.Dispose();
                                            }
                                        }));
                                    })
                                    {IsBackground = true}.Start();
                                    break;
                            }
                        }));
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = true;
                        RipTerrainButton.Enabled = true;
                    }));
                }
            }) {IsBackground = true}.Start();
        }

        private void RequestDownloadTerrain(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                DownloadTerrainButton.Enabled = false;
            }));

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    // Download the terrain.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "terrain"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"action", "get"}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade.");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved.");

                    if (!success)
                        throw new Exception("Could not download terrain.");

                    var data = Convert.FromBase64String(wasInput(KeyValue.Get("data", result)));

                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        switch (vassalForm.SaveRawFileDialog.ShowDialog())
                        {
                            case DialogResult.OK:
                                var file = vassalForm.SaveRawFileDialog.FileName;
                                new Thread(() =>
                                {
                                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                                    {
                                        try
                                        {
                                            vassalForm.StatusText.Text = @"saving terrain...";
                                            vassalForm.StatusProgress.Value = 0;

                                            File.WriteAllBytes(file, data);

                                            vassalForm.StatusText.Text = @"terrain saved";
                                            vassalForm.StatusProgress.Value = 100;
                                        }
                                        catch (Exception ex)
                                        {
                                            vassalForm.StatusText.Text = ex.Message;
                                        }
                                    }));
                                })
                                {IsBackground = true}.Start();
                                break;
                        }
                    }));
                }
                catch (Exception ex)
                {
                    vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        DownloadTerrainButton.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestUploadTerrain(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                UploadTerrainButton.Enabled = false;
            }));

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    byte[] data = null;
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        switch (vassalForm.LoadRawFileDialog.ShowDialog())
                        {
                            case DialogResult.OK:
                                var file = vassalForm.LoadRawFileDialog.FileName;
                                vassalForm.StatusText.Text = @"loading terrain...";
                                vassalForm.StatusProgress.Value = 0;

                                data = File.ReadAllBytes(file);

                                vassalForm.StatusText.Text = @"terrain loaded";
                                vassalForm.StatusProgress.Value = 100;
                                break;
                        }
                    }));

                    // Upload the terrain.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "terrain"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"action", "set"},
                            {"data", Convert.ToBase64String(data)}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade.");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved.");

                    if (!success)
                        throw new Exception("Could not upload terrain.");
                }
                catch (Exception ex)
                {
                    vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        UploadTerrainButton.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestTabsChanged(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                overviewTabTimer.Stop();
                regionsStateTabTimer.Stop();
                residentListTabTimer.Stop();
                estateTopTabTimer.Stop();

                if (Tabs.SelectedTab.Equals(OverviewTab))
                {
                    overviewTabTimer.Start();
                    return;
                }
                if (Tabs.SelectedTab.Equals(RegionsStateTab))
                {
                    regionsStateTabTimer.Start();
                    return;
                }
                if (Tabs.SelectedTab.Equals(ResidentListTab))
                {
                    residentListTabTimer.Start();
                    return;
                }
                if (Tabs.SelectedTab.Equals(EstateTopTab))
                {
                    estateTopTabTimer.Start();
                    return;
                }
                if (Tabs.SelectedTab.Equals(EstateTexturesTab))
                {
                    estateTexturesTabTimer.Start();
                }
            }));
        }

        private void RequestFilterEstateList(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                Regex estateListRowRegex;
                switch (!string.IsNullOrEmpty(EstateListFilter.Text))
                {
                    case true:
                        estateListRowRegex = new Regex(EstateListFilter.Text, RegexOptions.Compiled);
                        break;
                    default:
                        estateListRowRegex = new Regex(@".+?", RegexOptions.Compiled);
                        break;
                }
                foreach (var estateListRow in EstateListGridView.Rows.AsParallel().Cast<DataGridViewRow>())
                {
                    estateListRow.Visible =
                        estateListRowRegex.IsMatch(estateListRow.Cells["EstateListName"].Value.ToString());
                }
            }));
        }

        private void EstateListSelected(object sender, EventArgs e)
        {
            var selectedEstateListType = string.Empty;
            var queryEstateList = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
                selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
                switch (
                    !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
                {
                    case true:
                        queryEstateList = true;
                        break;
                    default:
                        EstateListsResidentsGroup.Enabled = false;
                        EstateListsGroupsGroup.Enabled = false;
                        queryEstateList = false;
                        break;
                }
            }));

            if (!queryEstateList) return;

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    // Disable controls.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = false;
                        EstateListsResidentsGroup.Enabled = false;
                        EstateListsGroupsGroup.Enabled = false;
                    }));

                    // Get the selected estate list.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getestatelist"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", selectedEstateListType}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade.");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved.");

                    if (!success)
                        throw new Exception("Could not retrieve estate list.");

                    vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
                    foreach (var data in CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                        .Where(x => !string.IsNullOrEmpty(x))
                        .Select((x, i) => new {Index = i, Value = x})
                        .GroupBy(x => x.Index/2)
                        .Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
                    {
                        vassalForm.Invoke(
                            (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Enable controls
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        vassalForm.RegionTeleportGroup.Enabled = true;

                        switch (selectedEstateListType)
                        {
                            case "ban":
                            case "manager":
                            case "user":
                                EstateListsResidentsGroup.Enabled = true;
                                EstateListsGroupsGroup.Enabled = false;
                                break;
                            case "group":
                                EstateListsResidentsGroup.Enabled = false;
                                EstateListsGroupsGroup.Enabled = true;
                                break;
                        }
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestRemoveEstateListMember(object sender, EventArgs e)
        {
            // Get the estate list type.
            var selectedEstateListType = string.Empty;
            var queryEstateList = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                if (vassalForm.EstateListSelectBox.SelectedItem == null)
                {
                    queryEstateList = false;
                    return;
                }
                selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
                switch (
                    !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
                {
                    case true:
                        queryEstateList = true;
                        break;
                    default:
                        queryEstateList = false;
                        break;
                }
            }));

            // If not estate list type is selected then return.
            if (!queryEstateList) return;

            // Enqueue all the regions to restart.
            var estateListMembersQueue = new Queue<UUID>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                foreach (
                    var estateListRow in
                        EstateListGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    UUID estateListMemberUUID;
                    if (!UUID.TryParse(estateListRow.Cells["EstateListUUID"].Value.ToString(),
                        out estateListMemberUUID))
                        continue;
                    estateListMembersQueue.Enqueue(estateListMemberUUID);
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (estateListMembersQueue.Count.Equals(0)) return;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                RemoveEstateListMemberButton.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);
                    var memberUUID = UUID.Zero;
                    do
                    {
                        try
                        {
                            memberUUID = estateListMembersQueue.Dequeue();

                            // Remove the agent or group from the list.
                            var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "setestatelist"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"type", selectedEstateListType},
                                    {"action", "remove"},
                                    {selectedEstateListType.Equals("group") ? "target" : "agent", memberUUID.ToString()}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade");

                            bool success;
                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved");

                            if (!success)
                                throw new Exception("Unable to remove member");

                            vassalForm.Invoke((MethodInvoker) (() =>
                            {
                                foreach (
                                    var i in
                                        EstateListGridView.Rows.AsParallel()
                                            .Cast<DataGridViewRow>()
                                            .Where(
                                                o =>
                                                    o.Cells["EstateListUUID"].Value.ToString()
                                                        .Equals(memberUUID.ToString(),
                                                            StringComparison.OrdinalIgnoreCase)).Select(o => o.Index)
                                    )
                                {
                                    EstateListGridView.Rows.RemoveAt(i);
                                }
                            }));
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke(
                                (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + memberUUID; }));
                        }
                    } while (!estateListMembersQueue.Count.Equals(0));
                }
                catch (Exception)
                {
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Enable teleports and enable button.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = true;
                        RemoveEstateListMemberButton.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestEstateListsAddResident(object sender, EventArgs e)
        {
            // Get the estate list type.
            var selectedEstateListType = string.Empty;
            var queryEstateList = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
                switch (
                    !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
                {
                    case true:
                        queryEstateList = true;
                        break;
                    default:
                        queryEstateList = false;
                        break;
                }
            }));

            // If not estate list type is selected then return.
            if (!queryEstateList) return;

            var firstName = string.Empty;
            var lastName = string.Empty;

            vassalForm.Invoke((MethodInvoker) (() =>
            {
                switch (string.IsNullOrEmpty(EstateListsResidentFirstName.Text))
                {
                    case true:
                        EstateListsResidentFirstName.BackColor = Color.MistyRose;
                        return;
                    default:
                        EstateListsResidentFirstName.BackColor = Color.Empty;
                        break;
                }
                firstName = EstateListsResidentFirstName.Text;
                switch (string.IsNullOrEmpty(EstateListsResidentLastName.Text))
                {
                    case true:
                        EstateListsResidentLastName.BackColor = Color.MistyRose;
                        return;
                    default:
                        EstateListsResidentLastName.BackColor = Color.Empty;
                        break;
                }
                lastName = EstateListsResidentLastName.Text;
            }));

            if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) return;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                EstateListsResidentsGroup.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    // Add the resident to the list.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "setestatelist"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", selectedEstateListType},
                            {"action", "add"},
                            {"firstname", firstName},
                            {"lastname", lastName}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    if (!success)
                        throw new Exception("Unable to add resident");

                    // Retrieve the estate list for updates.
                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getestatelist"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", selectedEstateListType}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade.");

                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved.");

                    if (!success)
                        throw new Exception("Could not retrieve estate list.");

                    vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
                    foreach (var data in CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                        .Where(x => !string.IsNullOrEmpty(x))
                        .Select((x, i) => new {Index = i, Value = x})
                        .GroupBy(x => x.Index/2)
                        .Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
                    {
                        vassalForm.Invoke(
                            (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke(
                        (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + firstName + @" " + lastName; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Enable teleports and enable button.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = true;
                        EstateListsResidentsGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestEstateListsAddGroup(object sender, EventArgs e)
        {
            // Get the estate list type.
            var selectedEstateListType = string.Empty;
            var queryEstateList = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
                switch (
                    !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
                {
                    case true:
                        queryEstateList = true;
                        break;
                    default:
                        queryEstateList = false;
                        break;
                }
            }));

            // If not estate list type is selected then return.
            if (!queryEstateList) return;

            var target = string.Empty;

            vassalForm.Invoke((MethodInvoker) (() =>
            {
                switch (string.IsNullOrEmpty(EstateListsAddGroupBox.Text))
                {
                    case true:
                        EstateListsAddGroupBox.BackColor = Color.MistyRose;
                        return;
                    default:
                        EstateListsAddGroupBox.BackColor = Color.Empty;
                        break;
                }
                target = EstateListsAddGroupBox.Text;
            }));

            if (string.IsNullOrEmpty(target)) return;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                EstateListsGroupsGroup.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    // Add the group to the list.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "setestatelist"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", selectedEstateListType},
                            {"action", "add"},
                            {"target", target}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    if (!success)
                        throw new Exception("Unable to add group");

                    // Retrieve the estate list for updates.
                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "getestatelist"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"type", selectedEstateListType}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade.");

                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved.");

                    if (!success)
                        throw new Exception("Could not retrieve estate list.");

                    vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
                    foreach (var data in CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                        .Where(x => !string.IsNullOrEmpty(x))
                        .Select((x, i) => new {Index = i, Value = x})
                        .GroupBy(x => x.Index/2)
                        .Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
                    {
                        vassalForm.Invoke(
                            (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Enable teleports and enable button.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = true;
                        EstateListsGroupsGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestRegionDebugApply(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                ApplyRegionDebugButton.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    var scripts = false;
                    var collisons = false;
                    var physics = false;
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        scripts = RegionDebugScriptsBox.Checked;
                        collisons = RegionDebugCollisionsBox.Checked;
                        physics = RegionDebugPhysicsBox.Checked;
                    }));

                    // Set the debug settings.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "setregiondebug"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"scripts", scripts.ToString()},
                            {"collisions", collisons.ToString()},
                            {"physics", physics.ToString()}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    if (!success)
                        throw new Exception("Unable to set region debug");
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                }

                // Block teleports and disable button.
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    RegionTeleportGroup.Enabled = true;
                    ApplyRegionDebugButton.Enabled = true;
                }));
            })
            {IsBackground = true}.Start();
        }

        private void RequestApplyRegionInfo(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                ApplyRegionInfoButton.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    var terraform = false;
                    var fly = false;
                    var damage = false;
                    var resell = false;
                    var push = false;
                    var parcel = false;
                    var mature = false;
                    uint agentLimit = 20;
                    var objectBonus = 2.0;

                    var run = false;

                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        terraform = RegionInfoTerraformBox.Checked;
                        fly = RegionInfoFlyBox.Checked;
                        damage = RegionInfoDamageBox.Checked;
                        resell = RegioninfoResellBox.Checked;
                        push = RegionInfoPushBox.Checked;
                        parcel = RegionInfoParcelBox.Checked;
                        mature = RegionInfoMatureBox.Checked;
                        switch (!uint.TryParse(RegionInfoAgentLimitBox.Text, out agentLimit))
                        {
                            case true:
                                RegionInfoAgentLimitBox.BackColor = Color.MistyRose;
                                return;
                            default:
                                RegionInfoAgentLimitBox.BackColor = Color.Empty;
                                run = true;
                                break;
                        }
                        switch (!double.TryParse(RegionInfoObjectBonusBox.Text, out objectBonus))
                        {
                            case true:
                                RegionInfoObjectBonusBox.BackColor = Color.MistyRose;
                                return;
                            default:
                                RegionInfoAgentLimitBox.BackColor = Color.Empty;
                                break;
                        }

                        run = true;
                    }));

                    if (!run) return;

                    // Set the debug settings.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "setregioninfo"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"terraform", terraform.ToString()},
                            {"fly", fly.ToString()},
                            {"damage", damage.ToString()},
                            {"resell", resell.ToString()},
                            {"push", push.ToString()},
                            {"parcel", parcel.ToString()},
                            {"mature", mature.ToString()},
                            {"limit", agentLimit.ToString(Utils.EnUsCulture)},
                            {"bonus", objectBonus.ToString(Utils.EnUsCulture)}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    if (!success)
                        throw new Exception("Unable to set region info");
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                }

                // Block teleports and disable button.
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    RegionTeleportGroup.Enabled = true;
                    ApplyRegionInfoButton.Enabled = true;
                }));
            })
            {IsBackground = true}.Start();
        }

        private void RequestEstateTexturesApply(object sender, EventArgs e)
        {
            var groundTextureUUIDs = new List<UUID>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                UUID textureUUID;
                switch (!UUID.TryParse(RegionTexturesLowUUIDApplyBox.Text, out textureUUID))
                {
                    case true:
                        RegionTexturesLowUUIDApplyBox.BackColor = Color.MistyRose;
                        return;
                    default:
                        RegionTexturesLowUUIDApplyBox.BackColor = Color.Empty;
                        break;
                }
                groundTextureUUIDs.Add(textureUUID);

                switch (!UUID.TryParse(RegionTexturesMiddleLowUUIDApplyBox.Text, out textureUUID))
                {
                    case true:
                        RegionTexturesMiddleLowUUIDApplyBox.BackColor = Color.MistyRose;
                        return;
                    default:
                        RegionTexturesMiddleLowUUIDApplyBox.BackColor = Color.Empty;
                        break;
                }
                groundTextureUUIDs.Add(textureUUID);

                switch (!UUID.TryParse(RegionTexturesMiddleHighUUIDApplyBox.Text, out textureUUID))
                {
                    case true:
                        RegionTexturesMiddleHighUUIDApplyBox.BackColor = Color.MistyRose;
                        return;
                    default:
                        RegionTexturesMiddleHighUUIDApplyBox.BackColor = Color.Empty;
                        break;
                }
                groundTextureUUIDs.Add(textureUUID);

                switch (!UUID.TryParse(RegionTexturesHighUUIDApplyBox.Text, out textureUUID))
                {
                    case true:
                        RegionTexturesHighUUIDApplyBox.BackColor = Color.MistyRose;
                        return;
                    default:
                        RegionTexturesHighUUIDApplyBox.BackColor = Color.Empty;
                        break;
                }
                groundTextureUUIDs.Add(textureUUID);
            }));

            if (!groundTextureUUIDs.Count.Equals(4)) return;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                GroundTexturesGroup.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    // Set the debug settings.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "setregionterraintextures"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"data", CSV.FromEnumerable(groundTextureUUIDs.Select(o => o.ToString()))}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    if (!success)
                        throw new Exception("Unable to apply estate ground textures");
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                }

                // Block teleports and disable button.
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    RegionTeleportGroup.Enabled = true;
                    GroundTexturesGroup.Enabled = true;
                }));
            })
            {IsBackground = true};
        }

        private void RequestDownloadRegionTexture(object sender, EventArgs e)
        {
            var textureName = string.Empty;
            var textureUUID = UUID.Zero;
            var run = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                var button = sender as Button;
                if (button == null)
                {
                    run = false;
                    return;
                }
                textureName = button.Tag.ToString();
                switch (textureName)
                {
                    case "Low":
                        if (!UUID.TryParse(RegionTexturesLowUUIDBox.Text, out textureUUID))
                        {
                            run = false;
                            return;
                        }
                        goto case "MiddleLow";
                    case "MiddleLow":
                        if (!UUID.TryParse(RegionTexturesMiddleLowUUIDBox.Text, out textureUUID))
                        {
                            run = false;
                            return;
                        }
                        goto case "MiddleHigh";
                    case "MiddleHigh":
                        if (!UUID.TryParse(RegionTexturesMiddleHighUUIDBox.Text, out textureUUID))
                        {
                            run = false;
                            return;
                        }
                        goto case "High";
                    case "High":
                        if (!UUID.TryParse(RegionTexturesHighUUIDBox.Text, out textureUUID))
                        {
                            run = false;
                            return;
                        }
                        run = true;
                        break;
                }
            }));

            if (!run) return;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                GroundTexturesGroup.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "download"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"item", textureUUID.ToString()},
                            {"type", "Texture"},
                            {"format", "Png"}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    var mapImageBytes = Convert.FromBase64String(wasInput(KeyValue.Get("data", result)));
                    Image mapImage;
                    using (var memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
                    {
                        mapImage = Image.FromStream(memoryStream);
                    }

                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        switch (vassalForm.SavePNGFileDialog.ShowDialog())
                        {
                            case DialogResult.OK:
                                var file = vassalForm.SavePNGFileDialog.FileName;
                                new Thread(() =>
                                {
                                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                                    {
                                        try
                                        {
                                            vassalForm.StatusText.Text = @"saving texture...";
                                            vassalForm.StatusProgress.Value = 0;

                                            mapImage.Save(file, ImageFormat.Png);

                                            vassalForm.StatusText.Text = @"texture saved";
                                            vassalForm.StatusProgress.Value = 100;
                                        }
                                        catch (Exception ex)
                                        {
                                            vassalForm.StatusText.Text = ex.Message;
                                        }
                                        finally
                                        {
                                            mapImage.Dispose();
                                        }
                                    }));
                                })
                                {IsBackground = true}.Start();
                                break;
                        }
                    }));
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                }

                // Block teleports and disable button.
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    RegionTeleportGroup.Enabled = true;
                    GroundTexturesGroup.Enabled = true;
                }));
            })
            {IsBackground = true}.Start();
        }

        private void RequestEstateListsAddGroupsFromCSV(object sender, EventArgs e)
        {
            // Get the estate list type.
            var selectedEstateListType = string.Empty;
            var queryEstateList = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
                selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
                switch (
                    !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
                {
                    case true:
                        queryEstateList = true;
                        break;
                    default:
                        queryEstateList = false;
                        break;
                }
            }));

            // If not estate list type is selected then return.
            if (!queryEstateList) return;

            var targets = new Queue<KeyValuePair<string, UUID>>();

            vassalForm.Invoke((MethodInvoker) (() =>
            {
                switch (vassalForm.LoadCSVFile.ShowDialog())
                {
                    case DialogResult.OK:
                        var file = vassalForm.LoadCSVFile.FileName;
                        try
                        {
                            vassalForm.StatusText.Text = @"loading group list...";
                            vassalForm.StatusProgress.Value = 0;

                            // import groups
                            UUID targetUUID;
                            foreach (var target in
                                File.ReadAllLines(file)
                                    .AsParallel()
                                    .Select(o => new List<string>(CSV.ToEnumerable(o)))
                                    .Where(o => o.Count == 2)
                                    .ToDictionary(o => o.First(),
                                        p =>
                                            UUID.TryParse(p.Last(), out targetUUID)
                                                ? targetUUID
                                                : UUID.Zero))
                            {
                                targets.Enqueue(target);
                            }

                            vassalForm.StatusText.Text = @"group list loaded";
                            vassalForm.StatusProgress.Value = 100;
                        }
                        catch (Exception ex)
                        {
                            vassalForm.StatusText.Text = ex.Message;
                        }
                        break;
                }
            }));

            if (targets.Count.Equals(0)) return;
            var initialQueueSize = targets.Count;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                EstateListsGroupsGroup.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    do
                    {
                        var target = targets.Dequeue();

                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            StatusText.Text = @"Adding to estate list: " + target.Key;
                            vassalForm.StatusProgress.Value =
                                Math.Min((int) (100d*Math.Abs(targets.Count - initialQueueSize)/initialQueueSize), 100);
                        }));

                        // Skip any items that already exist.
                        var run = false;
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            run =
                                !EstateListGridView.Rows.AsParallel()
                                    .Cast<DataGridViewRow>()
                                    .Any(o => o.Cells["EstateListUUID"].Value.ToString().Equals(target.Value.ToString()));
                        }));
                        if (!run) continue;

                        // Skip broken UUIDs.
                        if (target.Value.Equals(UUID.Zero)) continue;

                        try
                        {
                            // Add the group to the list.
                            var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "setestatelist"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"type", selectedEstateListType},
                                    {"action", "add"},
                                    {"target", target.Value.ToString()}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade");

                            bool success;
                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved");

                            if (!success)
                                throw new Exception("Unable to add group");
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke(
                                (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target.Value; }));
                        }
                    } while (!targets.Count.Equals(0));

                    // Retrieve the estate list.
                    try
                    {
                        // Retrieve the estate list for updates.
                        var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "getestatelist"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"type", selectedEstateListType}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result))
                            throw new Exception("Error communicating with Corrade.");

                        bool success;
                        if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                            throw new Exception("No success status could be retrieved.");

                        if (!success)
                            throw new Exception("Could not retrieve estate list.");

                        vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
                        foreach (var data in CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                            .Where(x => !string.IsNullOrEmpty(x))
                            .Select((x, i) => new {Index = i, Value = x})
                            .GroupBy(x => x.Index/2)
                            .Select(x => x.Select(v => v.Value).ToList()))
                        {
                            vassalForm.BeginInvoke(
                                (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
                        }
                    }
                    catch (Exception ex)
                    {
                        vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Enable teleports and enable button.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = true;
                        EstateListsGroupsGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestEstateListsAddResidentsFromCSV(object sender, EventArgs e)
        {
            // Get the estate list type.
            var selectedEstateListType = string.Empty;
            var queryEstateList = false;
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
                selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
                switch (
                    !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
                {
                    case true:
                        queryEstateList = true;
                        break;
                    default:
                        queryEstateList = false;
                        break;
                }
            }));

            // If not estate list type is selected then return.
            if (!queryEstateList) return;

            var targets = new Queue<KeyValuePair<string, UUID>>();

            vassalForm.Invoke((MethodInvoker) (() =>
            {
                switch (vassalForm.LoadCSVFile.ShowDialog())
                {
                    case DialogResult.OK:
                        var file = vassalForm.LoadCSVFile.FileName;
                        try
                        {
                            vassalForm.StatusText.Text = @"loading residents list...";
                            vassalForm.StatusProgress.Value = 0;

                            // import groups
                            UUID targetUUID;
                            foreach (var target in
                                File.ReadAllLines(file)
                                    .AsParallel()
                                    .Select(o => new List<string>(CSV.ToEnumerable(o)))
                                    .Where(o => o.Count == 2)
                                    .ToDictionary(o => o.First(),
                                        p =>
                                            UUID.TryParse(p.Last(), out targetUUID)
                                                ? targetUUID
                                                : UUID.Zero))
                            {
                                targets.Enqueue(target);
                            }

                            vassalForm.StatusText.Text = @"residents list loaded";
                            vassalForm.StatusProgress.Value = 100;
                        }
                        catch (Exception ex)
                        {
                            vassalForm.StatusText.Text = ex.Message;
                        }
                        break;
                }
            }));

            if (targets.Count.Equals(0)) return;
            var initialQueueSize = targets.Count;

            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                EstateListsResidentsGroup.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    do
                    {
                        var target = targets.Dequeue();

                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            StatusText.Text = @"Adding to estate list: " + target.Key;
                            vassalForm.StatusProgress.Value =
                                Math.Min((int) (100d*Math.Abs(targets.Count - initialQueueSize)/initialQueueSize), 100);
                        }));

                        // Skip any items that already exist.
                        var run = false;
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            run =
                                !EstateListGridView.Rows.AsParallel()
                                    .Cast<DataGridViewRow>()
                                    .Any(o => o.Cells["EstateListUUID"].Value.ToString().Equals(target.Value.ToString()));
                        }));
                        if (!run) continue;

                        // Skip broken UUIDs.
                        if (target.Value.Equals(UUID.Zero)) continue;

                        try
                        {
                            // Add the group to the list.
                            var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "setestatelist"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"type", selectedEstateListType},
                                    {"action", "add"},
                                    {"agent", target.Value.ToString()}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade");

                            bool success;
                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved");

                            if (!success)
                                throw new Exception("Unable to add resident");
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke(
                                (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target.Value; }));
                        }
                    } while (!targets.Count.Equals(0));

                    // Retrieve the estate list.
                    try
                    {
                        // Retrieve the estate list for updates.
                        var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                            KeyValue.Escape(new Dictionary<string, string>
                            {
                                {"command", "getestatelist"},
                                {"group", vassalConfiguration.Group},
                                {"password", vassalConfiguration.Password},
                                {"type", selectedEstateListType}
                            }, wasOutput)).Result);

                        if (string.IsNullOrEmpty(result))
                            throw new Exception("Error communicating with Corrade.");

                        bool success;
                        if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                            throw new Exception("No success status could be retrieved.");

                        if (!success)
                            throw new Exception("Could not retrieve estate list.");

                        vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
                        foreach (var data in CSV.ToEnumerable(wasInput(KeyValue.Get("data", result)))
                            .Where(x => !string.IsNullOrEmpty(x))
                            .Select((x, i) => new {Index = i, Value = x})
                            .GroupBy(x => x.Index/2)
                            .Select(x => x.Select(v => v.Value).ToList()))
                        {
                            vassalForm.BeginInvoke(
                                (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
                        }
                    }
                    catch (Exception ex)
                    {
                        vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                    }
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Enable teleports and enable button.
                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        RegionTeleportGroup.Enabled = true;
                        EstateListsResidentsGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestExportEstateList(object sender, EventArgs e)
        {
            vassalForm.BeginInvoke((MethodInvoker) (() =>
            {
                switch (vassalForm.ExportCSVDialog.ShowDialog())
                {
                    case DialogResult.OK:
                        var file = vassalForm.ExportCSVDialog.FileName;
                        new Thread(() =>
                        {
                            vassalForm.BeginInvoke((MethodInvoker) (() =>
                            {
                                try
                                {
                                    vassalForm.StatusText.Text = @"exporting...";
                                    vassalForm.StatusProgress.Value = 0;

                                    using (var streamWriter = new StreamWriter(file, false, Encoding.UTF8))
                                    {
                                        foreach (DataGridViewRow estateListRow in EstateListGridView.Rows)
                                        {
                                            streamWriter.WriteLine(CSV.FromEnumerable(new[]
                                            {
                                                estateListRow.Cells["EstateListName"].Value.ToString(),
                                                estateListRow.Cells["EstateListUUID"].Value.ToString()
                                            }));
                                        }
                                    }

                                    vassalForm.StatusText.Text = @"exported";
                                    vassalForm.StatusProgress.Value = 100;
                                }
                                catch (Exception ex)
                                {
                                    vassalForm.StatusText.Text = ex.Message;
                                }
                            }));
                        })
                        {IsBackground = true}.Start();
                        break;
                }
            }));
        }

        private void RequestTeleportHome(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                ResidentListTeleportHomeGroup.Enabled = false;
                ResidentListBanGroup.Enabled = false;
                RegionTeleportGroup.Enabled = false;
            }));

            // Enqueue all the agents to teleport home.
            var agentsQueue = new Queue<UUID>();
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                foreach (
                    var residentListRow in
                        ResidentListGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    UUID agentUUID;
                    if (!UUID.TryParse(residentListRow.Cells["ResidentListUUID"].Value.ToString(), out agentUUID))
                        continue;
                    agentsQueue.Enqueue(agentUUID);
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (agentsQueue.Count.Equals(0))
            {
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    ResidentListBanGroup.Enabled = true;
                    RegionTeleportGroup.Enabled = true;
                }));
                return;
            }

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);
                try
                {
                    do
                    {
                        // Dequeue the first object.
                        var agentUUID = agentsQueue.Dequeue();
                        DataGridViewRow currentDataGridViewRow = null;
                        vassalForm.Invoke((MethodInvoker) (() =>
                        {
                            currentDataGridViewRow = vassalForm.ResidentListGridView.Rows.AsParallel()
                                .Cast<DataGridViewRow>()
                                .FirstOrDefault(
                                    o =>
                                        o.Cells["ResidentListUUID"].Value.ToString()
                                            .Equals(agentUUID.ToString(), StringComparison.OrdinalIgnoreCase));
                        }));

                        if (currentDataGridViewRow == null) continue;

                        try
                        {
                            // Teleport the user home.
                            var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "estateteleportusershome"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"avatars", agentUUID.ToString()}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade.");

                            bool success;
                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved.");

                            switch (success)
                            {
                                case true:
                                    vassalForm.Invoke((MethodInvoker) (() =>
                                    {
                                        vassalForm.StatusText.Text = @"Resident teleported home.";
                                        currentDataGridViewRow.Selected = false;
                                        currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
                                        foreach (
                                            var cell in
                                                currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                        {
                                            cell.ToolTipText = @"Resident teleported home.";
                                        }
                                    }));
                                    break;
                                default:
                                    throw new Exception("Unable to teleport resident home.");
                            }
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke((MethodInvoker) (() =>
                            {
                                vassalForm.StatusText.Text = ex.Message;
                                currentDataGridViewRow.Selected = false;
                                currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
                                foreach (
                                    var cell in
                                        currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                {
                                    cell.ToolTipText = ex.Message;
                                }
                            }));
                        }
                    } while (agentsQueue.Count.Equals(0));
                }
                catch (Exception)
                {
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Allow teleports and enable button.
                    vassalForm.BeginInvoke((MethodInvoker) (() =>
                    {
                        ResidentListTeleportHomeGroup.Enabled = true;
                        ResidentListBanGroup.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            {IsBackground = true}.Start();
        }

        private void RequestSetVariables(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker) (() =>
            {
                RegionTeleportGroup.Enabled = false;
                SetTerrainVariablesButton.Enabled = false;
            }));

            new Thread(() =>
            {
                try
                {
                    Monitor.Enter(ClientInstanceTeleportLock);

                    var waterHeight = 10;
                    var terrainRaiseLimit = 100;
                    var terrainLowerLimit = -100;
                    var useEstateSun = true;
                    var fixedSun = false;
                    var sunPosition = 18;

                    var run = false;

                    vassalForm.Invoke((MethodInvoker) (() =>
                    {
                        useEstateSun = TerrainToolsUseEstateSunBox.Checked;
                        fixedSun = TerrainToolsFixedSunBox.Checked;
                        switch (!int.TryParse(TerrainToolsWaterHeightBox.Text, out waterHeight))
                        {
                            case true:
                                TerrainToolsWaterHeightBox.BackColor = Color.MistyRose;
                                return;
                            default:
                                TerrainToolsWaterHeightBox.BackColor = Color.Empty;
                                break;
                        }
                        switch (!int.TryParse(TerrainToolsTerrainRaiseLimitBox.Text, out terrainRaiseLimit))
                        {
                            case true:
                                TerrainToolsTerrainRaiseLimitBox.BackColor = Color.MistyRose;
                                return;
                            default:
                                TerrainToolsTerrainRaiseLimitBox.BackColor = Color.Empty;
                                break;
                        }
                        switch (!int.TryParse(TerrainToolsTerrainLowerLimitBox.Text, out terrainLowerLimit))
                        {
                            case true:
                                TerrainToolsTerrainLowerLimitBox.BackColor = Color.MistyRose;
                                return;
                            default:
                                TerrainToolsTerrainLowerLimitBox.BackColor = Color.Empty;
                                break;
                        }
                        switch (!int.TryParse(TerrainToolsSunPositionBox.Text, out sunPosition))
                        {
                            case true:
                                TerrainToolsSunPositionBox.BackColor = Color.MistyRose;
                                return;
                            default:
                                TerrainToolsSunPositionBox.BackColor = Color.Empty;
                                break;
                        }

                        run = true;
                    }));

                    if (!run) return;

                    // Set the terrain variables.
                    var result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                        KeyValue.Escape(new Dictionary<string, string>
                        {
                            {"command", "setregionterrainvariables"},
                            {"group", vassalConfiguration.Group},
                            {"password", vassalConfiguration.Password},
                            {"waterheight", waterHeight.ToString()},
                            {"terrainraiselimit", terrainRaiseLimit.ToString()},
                            {"terrainlowerlimit", terrainLowerLimit.ToString()},
                            {"useestatesun", useEstateSun.ToString()},
                            {"fixedsun", fixedSun.ToString()},
                            {"sunposition", sunPosition.ToString()}
                        }, wasOutput)).Result);

                    if (string.IsNullOrEmpty(result))
                        throw new Exception("Error communicating with Corrade");

                    bool success;
                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                        throw new Exception("No success status could be retrieved");

                    if (!success)
                        throw new Exception("Unable to set region variables");
                }
                catch (Exception ex)
                {
                    vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                }

                // Block teleports and disable button.
                vassalForm.Invoke((MethodInvoker) (() =>
                {
                    RegionTeleportGroup.Enabled = true;
                    SetTerrainVariablesButton.Enabled = true;
                }));
            })
            {IsBackground = true}.Start();
        }

        private void ReconnectRequested(object sender, EventArgs e)
        {
            // Spawn a thread to check Corrade's connection status.
            new Thread(() =>
            {
                var tcpClient = new TcpClient();
                try
                {
                    var uri = new Uri(vassalConfiguration.HTTPServerURL);
                    tcpClient.Connect(uri.Host, uri.Port);
                    // port open
                    vassalForm.BeginInvoke((MethodInvoker) (() => { vassalForm.Tabs.Enabled = true; }));
                    // set the loading spinner
                    if (vassalForm.RegionAvatarsMap.Image == null)
                    {
                        var thisAssembly = Assembly.GetExecutingAssembly();
                        var file =
                            thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
                        switch (file != null)
                        {
                            case true:
                                vassalForm.BeginInvoke((MethodInvoker) (() =>
                                {
                                    vassalForm.RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
                                    vassalForm.RegionAvatarsMap.Image = Image.FromStream(file);
                                    vassalForm.RegionAvatarsMap.Refresh();
                                }));
                                break;
                        }
                    }
                }
                catch (Exception)
                {
                    // port closed
                    vassalForm.BeginInvoke((MethodInvoker) (() => { vassalForm.Tabs.Enabled = false; }));
                }
            })
            {IsBackground = true}.Start();
        }

        /// <summary>
        ///     Linden constants.
        /// </summary>
        public struct LINDEN_CONSTANTS
        {
            public struct ALERTS
            {
                public const string NO_ROOM_TO_SIT_HERE = @"No room to sit here, try another spot.";

                public const string UNABLE_TO_SET_HOME =
                    @"You can only set your 'Home Location' on your land or at a mainland Infohub.";

                public const string HOME_SET = @"Home position set.";
            }

            public struct ASSETS
            {
                public struct NOTECARD
                {
                    public const string NEWLINE = "\n";
                    public const uint MAXIMUM_BODY_LENTH = 65536;
                }
            }

            public struct AVATARS
            {
                public const uint SET_DISPLAY_NAME_SUCCESS = 200;
                public const string LASTNAME_PLACEHOLDER = @"Resident";
                public const uint MAXIMUM_DISPLAY_NAME_CHARACTERS = 31;
                public const uint MINIMUM_DISPLAY_NAME_CHARACTERS = 1;
                public const uint MAXIMUM_NUMBER_OF_ATTACHMENTS = 38;

                public struct PROFILE
                {
                    public const uint SECOND_LIFE_TEXT_SIZE = 510;
                    public const uint FIRST_LIFE_TEXT_SIZE = 253;
                }

                public struct PICKS
                {
                    public const uint MAXIMUM_PICKS = 10;
                    public const uint MAXIMUM_PICK_DESCRIPTION_SIZE = 1022;
                }

                public struct CLASSIFIEDS
                {
                    public const uint MAXIMUM_CLASSIFIEDS = 100;
                }
            }

            public struct PRIMITIVES
            {
                public const uint MAXIMUM_NAME_SIZE = 63;
                public const uint MAXIMUM_DESCRIPTION_SIZE = 127;
                public const double MAXIMUM_REZ_HEIGHT = 4096.0;
                public const double MINIMUM_SIZE_X = 0.01;
                public const double MINIMUM_SIZE_Y = 0.01;
                public const double MINIMUM_SIZE_Z = 0.01;
                public const double MAXIMUM_SIZE_X = 64.0;
                public const double MAXIMUM_SIZE_Y = 64.0;
                public const double MAXIMUM_SIZE_Z = 64.0;
            }

            public struct OBJECTS
            {
                public const uint MAXIMUM_PRIMITIVE_COUNT = 256;
            }

            public struct DIRECTORY
            {
                public struct EVENT
                {
                    public const uint SEARCH_RESULTS_COUNT = 200;
                }

                public struct GROUP
                {
                    public const uint SEARCH_RESULTS_COUNT = 100;
                }

                public struct LAND
                {
                    public const uint SEARCH_RESULTS_COUNT = 100;
                }

                public struct PEOPLE
                {
                    public const uint SEARCH_RESULTS_COUNT = 100;
                }
            }

            public struct ESTATE
            {
                public const uint REGION_RESTART_DELAY = 120;
                public const uint MAXIMUM_BAN_LIST_LENGTH = 500;
                public const uint MAXIMUM_GROUP_LIST_LENGTH = 63;
                public const uint MAXIMUM_USER_LIST_LENGTH = 500;
                public const uint MAXIMUM_MANAGER_LIST_LENGTH = 10;

                public struct MESSAGES
                {
                    public const string REGION_RESTART_MESSAGE = @"restart";
                }
            }

            public struct PARCELS
            {
                public const double MAXIMUM_AUTO_RETURN_TIME = 999999;
                public const uint MINIMUM_AUTO_RETURN_TIME = 0;
                public const uint MAXIMUM_NAME_LENGTH = 63;
                public const uint MAXIMUM_DESCRIPTION_LENGTH = 255;
            }

            public struct GRID
            {
                public const string SECOND_LIFE = @"Second Life";
                public const string TIME_ZONE = @"Pacific Standard Time";
            }

            public struct CHAT
            {
                public const uint MAXIMUM_MESSAGE_LENGTH = 1024;
            }

            public struct GROUPS
            {
                public const uint MAXIMUM_NUMBER_OF_ROLES = 10;
                public const string EVERYONE_ROLE_NAME = @"Everyone";
                public const uint MAXIMUM_GROUP_NAME_LENGTH = 35;
                public const uint MAXIMUM_GROUP_TITLE_LENGTH = 20;
            }

            public struct NOTICES
            {
                public const uint MAXIMUM_NOTICE_MESSAGE_LENGTH = 512;
            }

            public struct LSL
            {
                public const string CSV_DELIMITER = @", ";
                public const float SENSOR_RANGE = 96;
                public const string DATE_TIME_STAMP = @"yyy-MM-ddTHH:mm:ss.ffffffZ";
            }

            public struct REGION
            {
                public const float TELEPORT_MINIMUM_DISTANCE = 1;
                public const float DEFAULT_AGENT_LIMIT = 40;
                public const float DEFAULT_OBJECT_BONUS = 1;
                public const bool DEFAULT_FIXED_SUN = false;
                public const float DEFAULT_TERRAIN_LOWER_LIMIT = -4;
                public const float DEFAULT_TERRAIN_RAISE_LIMIT = 4;
                public const bool DEFAULT_USE_ESTATE_SUN = true;
                public const float DEFAULT_WATER_HEIGHT = 20;
                public const float SUNRISE = 6;
            }

            public struct VIEWER
            {
                public const float MAXIMUM_DRAW_DISTANCE = 4096;
            }

            public struct TELEPORTS
            {
                public struct THROTTLE
                {
                    public const uint MAX_TELEPORTS = 10;
                    public const uint GRACE_SECONDS = 15;
                }
            }
        }

        /// <summary>
        ///     Constants used by Corrade.
        /// </summary>
        public struct VASSAL_CONSTANTS
        {
            /// <summary>
            ///     Copyright.
            /// </summary>
            public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks";

            public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks";
            public const string VASSAL = @"Vassal";
            public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org";

            /// <summary>
            ///     Vassal version.
            /// </summary>
            public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();

            /// <summary>
            ///     Corrade user agent.
            /// </summary>
            public static readonly string USER_AGENT =
                $"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})";

            /// <summary>
            ///     Vassal compile date.
            /// </summary>
            public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan(
                TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000
                TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString();

            /// <summary>
            ///     Vassal configuration file.
            /// </summary>
            public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini";

            /// <summary>
            ///     Vassal regions file.
            /// </summary>
            public static readonly string VASSAL_REGIONS = @"Regions.csv";

            /// <summary>
            ///     Conten-types that Corrade can send and receive.
            /// </summary>
            public struct CONTENT_TYPE
            {
                public const string TEXT_PLAIN = @"text/plain";
                public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded";
            }
        }

        private void RequestBatchSetCovenant(object sender, EventArgs e)
        {
            // Block teleports and disable button.
            vassalForm.Invoke((MethodInvoker)(() =>
            {
                vassalForm.BatchSetCovenantButton.Enabled = false;
                vassalForm.SetCovenantNotecardUUIDBox.Enabled = false;
                RegionTeleportGroup.Enabled = false;
            }));

            // Enqueue all the regions to set covenant.
            var batchSetCovenantQueue = new Queue<KeyValuePair<string, Vector3>>();
            vassalForm.Invoke((MethodInvoker)(() =>
            {
                foreach (
                    var topCollidersRow in
                        BatchSetCovenantGridView.Rows.AsParallel()
                            .Cast<DataGridViewRow>()
                            .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
                {
                    Vector3 objectPosition;
                    var regionName = topCollidersRow.Cells["BatchSetCovenantRegionName"].Value.ToString();
                    if (string.IsNullOrEmpty(regionName) ||
                        !Vector3.TryParse(topCollidersRow.Cells["BatchSetCovenantPosition"].Value.ToString(),
                            out objectPosition))
                        continue;
                    batchSetCovenantQueue.Enqueue(new KeyValuePair<string, Vector3>(regionName, objectPosition));
                }
            }));

            // If no rows were selected, enable teleports, the return button and return.
            if (batchSetCovenantQueue.Count.Equals(0))
            {
                vassalForm.Invoke((MethodInvoker)(() =>
                {
                    vassalForm.BatchSetCovenantButton.Enabled = true;
                    vassalForm.SetCovenantNotecardUUIDBox.Enabled = true;
                    RegionTeleportGroup.Enabled = true;
                }));
                return;
            }

            new Thread(() =>
            {
                Monitor.Enter(ClientInstanceTeleportLock);

                try
                {
                    do
                    {
                        // Dequeue the first object.
                        var batchSetCovenantRegionData = batchSetCovenantQueue.Dequeue();
                        DataGridViewRow currentDataGridViewRow = null;
                        vassalForm.Invoke((MethodInvoker)(() =>
                        {
                            currentDataGridViewRow = vassalForm.BatchSetCovenantGridView.Rows.AsParallel()
                                .Cast<DataGridViewRow>()
                                .FirstOrDefault(
                                    o =>
                                        o.Cells["BatchSetCovenantRegionName"].Value.ToString()
                                            .Equals(batchSetCovenantRegionData.Key, StringComparison.OrdinalIgnoreCase) &&
                                        o.Cells["BatchSetCovenantPosition"].Value.ToString()
                                            .Equals(batchSetCovenantRegionData.Value.ToString(),
                                                StringComparison.OrdinalIgnoreCase));
                        }));

                        if (currentDataGridViewRow == null) continue;

                        try
                        {
                            var success = false;
                            string result;

                            // Retry to teleport to each region a few times.
                            var teleportRetries = 3;
                            do
                            {
                                vassalForm.Invoke((MethodInvoker)(() =>
                                {
                                    vassalForm.StatusText.Text = @"Attempting to teleport to " + batchSetCovenantRegionData.Key +
                                                                 @" " + @"(" +
                                                                 teleportRetries.ToString(Utils.EnUsCulture) +
                                                                 @")";
                                }));

                                // Teleport to the region.
                                result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                    KeyValue.Escape(new Dictionary<string, string>
                                    {
                                        {"command", "teleport"},
                                        {"group", vassalConfiguration.Group},
                                        {"password", vassalConfiguration.Password},
                                        {"position", batchSetCovenantRegionData.Value.ToString()},
                                        {"region", batchSetCovenantRegionData.Key},
                                        {"fly", "True"}
                                    }, wasOutput)).Result);

                                if (string.IsNullOrEmpty(result))
                                {
                                    vassalForm.Invoke(
                                        (MethodInvoker)
                                            (() =>
                                            {
                                                vassalForm.StatusText.Text = @"Error communicating with Corrade.";
                                            }));
                                    continue;
                                }
                                if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                {
                                    vassalForm.Invoke(
                                        (MethodInvoker)
                                            (() =>
                                            {
                                                vassalForm.StatusText.Text = @"No success status could be retrieved. ";
                                            }));
                                    continue;
                                }
                                switch (success)
                                {
                                    case true:
                                        vassalForm.Invoke(
                                            (MethodInvoker)
                                                (() => { vassalForm.StatusText.Text = @"Teleport succeeded."; }));
                                        break;
                                    default:
                                        // In case the destination is to close (Corrade status code 37559), 
                                        // then we are on the same region so no need to retry.
                                        uint status; //37559
                                        switch (
                                            uint.TryParse(wasInput(KeyValue.Get("status", result)), out status) &&
                                            status.Equals(37559))
                                        {
                                            case true: // We are on the region already!
                                                success = true;
                                                break;
                                            default:
                                                vassalForm.Invoke(
                                                    (MethodInvoker)
                                                        (() => { vassalForm.StatusText.Text = @"Teleport failed."; }));
                                                break;
                                        }
                                        break;
                                }

                                // Pause for teleport (10 teleports / 15s allowed).
                                Thread.Sleep(700);
                            } while (!success && !(--teleportRetries).Equals(0));

                            if (!success)
                                throw new Exception("Failed to teleport to region.");

                            result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                KeyValue.Escape(new Dictionary<string, string>
                                {
                                    {"command", "getregiondata"},
                                    {"group", vassalConfiguration.Group},
                                    {"password", vassalConfiguration.Password},
                                    {"data", "IsEstateManager"}
                                }, wasOutput)).Result);

                            if (string.IsNullOrEmpty(result))
                                throw new Exception("Error communicating with Corrade.");

                            if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                throw new Exception("No success status could be retrieved.");

                            if (!success)
                                throw new Exception("Could not retrieve estate rights.");

                            var data = CSV.ToEnumerable(wasInput(KeyValue.Get("data", result))).ToList();
                            if (!data.Count.Equals(2))
                                throw new Exception("Could not retrieve estate rights.");

                            bool isEstateManager;
                            switch (
                                bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
                                isEstateManager)
                            {
                                case true: // we are an estate manager
                                    result = Encoding.UTF8.GetString(HTTPClient.POST(vassalConfiguration.HTTPServerURL,
                                        KeyValue.Escape(new Dictionary<string, string>
                                        {
                                            {"command", "setestatecovenant"},
                                            {"group", vassalConfiguration.Group},
                                            {"password", vassalConfiguration.Password},
                                            {"item", vassalForm.SetCovenantNotecardUUIDBox.Text}
                                        }, wasOutput)).Result);

                                    if (string.IsNullOrEmpty(result))
                                        throw new Exception("Error communicating with Corrade.");

                                    if (!bool.TryParse(wasInput(KeyValue.Get("success", result)), out success))
                                        throw new Exception("No success status could be retrieved.");

                                    if (!success)
                                        throw new Exception("Could not set region covenant.");

                                    vassalForm.Invoke((MethodInvoker)(() =>
                                    {
                                        vassalForm.StatusText.Text = @"Region covenant set.";
                                        currentDataGridViewRow.Selected = false;
                                        currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
                                        foreach (
                                            var cell in
                                                currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                        {
                                            cell.ToolTipText = @"Region covenant set.";
                                        }
                                    }));
                                    break;
                                default:
                                    throw new Exception("No estate manager rights for setting covenant.");
                            }
                        }
                        catch (Exception ex)
                        {
                            vassalForm.Invoke((MethodInvoker)(() =>
                            {
                                vassalForm.StatusText.Text = ex.Message;
                                currentDataGridViewRow.Selected = false;
                                currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
                                foreach (
                                    var cell in
                                        currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
                                {
                                    cell.ToolTipText = ex.Message;
                                }
                            }));
                        }
                        finally
                        {
                            // Pause for teleport (10 teleports / 15s allowed).
                            Thread.Sleep(700);
                        }
                    } while (!batchSetCovenantQueue.Count.Equals(0));
                }
                catch (Exception)
                {
                }
                finally
                {
                    Monitor.Exit(ClientInstanceTeleportLock);
                    // Allow teleports and enable button.
                    vassalForm.BeginInvoke((MethodInvoker)(() =>
                    {
                        vassalForm.BatchSetCovenantButton.Enabled = true;
                        vassalForm.SetCovenantNotecardUUIDBox.Enabled = true;
                        RegionTeleportGroup.Enabled = true;
                    }));
                }
            })
            { IsBackground = true }.Start();
        }
    }
}

Generated by GNU Enscript 1.6.5.90.