/// <summary>
        /// Sets the specified traceroute information.
        /// </summary>
        /// <param name="traceroute">The site.</param>
        public void Set(MercuryTraceroute traceroute)
        {
            // Clear the information.
            this.Clear();

            if (null != traceroute)
            {
                this.labelTitle.Text = @"{0} → {1}".FormatWith(traceroute.SourceIp, traceroute.DestinationIp);
                this.textBoxSource.Text = string.IsNullOrWhiteSpace(traceroute.SourceHostname) ? traceroute.SourceIp.ToString() : "{0} ({1})".FormatWith(traceroute.SourceHostname, traceroute.SourceIp);
                this.textBoxDestination.Text = string.IsNullOrWhiteSpace(traceroute.DestinationHostname) ? traceroute.DestinationIp.ToString() : "{0} ({1})".FormatWith(traceroute.DestinationHostname, traceroute.DestinationIp);
                this.textBoxMaxHops.Text = traceroute.MaximumHops.HasValue ? traceroute.MaximumHops.Value.ToString() : "(not set)";
                this.textBoxPacketSize.Text = traceroute.PacketSize.HasValue ? traceroute.PacketSize.Value.ToString() : "(not set)";
                foreach (MercuryTracerouteHop hop in traceroute.Hops)
                {
                    ListViewItem item = new ListViewItem(new string[] {
                        hop.Number.ToString(),
                        hop.Address != null ? hop.Address.ToString() : "(not set)",
                        hop.Hostname != null ? hop.Hostname : "(not set)",
                        hop.AutonomousSystems != null ? hop.AutonomousSystems.ToExtendedString() : "(not set)",
                        hop.Rtt != null ? hop.Rtt.ToExtendedString() : "(not set)"
                        });
                    item.ImageIndex = hop.Address != null ? 0 : 1;
                    item.Tag =
                    this.listViewHops.Items.Add(item);
                }
            }
        }
        /// <summary>
        /// An event handler called when the user clicks on the start button.
        /// </summary>
        /// <param name="sender">The sender object.</param>
        /// <param name="e">The event arguments.</param>
        private void OnStart(object sender, EventArgs e)
        {
            // Parse the IP address.
            IPAddress localAddress;
            if (!IPAddress.TryParse(this.config.LocalAddress, out localAddress))
            {
                // Show an error message.
                MessageBox.Show(this, "The local IP address is not valid. Correct the tool settings and try again.", "Invalid Configuration", MessageBoxButtons.OK, MessageBoxIcon.Error);
                // Return.
                return;
            }

            // Check there is no pending request.
            lock (this.sync)
            {
                if (null != this.result)
                {
                    // Show an error message.
                    MessageBox.Show(this, "There is another Mercury request in progress. Wait for the current request to complete, and try again.", "Mercury Request", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    // Return.
                    return;
                }
            }

            // The Mercury traceroute.
            MercuryTraceroute traceroute;

            try
            {
                // Try and parse the traceroute.
                traceroute = new MercuryTraceroute(Guid.Empty, null, localAddress, this.codeTextBox.Text);

                // Set the traceroute.
                this.controlTraceroute.Set(traceroute);
            }
            catch (Exception exception)
            {
                // Show an error message.
                MessageBox.Show(this, "An error occurred while parsing the traceroute data. {0}".FormatWith(exception.Message), "Invalid Traceroute Format", MessageBoxButtons.OK, MessageBoxIcon.Error);
                // Return.
                return;
            }

            // Save the server URL.
            this.config.UploadTracerouteUrl = this.textBoxUrl.Text;

            // Call the request started event handler.
            this.OnRequestStarted();

            // Set the status.
            this.status.Send(ApplicationStatus.StatusType.Busy, "Uploading the traceroute to the Mercury server...", Resources.Busy_16);
            // Show a message.
            this.ShowMessage(
                Resources.GlobeClock_48,
                "Mercury Server Request",
                "Uploading the traceroute to the Mercury server...");
            // Log the events.
            this.controlLog.Add(this.config.Api.Log(
                LogEventLevel.Verbose,
                LogEventType.Information,
                @"Uploading the traceroute to the Mercury server '{0}'.",
                new object[] { this.config.UploadTracerouteUrl }
                ));

            // Compute the server URI.
            Uri uri = new Uri(this.textBoxUrl.Text);

            try
            {
                lock (this.sync)
                {
                    // Begin the request.
                    this.result = this.request.BeginUploadTraceroute(uri, traceroute, this.OnCallback);
                }
            }
            catch (Exception exception)
            {
                // Update the status label.
                this.status.Send(ApplicationStatus.StatusType.Normal, "Uploading the traceroute to the Mercury server failed. {0}".FormatWith(exception.Message), Resources.Error_16);
                // Show a message.
                this.ShowMessage(
                    Resources.GlobeError_48,
                    "Mercury Server Request",
                    "Uploading the traceroute to the Mercury server failed.{0}{1}".FormatWith(Environment.NewLine, exception.Message),
                    false,
                    (int)this.config.Api.Config.MessageCloseDelay.TotalMilliseconds,
                    (object[] parameters) =>
                    {
                        // Call the request finished event handler.
                        this.OnRequestFinished();
                    });
                // Log the events.
                this.controlLog.Add(this.config.Api.Log(
                    LogEventLevel.Important,
                    LogEventType.Error,
                    @"Uploading the traceroute to the Mercury server '{0}' failed. {1}",
                    new object[] { this.config.UploadTracerouteUrl, exception.Message },
                    exception
                    ));
            }
        }
        /// <summary>
        /// Uploads a traceroute to the Mercury web service.
        /// </summary>
        /// <param name="token">The cancellation token.</param>
        /// <param name="arguments">The method arguments.</param>
        /// <returns>The method result.</returns>
        private object UploadTracerouteFromPlanetLab(CancellationToken token, params object[] arguments)
        {
            // Check the number of arguments.
            if (arguments.Length != 3) throw new ArgumentException("This method takes only 3 arguments.");

            // Cheeck the arguments type.
            if (!(arguments[0] is Guid)) throw new ArgumentNullException("The identifier argument is of the wrong type (it must be a GUID).");
            if (!(arguments[1] is string)) throw new ArgumentNullException("The source hostname argument is of the wrong type (it must be a string).");
            if (!(arguments[2] is string)) throw new ArgumentNullException("The traceroute data argument is of the wrong type (it must be a string).");

            // Get the parameters.
            Guid id = (Guid)arguments[0];
            string sourceHostname = arguments[1] as string;
            string data = arguments[2] as string;

            // Check the arguments.
            if (null == sourceHostname) throw new ArgumentNullException("The source hostname argument is null.");
            if (null == data) throw new ArgumentNullException("The traceroute data argument is null.");

            // Resolve the IP address of the PlanetLab node.
            IPAddress[] sourceIps = Dns.GetHostAddresses(sourceHostname);

            // Create the traceroute.
            MercuryTraceroute traceroute = new MercuryTraceroute(id, sourceHostname, sourceIps.Length > 0 ? sourceIps[0] : null, data);

            // The success flag.
            bool success = false;
            // The exception.
            Exception exception = null;

            // Create a wait handle.
            using (ManualResetEvent wait = new ManualResetEvent(false))
            {
                // Upload the data to Mercury.
                IAsyncResult asyncResult = this.request.BeginUploadTraceroute(new Uri(this.config.UploadTracerouteUrl), traceroute, (AsyncWebResult result) =>
                    {
                        try
                        {
                            // Complete the request.
                            this.request.End(result);
                            // Set the success to true.
                            success = true;
                        }
                        catch (Exception ex)
                        {
                            // Set the exception.
                            exception = ex;
                        }
                        finally
                        {
                            // Set the wait handle to the signaled state.
                            wait.Set();
                        }
                    });

                // Wait for the request to complete.
                wait.WaitOne();
            }

            // If an exception occurred during the request.
            if (null != exception)
            {
                throw exception;
            }

            // Return the success flag.
            return success;
        }
        /// <summary>
        /// Begins a new request to the specified Mercury server to upload a traceroute.
        /// </summary>
        /// <param name="uri">The Mercury server URI.</param>
        /// <param name="traceroute">The traceroute to upload.</param>
        /// <param name="callback">The callback method.</param>
        /// <param name="userState">The user state.</param>
        /// <returns>The result of the asynchronous web operation.</returns>
        public IAsyncResult BeginUploadTraceroute(Uri uri, MercuryTraceroute traceroute, AsyncWebRequestCallback callback, object userState = null)
        {
            // Create the request state.
            AsyncWebResult asyncState = new AsyncWebResult(uri, callback, userState);

            // Set the request headers.
            asyncState.Request.Method = "POST";
            asyncState.Request.Accept = "text/html,application/xhtml+xml,application/xml";
            asyncState.Request.ContentType = "application/json;charset=UTF-8";

            // Create the traceroute JSON object.
            JObject obj = new JObject(
                new JProperty("sessionId", traceroute.Id.ToString()),
                new JProperty("srcIp", traceroute.SourceIp != null ? traceroute.SourceIp.ToString() : "none"),
                new JProperty("dstIp", traceroute.DestinationIp.ToString()),
                new JProperty("srcName", traceroute.SourceHostname),
                new JProperty("dstName", traceroute.DestinationHostname),
                new JProperty("hops",
                    new JArray(from hop in traceroute.Hops select new JObject(
                        new JProperty("id", hop.Number.ToString()),
                        new JProperty("ip", hop.Address != null ? hop.Address.ToString() : "none"),
                        new JProperty("asn", hop.AutonomousSystems != null ? new JArray(from asn in hop.AutonomousSystems select asn.ToString()) : new JArray()),
                        new JProperty("rtt", hop.Rtt != null ? new JArray(from rtt in hop.Rtt select rtt.ToString()) : new JArray())
                        )
                    )
                ));

            // Append the send data.
            asyncState.SendData.Append(obj.ToString(), Encoding.UTF8);

            // Begin the request.
            return base.Begin(asyncState);
        }