private void ClassifierList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right && SelectedItem != null)
            {
                Classifier classifier = SelectedItem as Classifier;
                if (classifier == null)
                {
                    throw new NullReferenceException("Failed to cast classifier item from list");
                }

                string updateWindowTitle = "Updating " + classifier.GetType().Name + "...";

                if (classifier is LibLinear)
                {
                    LibLinear   liblinear = classifier as LibLinear;
                    DynamicForm f         = new DynamicForm("Set LibLinear parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddCheckBox("Run feature selection:", ContentAlignment.MiddleRight, liblinear.RunFeatureSelection, "run_feature_selection");
                    f.AddDropDown("Positive weighting:", Enum.GetValues(typeof(LibLinear.PositiveClassWeighting)), liblinear.Weighting, "positive_weighting", true);
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        liblinear.RunFeatureSelection = f.GetValue <bool>("run_feature_selection");
                        liblinear.Weighting           = f.GetValue <LibLinear.PositiveClassWeighting>("positive_weighting");
                    }
                }
                else if (classifier is SvmRank)
                {
                    SvmRank     svmRank = classifier as SvmRank;
                    DynamicForm f       = new DynamicForm("Set SvmRank parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("c:", (decimal)svmRank.C, 3, decimal.MinValue, decimal.MaxValue, (decimal)0.01, "c");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        try { svmRank.C = Convert.ToSingle(f.GetValue <decimal>("c")); }
                        catch (Exception ex) { MessageBox.Show("Invalid value for C:  " + ex.Message); }
                    }
                }
                else if (classifier is RandomForest)
                {
                    RandomForest randomForest = classifier as RandomForest;
                    DynamicForm  f            = new DynamicForm("Set RandomForest parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("Number of trees:", randomForest.NumTrees, 0, 1, decimal.MaxValue, 1, "ntree");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        randomForest.NumTrees = Convert.ToInt32(f.GetValue <decimal>("ntree"));
                    }
                }
                else if (classifier is AdaBoost)
                {
                    AdaBoost    adaBoost = classifier as AdaBoost;
                    DynamicForm f        = new DynamicForm("Set AdaBoost parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("Number of iterations:", adaBoost.Iterations, 0, 1, decimal.MaxValue, 1, "iterations");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        adaBoost.Iterations = Convert.ToInt32(f.GetValue <decimal>("iterations"));
                    }
                }
            }
        }
        private void ClassifierList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right && SelectedItem != null)
            {
                Classifier classifier = SelectedItem as Classifier;
                if (classifier == null)
                    throw new NullReferenceException("Failed to cast classifier item from list");

                string updateWindowTitle = "Updating " + classifier.GetType().Name + "...";

                if (classifier is LibLinear)
                {
                    LibLinear liblinear = classifier as LibLinear;
                    DynamicForm f = new DynamicForm("Set LibLinear parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddCheckBox("Run feature selection:", ContentAlignment.MiddleRight, liblinear.RunFeatureSelection, "run_feature_selection");
                    f.AddDropDown("Positive weighting:", Enum.GetValues(typeof(LibLinear.PositiveClassWeighting)), liblinear.Weighting, "positive_weighting", true);
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        liblinear.RunFeatureSelection = f.GetValue<bool>("run_feature_selection");
                        liblinear.Weighting = f.GetValue<LibLinear.PositiveClassWeighting>("positive_weighting");
                    }
                }
                else if (classifier is SvmRank)
                {
                    SvmRank svmRank = classifier as SvmRank;
                    DynamicForm f = new DynamicForm("Set SvmRank parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("c:", (decimal)svmRank.C, 3, decimal.MinValue, decimal.MaxValue, (decimal)0.01, "c");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        try { svmRank.C = Convert.ToSingle(f.GetValue<decimal>("c")); }
                        catch (Exception ex) { MessageBox.Show("Invalid value for C:  " + ex.Message); }
                    }
                }
                else if (classifier is RandomForest)
                {
                    RandomForest randomForest = classifier as RandomForest;
                    DynamicForm f = new DynamicForm("Set RandomForest parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("Number of trees:", randomForest.NumTrees, 0, 1, decimal.MaxValue, 1, "ntree");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        randomForest.NumTrees = Convert.ToInt32(f.GetValue<decimal>("ntree"));
                    }
                }
                else if (classifier is AdaBoost)
                {
                    AdaBoost adaBoost = classifier as AdaBoost;
                    DynamicForm f = new DynamicForm("Set AdaBoost parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("Number of iterations:", adaBoost.Iterations, 0, 1, decimal.MaxValue, 1, "iterations");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        adaBoost.Iterations = Convert.ToInt32(f.GetValue<decimal>("iterations"));
                    }
                }
            }
        }
        private void SmootherList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                int clickedIndex = IndexFromPoint(e.Location);
                if (clickedIndex >= 0)
                {
                    Smoother smoother = Items[clickedIndex] as Smoother;
                    if (smoother == null)
                    {
                        throw new NullReferenceException("Expected Smoother objects in Items");
                    }

                    string updateWindowTitle = "Updating " + smoother.GetType().Name + "...";

                    if (smoother is KdeSmoother)
                    {
                        KdeSmoother kdeSmoother = smoother as KdeSmoother;
                        DynamicForm f           = new DynamicForm("Set KDE smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Sample size:", kdeSmoother.SampleSize, 0, 1, decimal.MaxValue, 1, "sample_size");
                        f.AddCheckBox("Normalize:", ContentAlignment.MiddleRight, kdeSmoother.Normalize, "normalize");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { kdeSmoother.SampleSize = Convert.ToInt32(f.GetValue <decimal>("sample_size")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for sample size:  " + ex.Message); }

                            kdeSmoother.Normalize = f.GetValue <bool>("normalize");
                        }
                    }
                    else if (smoother is WeightedAverageSmoother)
                    {
                        WeightedAverageSmoother avgSmoother = smoother as WeightedAverageSmoother;
                        DynamicForm             f           = new DynamicForm("Set weighted average smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Minimum:", (decimal)avgSmoother.Minimum, 0, 0, decimal.MaxValue, 1, "minimum");
                        f.AddNumericUpdown("Maximum:", (decimal)avgSmoother.Maximum, 0, 0, decimal.MaxValue, 1, "maximum");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { avgSmoother.Minimum = Convert.ToDouble(f.GetValue <decimal>("minimum")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for minimum:  " + ex.Message); }

                            try
                            {
                                double value = Convert.ToDouble(f.GetValue <decimal>("maximum"));
                                if (value < avgSmoother.Minimum)
                                {
                                    avgSmoother.Maximum = avgSmoother.Minimum + 500;
                                    throw new Exception("Maximum must be greater than or equal to minimum (" + avgSmoother.Minimum + "). Setting maximum to " + avgSmoother.Maximum + ".");
                                }

                                avgSmoother.Maximum = value;
                            }
                            catch (Exception ex) { MessageBox.Show("Invalid value for maximum:  " + ex.Message); }
                        }
                    }
                    else if (smoother is MarsSmoother)
                    {
                        MarsSmoother marsSmoother = smoother as MarsSmoother;
                        DynamicForm  f            = new DynamicForm("Set MARS smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Number of considered parent terms (-1 for all):", marsSmoother.ConsideredParentTerms, 0, -1, decimal.MaxValue, 1, "parent");
                        f.AddNumericUpdown("Degree of interaction:", marsSmoother.InteractionDegree, 0, 1, decimal.MaxValue, 1, "interaction");
                        f.AddNumericUpdown("Number of knots (-1 for auto):", marsSmoother.NumberOfKnots, 0, -1, decimal.MaxValue, 1, "knots");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { marsSmoother.ConsideredParentTerms = Convert.ToInt32(f.GetValue <decimal>("parent")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for parent terms:  " + ex.Message); }

                            try { marsSmoother.InteractionDegree = Convert.ToInt32(f.GetValue <decimal>("interaction")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for interaction degree:  " + ex.Message); }

                            try { marsSmoother.NumberOfKnots = Convert.ToInt32(f.GetValue <decimal>("knots")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for number of knots:  " + ex.Message); }
                        }
                    }
                    else
                    {
                        throw new NotImplementedException("Unrecognized smoother type:  " + smoother.GetType().FullName);
                    }
                }
            }
        }
        private void SmootherList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                int clickedIndex = IndexFromPoint(e.Location);
                if (clickedIndex >= 0)
                {
                    Smoother smoother = Items[clickedIndex] as Smoother;
                    if (smoother == null)
                        throw new NullReferenceException("Expected Smoother objects in Items");

                    string updateWindowTitle = "Updating " + smoother.GetType().Name + "...";

                    if (smoother is KdeSmoother)
                    {
                        KdeSmoother kdeSmoother = smoother as KdeSmoother;
                        DynamicForm f = new DynamicForm("Set KDE smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Sample size:", kdeSmoother.SampleSize, 0, 1, decimal.MaxValue, 1, "sample_size");
                        f.AddCheckBox("Normalize:", ContentAlignment.MiddleRight, kdeSmoother.Normalize, "normalize");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { kdeSmoother.SampleSize = Convert.ToInt32(f.GetValue<decimal>("sample_size")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for sample size:  " + ex.Message); }

                            kdeSmoother.Normalize = f.GetValue<bool>("normalize");
                        }
                    }
                    else if (smoother is WeightedAverageSmoother)
                    {
                        WeightedAverageSmoother avgSmoother = smoother as WeightedAverageSmoother;
                        DynamicForm f = new DynamicForm("Set weighted average smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Minimum:", (decimal)avgSmoother.Minimum, 0, 0, decimal.MaxValue, 1, "minimum");
                        f.AddNumericUpdown("Maximum:", (decimal)avgSmoother.Maximum, 0, 0, decimal.MaxValue, 1, "maximum");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { avgSmoother.Minimum = Convert.ToDouble(f.GetValue<decimal>("minimum")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for minimum:  " + ex.Message); }

                            try
                            {
                                double value = Convert.ToDouble(f.GetValue<decimal>("maximum"));
                                if (value < avgSmoother.Minimum)
                                {
                                    avgSmoother.Maximum = avgSmoother.Minimum + 500;
                                    throw new Exception("Maximum must be greater than or equal to minimum (" + avgSmoother.Minimum + "). Setting maximum to " + avgSmoother.Maximum + ".");
                                }

                                avgSmoother.Maximum = value;
                            }
                            catch (Exception ex) { MessageBox.Show("Invalid value for maximum:  " + ex.Message); }
                        }
                    }
                    else if (smoother is MarsSmoother)
                    {
                        MarsSmoother marsSmoother = smoother as MarsSmoother;
                        DynamicForm f = new DynamicForm("Set MARS smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Number of considered parent terms (-1 for all):", marsSmoother.ConsideredParentTerms, 0, -1, decimal.MaxValue, 1, "parent");
                        f.AddNumericUpdown("Degree of interaction:", marsSmoother.InteractionDegree, 0, 1, decimal.MaxValue, 1, "interaction");
                        f.AddNumericUpdown("Number of knots (-1 for auto):", marsSmoother.NumberOfKnots, 0, -1, decimal.MaxValue, 1, "knots");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { marsSmoother.ConsideredParentTerms = Convert.ToInt32(f.GetValue<decimal>("parent")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for parent terms:  " + ex.Message); }

                            try { marsSmoother.InteractionDegree = Convert.ToInt32(f.GetValue<decimal>("interaction")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for interaction degree:  " + ex.Message); }

                            try { marsSmoother.NumberOfKnots = Convert.ToInt32(f.GetValue<decimal>("knots")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for number of knots:  " + ex.Message); }
                        }
                    }
                    else
                        throw new NotImplementedException("Unrecognized smoother type:  " + smoother.GetType().FullName);
                }
            }
        }
        private void Import(string downloadDirectory,
            CompleteImporterFormDelegate completeImporterForm,
            CreateImporterDelegate createImporter,
            string initialBrowsingDirectory,
            string fileBrowserFilter,
            string[] importFileSearchPatterns,
            ImportCompletionDelegate completionCallback)
        {
            Thread t = new Thread(new ThreadStart(delegate()
            {
                try
                {
                    DynamicForm importerForm = new DynamicForm("Enter import information...", DynamicForm.CloseButtons.OkCancel);

                    importerForm.AddTextBox("Import name (descriptive):", null, 70, "name");
                    importerForm.AddTextBox("Path:", null, 200, "path", addFileBrowsingButtons: true, initialBrowsingDirectory: initialBrowsingDirectory, fileFilter: fileBrowserFilter, textChanged: (o, e) =>
                        {
                            TextBox pathTextBox = o as TextBox;
                            ComboBox fileTypeCombo = importerForm.GetControl<ComboBox>("file_type");
                            string path = pathTextBox.Text.Trim().ToLower();
                            string extension = Path.GetExtension(path);
                            bool pathIsDirectory = Directory.Exists(path);
                            if (!pathIsDirectory)
                                if (extension == ".zip")
                                    fileTypeCombo.SelectedItem = ImportFileType.Zip;
                                else
                                    fileTypeCombo.SelectedItem = ImportFileType.Plain;
                        });

                    importerForm.AddTextBox("Download XML URI:", null, 200, "uri");
                    importerForm.AddDropDown("File type:", Enum.GetValues(typeof(ImportFileType)), ImportFileType.Plain, "file_type", true);
                    importerForm.AddCheckBox("Delete imported file after import:", ContentAlignment.MiddleRight, false, "delete");
                    importerForm.AddCheckBox("Save importer(s):", ContentAlignment.MiddleRight, false, "save_importer");

                    if (completeImporterForm != null)
                        importerForm = completeImporterForm(importerForm);

                    if (importerForm == null)
                        return;

                    if (importerForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        string p = importerForm.GetValue<string>("path").Trim();
                        ImportFileType fileType = (ImportFileType)importerForm.GetValue<object>("file_type");
                        bool pathIsDirectory = Directory.Exists(p);

                        if (pathIsDirectory)
                            downloadDirectory = p;

                        #region download file if a URI is given -- some callbacks need the file in order to set up the importer
                        string sourceURI = importerForm.GetValue<string>("uri");
                        if (!string.IsNullOrWhiteSpace(sourceURI))
                        {
                            if (string.IsNullOrWhiteSpace(p) || pathIsDirectory)
                            {
                                p = Path.Combine(downloadDirectory, ReplaceInvalidFilenameCharacters("uri_download_" + DateTime.Now.ToShortDateString() + "_" + DateTime.Now.ToLongTimeString() + (fileType == ImportFileType.Zip ? ".zip" : "")));
                                pathIsDirectory = false;
                            }

                            try { LAIR.IO.Network.Download(sourceURI, p); }
                            catch (Exception ex)
                            {
                                try { File.Delete(p); }
                                catch (Exception ex2) { Console.Out.WriteLine("Failed to delete partially downloaded file \"" + p + "\":  " + ex2.Message); }

                                Console.Out.WriteLine("Error downloading file from URI:  " + ex.Message);

                                return;
                            }
                        }
                        #endregion

                        #region decompress zip files if the user is providing them
                        if (fileType == ImportFileType.Zip)
                        {
                            string[] pathsToUnzip = new string[] { p };
                            if (pathIsDirectory)
                                pathsToUnzip = Directory.GetFiles(p, "*.zip", SearchOption.AllDirectories);

                            foreach (string pathToUnzip in pathsToUnzip)
                            {
                                string destinationDirectory = Importer.GetImportUnzipDirectory(pathToUnzip);
                                Console.Out.WriteLine("Unzipping \"" + pathToUnzip + "\" to \"" + destinationDirectory + "\"...");
                                try { ZipFile.ExtractToDirectory(pathToUnzip, destinationDirectory); }
                                catch (Exception) { }
                                if (!pathIsDirectory)
                                    p = destinationDirectory;
                            }

                            pathIsDirectory = true;
                        }
                        #endregion

                        string[] paths = new string[] { p };
                        if (pathIsDirectory)
                            paths = importFileSearchPatterns == null ? Directory.GetFiles(p, "*", SearchOption.AllDirectories) : importFileSearchPatterns.SelectMany(pattern => Directory.GetFiles(p, pattern, SearchOption.AllDirectories)).ToArray();

                        foreach (string path in paths)
                            if (File.Exists(path))
                            {
                                string importName = importerForm.GetValue<string>("name");
                                if (paths.Length > 1)
                                    importName = "";

                                bool deleteImportedFileAfterImport = importerForm.GetValue<bool>("delete");
                                bool saveImporter = Convert.ToBoolean(importerForm.GetValue<bool>("save_importer"));

                                try
                                {
                                    Importer importer = createImporter(importName, path, sourceURI, importerForm);
                                    importer.Import();

                                    if (deleteImportedFileAfterImport)
                                        File.Delete(path);

                                    if (saveImporter)
                                        importer.Save(false);
                                }
                                catch (Exception ex)
                                {
                                    Console.Out.WriteLine("Error while importing from \"" + path + "\":  " + ex.Message);
                                }
                            }
                    }
                }
                catch (Exception ex)
                {
                    Console.Out.WriteLine(ex.Message);
                }

                if (completionCallback != null)
                    completionCallback();
            }));

            t.SetApartmentState(ApartmentState.STA);
            t.Start();
        }