1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Text;
7 using System.Windows.Forms;
8 using System.Threading;
9 using System.Diagnostics;
10 using System.IO;
11 using System.Reflection;
12 
13 namespace distribution_explorer
14 {
15   /// <summary>
16   /// Main distribution explorer.
17   /// </summary>
18   public partial class DistexForm : Form
19   {
20 
21     EventLog log = new EventLog();
22     /// <summary>
23     /// Main form
24     /// </summary>
DistexForm()25     public DistexForm()
26     {
27       if (!EventLog.SourceExists("EventLogDistex"))
28       {
29         EventLog.CreateEventSource("EventLogDistex", "Application");
30       }
31       log.Source = "EventLogDistex";
32       log.WriteEntry("DistexForm");
33 
34       InitializeComponent();
35 
36       Application.DoEvents();
37     }
38 
Form_Load(object sender, EventArgs e)39     private void Form_Load(object sender, EventArgs e)
40     { // Load distribution & parameters names, and default values.
41       try
42       {
43         // Create and show splash screen:
44         this.Hide();
45         distexSplash frmSplash = new distexSplash();
46         frmSplash.Show();
47         frmSplash.Update();
48         // Now load our data while the splash is showing:
49         if (boost_math.any_distribution.size() <= 0)
50         {
51           MessageBox.Show("Problem loading any distributions, size = " + boost_math.any_distribution.size().ToString());
52         }
53         for (int i = 0; i < boost_math.any_distribution.size(); ++i)
54         {
55           distribution.Items.Add(boost_math.any_distribution.distribution_name(i));
56         }
57         distribution.SelectedIndex = 0; // 1st in array, but could be any other.
58         // All parameters are made zero by default, but updated from chosen distribution.
59         parameter1.Text = boost_math.any_distribution.first_param_default(0).ToString();
60         parameter2.Text = boost_math.any_distribution.second_param_default(0).ToString();
61         parameter3.Text = boost_math.any_distribution.third_param_default(0).ToString();
62         //
63         // Sleep and then close splash;
64         Thread.Sleep(3000);
65         frmSplash.Close();
66         this.Visible = true;
67       }
68       catch
69       { //
70         log.WriteEntry("DistexForm_load exception!");
71         MessageBox.Show("Problem loading distributions, size = " + boost_math.any_distribution.size().ToString());
72       }
73     }
74 
distribution_SelectedIndexChanged(object sender, EventArgs e)75     private void distribution_SelectedIndexChanged(object sender, EventArgs e)
76     {
77       int i = distribution.SelectedIndex; // distribution tab.
78       parameter1Label.Text = boost_math.any_distribution.first_param_name(i);
79       parameterLabel1.Text = boost_math.any_distribution.first_param_name(i); // properties tab.
80       parameter2Label.Text = boost_math.any_distribution.second_param_name(i);
81       parameter3Label.Text = boost_math.any_distribution.third_param_name(i);
82       if (boost_math.any_distribution.first_param_name(i).Length.CompareTo(0) != 0)
83       { // Actually all the distributions have at least one parameters,
84         parameter1.Visible = true; // so should always be true.
85         parameterLabel1.Visible = true;
86       }
87       else
88       { // If distribution chosen has no parameter name(s) then hide.
89         parameter1.Visible = false;
90         parameterLabel1.Visible = false;
91       }
92       parameter1.Text = boost_math.any_distribution.first_param_default(i).ToString();
93       // Update parameter default to match distribution.
94       if (boost_math.any_distribution.second_param_name(i).Length.CompareTo(0) != 0)
95       {
96         parameter2.Visible = true;
97         parameterLabel2.Visible = true;
98         parameter2ValueLabel.Visible = true;
99       }
100       else
101       { // hide
102         parameter2.Visible = false;
103         parameterLabel2.Visible = false;
104         parameter2ValueLabel.Visible = false;
105 
106       }
107       parameter2.Text = boost_math.any_distribution.second_param_default(i).ToString();
108       if (boost_math.any_distribution.third_param_name(i).Length.CompareTo(0) != 0)
109       {
110         parameter3.Visible = true;
111         parameterLabel3.Visible = true;
112         parameter3ValueLabel.Visible = true;
113       }
114       else
115       { // hide
116         parameter3.Visible = false;
117         parameterLabel3.Visible = false;
118         parameter3ValueLabel.Visible = false;
119       }
120       parameter3.Text = boost_math.any_distribution.third_param_default(i).ToString();
121       // Update tool tips to show total and supported ranges.
122       PropertiesTabPage.ToolTipText = "Shows properties and ranges of chosen distribution.";
123     }
124 
125     private boost_math.any_distribution dist;
126 
dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)127     private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
128     { // Display a grid of pdf, cdf... values from user's random variate x value.
129       try
130       {
131         if (e.ColumnIndex == 0)
132         { // Clicked on left-most random variate x column to enter a value.
133           int i = e.RowIndex;
134           string s = CDF_data.Rows[i].Cells[0].Value.ToString();
135           double x = double.Parse(s); // Get value of users random variate x.
136           double pdf = dist.pdf(x); // Compute pdf values from x
137           double cdf = dist.cdf(x); // & cdf
138           double ccdf = dist.ccdf(x); // & complements.
139           CDF_data.Rows[i].Cells[1].Value = pdf; // and display values.
140           CDF_data.Rows[i].Cells[2].Value = cdf;
141           CDF_data.Rows[i].Cells[3].Value = ccdf;
142         }
143       }
144       catch (SystemException se)
145       {
146           MessageBox.Show("Error in random variable value: " + se.Message, "Calculation Error");
147       }
148     }
149 
tabPage2_Enter(object sender, EventArgs e)150     private void tabPage2_Enter(object sender, EventArgs e)
151     { // Properties tab shows distribution's mean, mode, median...
152       try
153       { // Show chosen distribution name, and parameter names & values.
154         int i = distribution.SelectedIndex;
155         distributionValueLabel.Text = boost_math.any_distribution.distribution_name(i).ToString();
156         parameterLabel1.Text = boost_math.any_distribution.first_param_name(i).ToString();
157         parameter1ValueLabel.Text = double.Parse(parameter1.Text).ToString();
158         parameterLabel2.Text = boost_math.any_distribution.second_param_name(i).ToString();
159         parameter2ValueLabel.Text = double.Parse(parameter2.Text).ToString();
160         parameterLabel3.Text = boost_math.any_distribution.third_param_name(i).ToString();
161         parameter3ValueLabel.Text = double.Parse(parameter3.Text).ToString();
162 
163         // Show computed properties of distribution.
164         try
165         {
166             mean.Text = dist.mean().ToString();
167         }
168         catch
169         {
170             mean.Text = "Undefined.";
171         }
172         try
173         {
174             mode.Text = dist.mode().ToString();
175         }
176         catch
177         {
178             mode.Text = "Undefined.";
179         }
180         try
181         {
182             median.Text = dist.median().ToString();
183         }
184         catch
185         {
186             median.Text = "Undefined.";
187         }
188         try
189         {
190             variance.Text = dist.variance().ToString();
191         }
192         catch
193         {
194             variance.Text = "Undefined.";
195         }
196         try
197         {
198             standard_deviation.Text = dist.standard_deviation().ToString();
199         }
200         catch
201         {
202             standard_deviation.Text = "Undefined.";
203         }
204         try
205         {
206             skewness.Text = dist.skewness().ToString();
207         }
208         catch
209         {
210             skewness.Text = "Undefined.";
211         }
212         try
213         {
214             kurtosis.Text = dist.kurtosis().ToString();
215         }
216         catch
217         {
218             kurtosis.Text = "Undefined.";
219         }
220         try
221         {
222             kurtosis_excess.Text = dist.kurtosis_excess().ToString();
223         }
224         catch
225         {
226             kurtosis_excess.Text = "Undefined.";
227         }
228         try
229         {
230             coefficient_of_variation.Text = dist.coefficient_of_variation().ToString();
231         }
232         catch
233         {
234             coefficient_of_variation.Text = "Undefined.";
235         }
236 
237         rangeLowestLabel.Text = dist.lowest().ToString();
238         rangeGreatestLabel.Text = dist.uppermost().ToString();
239         supportLowerLabel.Text = dist.lower().ToString();
240         supportUpperLabel.Text = dist.upper().ToString();
241         cdfTabPage.ToolTipText = "Random variate can range from " + rangeLowestLabel.Text
242           + " to " + rangeGreatestLabel.Text
243           + ",\nbut is said to be supported from " + supportLowerLabel.Text
244           + " to " + supportUpperLabel.Text
245           + "\nWithin this supported range the PDF and CDF have values between 0 and 1,\nbut below " + supportLowerLabel.Text + " both are zero, and above "
246           +  supportUpperLabel.Text + " both are unity";
247       }
248       catch (SystemException se)
249       {
250         MessageBox.Show(se.Message, "Calculation Error!");
251       }
252     }
253 
properties_tab_Deselecting(object sender, TabControlCancelEventArgs e)254     private void properties_tab_Deselecting(object sender, TabControlCancelEventArgs e)
255     {
256       try
257       {
258         if (e.TabPageIndex == 0)
259         {   // Update selected distribution object:
260           double x = double.Parse(parameter1.Text);
261           double y = double.Parse(parameter2.Text);
262           double z = double.Parse(parameter3.Text);
263           int i = distribution.SelectedIndex;
264           dist = new boost_math.any_distribution(i, x, y, z);
265           // Clear existing CDF data (has to be a better way?):
266           while (CDF_data.Rows.Count > 1)
267           {
268             CDF_data.Rows.Remove(CDF_data.Rows[0]);
269           }
270           // Clear existing quantile data (has to be a better way?):
271           while (QuantileData.Rows.Count > 1)
272           {
273             QuantileData.Rows.Remove(QuantileData.Rows[0]);
274           }
275         }
276       }
277       catch (SystemException se)
278       {
279           MessageBox.Show(se.Message +
280               " Please check the distribution's parameters and try again.", "Distribution Error");
281           this.propertiesTab.SelectedIndex = 0;
282           e.Cancel = true;
283       }
284     }
285 
QuantileData_CellEndEdit(object sender, DataGridViewCellEventArgs e)286     private void QuantileData_CellEndEdit(object sender, DataGridViewCellEventArgs e)
287     { // aka Risk & critical values tab.
288       try
289       {
290         if (e.ColumnIndex == 0)
291         {
292           int i = e.RowIndex;
293           string s = QuantileData.Rows[i].Cells[0].Value.ToString();
294           double x = double.Parse(s);
295           // Remember x is alpha: 1 - the probability:
296           double lcv = dist.quantile(x);
297           double ucv = dist.quantile_c(x);
298           QuantileData.Rows[i].Cells[1].Value = lcv;
299           QuantileData.Rows[i].Cells[2].Value = ucv;
300         }
301       }
302       catch (SystemException se)
303       {
304         // TODO add some proper handling here!
305         MessageBox.Show("Error in probability value: " + se.Message, "Calculation Error");
306       }
307     }
308 
QuantileTab_Enter(object sender, EventArgs e)309     private void QuantileTab_Enter(object sender, EventArgs e)
310     { // Evaluate critical values (quantiles) for pre-chosen risk level.
311       // and then, optionally, for other user-provided risk levels.
312       try
313       {
314         if (QuantileData.Rows.Count == 1)
315         {
316           // Add some defaults:
317           QuantileData.Rows.Add(5); // 5 Risk levels.
318           QuantileData.Rows[0].Cells[0].Value = "0.001"; // Risk values as text,
319           QuantileData.Rows[0].Cells[1].Value = dist.quantile(0.001); // & as double.
320           QuantileData.Rows[0].Cells[2].Value = dist.quantile_c(0.001);
321           QuantileData.Rows[1].Cells[0].Value = "0.01";
322           QuantileData.Rows[1].Cells[1].Value = dist.quantile(0.01); // 99% confidence.
323           QuantileData.Rows[1].Cells[2].Value = dist.quantile_c(0.01);
324           QuantileData.Rows[2].Cells[0].Value = "0.05";
325           QuantileData.Rows[2].Cells[1].Value = dist.quantile(0.05);
326           QuantileData.Rows[2].Cells[2].Value = dist.quantile_c(0.05);
327           QuantileData.Rows[3].Cells[0].Value = "0.1";
328           QuantileData.Rows[3].Cells[1].Value = dist.quantile(0.1);
329           QuantileData.Rows[3].Cells[2].Value = dist.quantile_c(0.1);
330           QuantileData.Rows[4].Cells[0].Value = "0.33333333333333333";
331           QuantileData.Rows[4].Cells[1].Value = dist.quantile(0.33333333333333333);
332           QuantileData.Rows[4].Cells[2].Value = dist.quantile_c(0.33333333333333333);
333         }
334       }
335       catch (SystemException se)
336       {
337         // TODO add some proper handling here!
338         MessageBox.Show(se.Message, "Calculation Error");
339       }
340     }
341 
342 
properties_tab_SelectedIndexChanged(object sender, EventArgs e)343     private void properties_tab_SelectedIndexChanged(object sender, EventArgs e)
344     {
345     }
346 
tabPage1_Click(object sender, EventArgs e)347     private void tabPage1_Click(object sender, EventArgs e)
348     {
349     }
350 
CDF_data_CellContentClick(object sender, DataGridViewCellEventArgs e)351     private void CDF_data_CellContentClick(object sender, DataGridViewCellEventArgs e)
352     {
353     }
354 
355     distexAboutBox DistexAboutBox = new distexAboutBox();
356 
aboutToolStripMenuItem_Click(object sender, EventArgs e)357     private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
358     {
359       DistexAboutBox.ShowDialog();
360     }
361 
DistexForm_Activated(object sender, EventArgs e)362     private void DistexForm_Activated(object sender, EventArgs e)
363     {
364     }
365 
366     /// get AssemblyDescription
367     public string AssemblyDescription
368     {
369       get
370       {
371         // Get all Description attributes on this assembly
372         object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
373         // If there aren't any Description attributes, return an empty string
374         if (attributes.Length == 0)
375           return "";
376         // If there is a Description attribute, return its value
377         return ((AssemblyDescriptionAttribute)attributes[0]).Description;
378       }
379     }
380 
saveFileDialog1_FileOk(object sender, CancelEventArgs e)381     private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
382     {
383       using (StreamWriter sw = new StreamWriter(this.saveFileDialog.FileName))
384       { // Write distribution info and properties to file.
385         sw.WriteLine( AssemblyDescription);
386         sw.WriteLine("Version " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
387         // Get parameter names (null "" if no parameter).
388         int i = distribution.SelectedIndex;
389         distributionValueLabel.Text = boost_math.any_distribution.distribution_name(i).ToString();
390         sw.WriteLine(distributionValueLabel.Text + " distribution");
391         parameterLabel1.Text = boost_math.any_distribution.first_param_name(i).ToString();
392         parameterLabel2.Text = boost_math.any_distribution.second_param_name(i).ToString();
393         parameterLabel3.Text = boost_math.any_distribution.third_param_name(i).ToString();
394         string separator = "\t "; // , or tab or space?
395         // Write parameter name & value.
396         sw.WriteLine(parameterLabel1.Text + separator + this.parameter1.Text);
397         if (boost_math.any_distribution.second_param_name(i).Length.CompareTo(0) != 0)
398         { // Is a 2nd parameter.
399           sw.WriteLine(parameterLabel2.Text + separator +  this.parameter2.Text);
400         }
401         if (boost_math.any_distribution.third_param_name(i).Length.CompareTo(0) != 0)
402         { // Is a 3rd parameter.
403           sw.WriteLine(parameterLabel3.Text + separator + this.parameter3.Text);
404         }
405         sw.WriteLine();
406         sw.WriteLine("Properties");
407         // Show computed properties of distribution.
408         double x = double.Parse(parameter1.Text);
409         double y = double.Parse(parameter2.Text);
410         double z = double.Parse(parameter3.Text);
411         dist = new boost_math.any_distribution(i, x, y, z);
412         // Note global dist might not have been calculated yet if no of the tabs clicked.
413         try
414         {
415             mean.Text = dist.mean().ToString();
416         }
417         catch
418         {
419             mean.Text = "Undefined";
420         }
421         sw.WriteLine("Mean" + separator + mean.Text);
422         try
423         {
424             mode.Text = dist.mode().ToString();
425         }
426         catch
427         {
428             mode.Text = "Undefined";
429         }
430         sw.WriteLine("mode" + separator + mode.Text);
431         try
432         {
433             median.Text = dist.median().ToString();
434         }
435         catch
436         {
437             median.Text = "Undefined";
438         }
439         sw.WriteLine("Median" + separator + median.Text);
440         try
441         {
442             variance.Text = dist.variance().ToString();
443         }
444         catch
445         {
446             variance.Text = "Undefined";
447         }
448         sw.WriteLine("Variance" + separator + variance.Text);
449         try
450         {
451             standard_deviation.Text = dist.standard_deviation().ToString();
452         }
453         catch
454         {
455             standard_deviation.Text = "Undefined";
456         }
457         sw.WriteLine("Standard Deviation" + separator + standard_deviation.Text);
458         try
459         {
460             skewness.Text = dist.skewness().ToString();
461         }
462         catch
463         {
464             skewness.Text = "Undefined";
465         }
466         sw.WriteLine("Skewness" + separator + skewness.Text);
467         try
468         {
469             coefficient_of_variation.Text = dist.coefficient_of_variation().ToString();
470         }
471         catch
472         {
473             coefficient_of_variation.Text = "Undefined";
474         }
475         sw.WriteLine("Cofficient of variation" + separator + coefficient_of_variation.Text);
476         try
477         {
478             kurtosis.Text = dist.kurtosis().ToString();
479         }
480         catch
481         {
482             kurtosis.Text = "Undefined";
483         }
484         sw.WriteLine("Kurtosis" + separator + kurtosis.Text);
485         try
486         {
487             kurtosis_excess.Text = dist.kurtosis_excess().ToString();
488         }
489         catch
490         {
491             kurtosis_excess.Text = "Undefined";
492         }
493         sw.WriteLine("Kurtosis excess" + separator + kurtosis_excess.Text);
494         sw.WriteLine();
495 
496         sw.WriteLine("Range from" + separator + dist.lowest().ToString() + separator +
497         "to" + separator + dist.uppermost().ToString());
498         sw.WriteLine("Support from " + separator + dist.lower().ToString() +separator+
499         "to " + separator + dist.upper().ToString());
500         sw.WriteLine();
501 
502         //
503         sw.WriteLine("Quantiles");
504         if (QuantileData.Rows.Count == 1)
505         { // Add some defaults:
506           QuantileData.Rows.Add(5); // 5 Risk levels.
507           QuantileData.Rows[0].Cells[0].Value = "0.001"; // Risk values as text,
508           QuantileData.Rows[0].Cells[1].Value = dist.quantile(0.001); // & as double.
509           QuantileData.Rows[0].Cells[2].Value = dist.quantile_c(0.001);
510           QuantileData.Rows[1].Cells[0].Value = "0.01";
511           QuantileData.Rows[1].Cells[1].Value = dist.quantile(0.01); // 99% confidence.
512           QuantileData.Rows[1].Cells[2].Value = dist.quantile_c(0.01);
513           QuantileData.Rows[2].Cells[0].Value = "0.05";
514           QuantileData.Rows[2].Cells[1].Value = dist.quantile(0.05);
515           QuantileData.Rows[2].Cells[2].Value = dist.quantile_c(0.05);
516           QuantileData.Rows[3].Cells[0].Value = "0.1";
517           QuantileData.Rows[3].Cells[1].Value = dist.quantile(0.1);
518           QuantileData.Rows[3].Cells[2].Value = dist.quantile_c(0.1);
519           QuantileData.Rows[4].Cells[0].Value = "0.33333333333333333";
520           QuantileData.Rows[4].Cells[1].Value = dist.quantile(0.33333333333333333);
521           QuantileData.Rows[4].Cells[2].Value = dist.quantile_c(0.33333333333333333);
522         }
523         // else have already been calculated by entering the quantile tab.
524         for (int r = 0; r < QuantileData.Rows.Count-1; r++)
525         { // Show all the rows of quantiles, including any optional user values.
526           sw.WriteLine(QuantileData.Rows[r].Cells[0].Value.ToString() + separator +
527             QuantileData.Rows[r].Cells[1].Value.ToString() + separator +
528             QuantileData.Rows[r].Cells[2].Value.ToString());
529         }
530         sw.WriteLine();
531         sw.WriteLine("PDF, CDF & complement(s)");
532         for (int r = 0; r < CDF_data.Rows.Count-1; r++)
533         { // Show all the rows of pdf, cdf, including any optional user values.
534           sw.WriteLine(CDF_data.Rows[r].Cells[0].Value.ToString() + separator + // x value.
535             CDF_data.Rows[r].Cells[1].Value.ToString() + separator + // pdf
536             CDF_data.Rows[r].Cells[2].Value.ToString() + separator + // cdf
537             CDF_data.Rows[r].Cells[3].Value.ToString());// cdf complement.
538         }
539         sw.WriteLine();
540     }
541 
542     } // saveFileDialog1_FileOk
543 
saveToolStripMenuItem_Click(object sender, EventArgs e)544     private void saveToolStripMenuItem_Click(object sender, EventArgs e)
545     {
546       this.saveFileDialog.ShowDialog();
547     }
548 
saveAsToolStripMenuItem_Click(object sender, EventArgs e)549     private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
550     { // Same as Save.
551       this.saveFileDialog.ShowDialog();
552     }
553 
contentsToolStripMenuItem_Click(object sender, EventArgs e)554     private void contentsToolStripMenuItem_Click(object sender, EventArgs e)
555     { // In lieu of proper help.
556       string helpText = "\n" + AssemblyDescription +
557       "\nVersion " + Assembly.GetExecutingAssembly().GetName().Version.ToString() +
558       "\nA Windows utility to show the properties of distributions " +
559       "\nand permit calculation of probability density (or mass) function (PDF) " +
560       "\nand cumulative distribution function (CDF) and complements from values provided." +
561       "\nQuantiles are also calculated for typical risk (alpha) probabilities" +
562       "\nand for probabilities provided by the user." +
563       "\n" +
564       "\nResults can be saved to text files using Save or SaveAs." +
565       "\nAll the values on the four tabs are output to the file chosen," +
566       "\nand are tab separated to assist input to other programs," +
567       "\nfor example, spreadsheets or text editors." +
568       "\nNote: when importing to Excel, by default only 10 decimal digits are shown by Excel:" +
569       "\nit is necessary to format all cells to display the full 15 decimal digits," +
570       "\nalthough not all computed values will be as accurate as this." +
571       "\n\nValues shown as NaN cannot be calculated for the value given," +
572       "\nmost commonly because the value is outside the range for the distribution." +
573       "\n" +
574       "\nFor more information, including downloads, see " +
575       "\nhttp://sourceforge.net/projects/distexplorer/" +
576       "\n(Note that .NET framework 4.0 and VC Redistribution X86 are requirements for this program.)" +
577       "\n\nCopyright John Maddock & Paul A. Bristow 2007, 2009, 2010, 2012";
578 
579       MessageBox.Show("Statistical Distribution Explorer\n" + helpText);
580     }
581 
newToolStripMenuItem_Click(object sender, EventArgs e)582     private void newToolStripMenuItem_Click(object sender, EventArgs e)
583     {
584       MessageBox.Show("New is not yet implemented.");
585     }
586 
openToolStripMenuItem_Click(object sender, EventArgs e)587     private void openToolStripMenuItem_Click(object sender, EventArgs e)
588     {
589       MessageBox.Show("Open is not yet implemented.");
590     }
591 
printToolStripMenuItem_Click(object sender, EventArgs e)592     private void printToolStripMenuItem_Click(object sender, EventArgs e)
593     {
594       MessageBox.Show("Print is not yet implemented." +
595         "\nSave all values to a text file and print that file.");
596     }
597 
printPreviewToolStripMenuItem_Click(object sender, EventArgs e)598     private void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
599     {
600       MessageBox.Show("Print Preview is not yet implemented." +
601         "\nSave all values to a text file and print that file.");
602     }
603 
604 
exitToolStripMenuItem_Click(object sender, EventArgs e)605     private void exitToolStripMenuItem_Click(object sender, EventArgs e)
606     { // exit DistexForm
607         this.Close();
608     }
609   } // class DistexForm
610 } // namespace distribution_explorer