/// <summary>
        /// Raises the BeforeSwitchToLatestVersion event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnBeforeSwitchToLatestVersion(object sender, AutoUpdateManagerWithDownloadDescriptorCancelEventArgs e)
        {
            try
            {				
                if (this.BeforeSwitchToLatestVersion != null)
                    this.BeforeSwitchToLatestVersion(sender, e);

                // cancel if it's not supposed to switch to the latest version automatically
                if (!e.OverrideOptions && !e.Cancel)
                    if (!_options.AutomaticallySwitchToNewVersion)
                        e.Cancel = true;
            }
            catch(ThreadAbortException)
            {

            }
            catch(Exception ex)
            {
				Debug.WriteLine(ex);
            }
        }
        /// <summary>
        /// Occurs when the engine's background thread runs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ea"></param>
        protected virtual void OnThreadRun(object sender, BackgroundThreadStartEventArgs threadStartEventArgs)
        {
            bool downloaded = false;
            bool installed = false;
            bool finalized = false;
            AutoUpdateDownloadDescriptor recommendedUpdateDescriptor = null;

            try
            {
                /*
                 * Raise the AutoUpdateProcessStarted event
                 * */
                AutoUpdateManagerEventArgs startedArgs = new AutoUpdateManagerEventArgs(this, null);
                this.OnAutoUpdateProcessStarted(this, startedArgs);

                #region Step 1. QueryForLatestVersion

                /*
                 * Raise the BeforeQueryForLatestVersion event
                 * */
                AutoUpdateManagerCancelEventArgs beforeQueryArgs = new AutoUpdateManagerCancelEventArgs(this, startedArgs.ProgressViewer, false);
                this.OnBeforeQueryForLatestVersion(this, beforeQueryArgs);

                // create an array list to hold all of the available updates
                ArrayList listOfAvailableDownloads = new ArrayList();				
				
                // use the downloaders to check for downloads
                foreach(AutoUpdateDownloader downloader in _downloaders)
                {
                    try
                    {
                        // query the latest update available for the specified product
                        AutoUpdateDownloadDescriptor updateAvailable;						
						
                        // if the downloader finds an update is available
                        if (downloader.QueryLatestVersion(beforeQueryArgs.ProgressViewer, _options, _productToUpdate, out updateAvailable))														
                            // add it to the list of downloads available
                            listOfAvailableDownloads.Add(updateAvailable);						
                    }
                    catch(ThreadAbortException ex)
                    {
                        throw new Exception(ex.Message, ex);
                    }
                    catch(Exception ex)
                    {
                        Debug.WriteLine(ex);
                    }
                }

                // create a simple array of the updates that are available for download
                AutoUpdateDownloadDescriptor[] availableDownloads = listOfAvailableDownloads.ToArray(typeof(AutoUpdateDownloadDescriptor)) as AutoUpdateDownloadDescriptor[];

                // sort and select the download that contains the newest version
                recommendedUpdateDescriptor = this.SelectTheDownloadWithTheNewestUpdate(availableDownloads);

                /*
                 * Raise the AfterQueryForLatestVersion event
                 * */
                AutoUpdateManagerWithDownloadDescriptorEventArgs afterQueryArgs = new AutoUpdateManagerWithDownloadDescriptorEventArgs(this, beforeQueryArgs.ProgressViewer, recommendedUpdateDescriptor);
                this.OnAfterQueryForLatestVersion(this, afterQueryArgs);

                // if the manager could not find a suitable recomendation for downloading, we're done 
                if (recommendedUpdateDescriptor == null)
                {
                    /*
                     * Raise the NoLaterVersionAvailable event
                     * */
                    this.OnNoLaterVersionAvailable(this, new AutoUpdateManagerEventArgs(this, afterQueryArgs.ProgressViewer));
                    return;
                }
				
                // or if the product to update is newer or equal to the version of the recommended update picked for downloading
                if (_productToUpdate.Version >= recommendedUpdateDescriptor.Manifest.Product.Version)
                {
                    /*
                     * Raise the NoLaterVersionAvailable event
                     * */
                    this.OnNoLaterVersionAvailable(this, new AutoUpdateManagerEventArgs(this, afterQueryArgs.ProgressViewer));
                    return;
                }
                
                #endregion

                #region Step 2. Download

                /*
                 * Create the path including the filename where the .Update file will be downloaded to locally
                 * (ex: "C:\Program Files\Razor\1.0.0.0.update")				  
                 * */
                recommendedUpdateDescriptor.DownloadedPath = Path.Combine(_options.DownloadPath, Path.GetFileName(recommendedUpdateDescriptor.Manifest.UrlOfUpdate));

                /*
                 * Raise the BeforeDownload event
                 * */
                AutoUpdateManagerWithDownloadDescriptorCancelEventArgs beforeDownloadArgs = new AutoUpdateManagerWithDownloadDescriptorCancelEventArgs(this, afterQueryArgs.ProgressViewer, recommendedUpdateDescriptor, false);
                this.OnBeforeDownload(this, beforeDownloadArgs);
				
                // bail if the download was cancelled
                if (beforeDownloadArgs.Cancel)
                    return;				
				
                // use the downloader that found the update to download it
                // the update may be available via some proprietary communications channel (http, ftp, or Unc paths)
                downloaded = recommendedUpdateDescriptor.Downloader.Download(beforeDownloadArgs.ProgressViewer, recommendedUpdateDescriptor);

                /*
                 * Raise the AfterDownload event
                 * */
                AutoUpdateManagerWithDownloadDescriptorEventArgs afterDownloadArgs = new AutoUpdateManagerWithDownloadDescriptorEventArgs(this, beforeDownloadArgs.ProgressViewer, recommendedUpdateDescriptor);
                afterDownloadArgs.OperationStatus = downloaded;
                this.OnAfterDownload(this, afterDownloadArgs);
				
                // if the download failed bail out
                if (!downloaded)
                    return;

                #endregion

                #region Step 3. Install

                /*
                 * Raise the BeforeInstall event
                 * */
                AutoUpdateManagerWithDownloadDescriptorCancelEventArgs beforeInstallArgs = new AutoUpdateManagerWithDownloadDescriptorCancelEventArgs(this, afterDownloadArgs.ProgressViewer, recommendedUpdateDescriptor, false);
                this.OnBeforeInstall(this, beforeInstallArgs);

                // if the installation was not cancelled
                if (!beforeInstallArgs.Cancel)
                {				
                    // install the update
                    installed = this.InstallUpdate(beforeInstallArgs.ProgressViewer, recommendedUpdateDescriptor);

                    // if the update was installed, now is the time to finalize the installation
                    if (installed)
                    {
                        // all the downloader to finalize the install, there may be things to do after the installation is complete
                        // depending upon the source of the download, and again since it's plugable only the downloader will know how to deal with it
                        // and by default it will just delete the downloaded .update file
                        finalized = recommendedUpdateDescriptor.Downloader.FinalizeInstallation(beforeInstallArgs.ProgressViewer, recommendedUpdateDescriptor);
                    }    															
                }

                /*
                 * Raise the AfterInstall event
                 * */				
                AutoUpdateManagerWithDownloadDescriptorEventArgs afterInstallArgs = new AutoUpdateManagerWithDownloadDescriptorEventArgs(this, beforeInstallArgs.ProgressViewer, recommendedUpdateDescriptor);				
                afterInstallArgs.OperationStatus = installed && finalized;																	
                this.OnAfterInstall(this, afterInstallArgs);
				
                #endregion

                #region Step 4. Update Alternate Path

                /*
                 * Raise the X event
                 * */
                AutoUpdateManagerWithDownloadDescriptorCancelEventArgs beforeUpdateAltPathArgs = new AutoUpdateManagerWithDownloadDescriptorCancelEventArgs(this, afterInstallArgs.ProgressViewer, recommendedUpdateDescriptor, false);
                this.OnBeforeUpdateAlternatePath(this, beforeUpdateAltPathArgs);

                if (!beforeUpdateAltPathArgs.Cancel)
                {
                    // copy the manifest & the update there 
                    this.AdjustUrlOfUpdateInManifest(_options, recommendedUpdateDescriptor);
                    this.CreateCopyOfManifestInAlternatePath(beforeUpdateAltPathArgs.ProgressViewer, recommendedUpdateDescriptor);
                    this.CreateCopyOfUpdateInAlternatePath(beforeUpdateAltPathArgs.ProgressViewer, recommendedUpdateDescriptor);
                }
				
                // delete the downloaded .update file, don't leave it laying around
                File.Delete(recommendedUpdateDescriptor.DownloadedPath);

                AutoUpdateManagerWithDownloadDescriptorEventArgs afterUpdateAltPathArgs = new AutoUpdateManagerWithDownloadDescriptorEventArgs(this, beforeUpdateAltPathArgs.ProgressViewer, recommendedUpdateDescriptor);
                this.OnAfterUpdateAlternatePath(this, afterUpdateAltPathArgs);

                #endregion

                #region Step 5. Switch to Latest Version

                if (installed)
                {
                    /*
                     * Raise the BeforeSwitchToLatestVersion event
                     * */
                    AutoUpdateManagerWithDownloadDescriptorCancelEventArgs beforeSwitchedArgs = new AutoUpdateManagerWithDownloadDescriptorCancelEventArgs(this, afterUpdateAltPathArgs.ProgressViewer, recommendedUpdateDescriptor, false);
                    this.OnBeforeSwitchToLatestVersion(this, beforeSwitchedArgs);

                    // if switching to the latest version was not cancelled
                    if (!beforeSwitchedArgs.Cancel)
                    {
                        /*
                        * Raise the SwitchToLatestVersion event
                        * */
                        AutoUpdateManagerWithDownloadDescriptorEventArgs switchToArgs = new AutoUpdateManagerWithDownloadDescriptorEventArgs(this, beforeSwitchedArgs.ProgressViewer, recommendedUpdateDescriptor);
                        this.OnSwitchToLatestVersion(this, switchToArgs);

                        // the rest should be history because the AutoUpdateSnapIn should catch that event and switch to the latest version using the bootstrap
                    }
                }

                #endregion
            }
            catch(ThreadAbortException)
            {
                Debug.WriteLine("The AutoUpdateManager has encountered a ThreadAbortException.\n\tThe auto-update thread has been aborted.", MY_TRACE_CATEGORY);

                try
                {
                    // delete the downloaded .update file, don't leave it laying around
                    File.Delete(recommendedUpdateDescriptor.DownloadedPath);
                }
                catch(Exception ex)
                {
					Debug.WriteLine(ex);
                }
            }
            catch(Exception ex)
            {
                //Debug.WriteLine(ex);
                this.OnException(this, new AutoUpdateExceptionEventArgs(ex));				
            }
        }
        /// <summary>
        /// Raises the BeforeUpdateAlternatePath event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnBeforeUpdateAlternatePath(object sender, AutoUpdateManagerWithDownloadDescriptorCancelEventArgs e)
        {
            try
            {				
                if (this.BeforeUpdateAlternatePath != null)
                    this.BeforeUpdateAlternatePath(sender, e);

                // cancel if it's not supposed to update the alternate path automatically
                if (!e.OverrideOptions && !e.Cancel)
                    if (!_options.AutomaticallyUpdateAlternatePath)
                        e.Cancel = true;
            }
            catch(ThreadAbortException)
            {

            }
            catch(Exception ex)
            {
				Debug.WriteLine(ex);
            }
        }