List:Commits« Previous MessageNext Message »
From:Mike Lischke Date:May 3 2011 2:12pm
Subject:bzr commit into wex-installer-1.0 branch (mike.lischke:456)
View as plain text  
#At file:///D:/Work/MySQL/installer/ based on revid:iggy@stripped

  456 Mike Lischke	2011-05-03
      - Adjusted default config.xml to current values.
      - IniTemplate: added support for non-formula-based values read from (existing) server config files.
      - Service control manager: don't hide exceptions for service manipulation in lower levels. The UI won't be able to show proper messages.

    modified:
      StandardPlugins/Server/IniTemplate.cs
      StandardPlugins/Server/MysqlSCM.cs
      StandardPlugins/Server/ServerConfigPanel2.cs
      StandardPlugins/StandardPlugins.csproj
      WexInstaller.Core/LoggerListener.cs
      common/config.xml
=== modified file 'StandardPlugins/Server/IniTemplate.cs'
=== modified file 'StandardPlugins/Server/IniTemplate.cs'
--- a/StandardPlugins/Server/IniTemplate.cs	2011-04-07 15:34:55 +0000
+++ b/StandardPlugins/Server/IniTemplate.cs	2011-05-03 14:12:50 +0000
@@ -3,1170 +3,1286 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
-using System.Text;
 using System.Text.RegularExpressions;
 
 namespace WexInstaller.Core
 {
-    public class IniTemplateStatic
-    {
-        protected string line_as_read;
-
-        public IniTemplateStatic(string input)
-        {
-            line_as_read = input;
-        }
-
-        public string LineAsRead
-        {
-            get { return line_as_read; }
-        }
-    }
-
-    public class IniTemplateVariable : IniTemplateStatic
-    {
-        private string variable_name;
-        private string formula;
-        private string options;
-        private string output_parameter;
-        private string default_value;
-        private bool reduce_result;
-        private bool disabled;
-
-        public IniTemplateVariable(string input, string name, string form, string opt)
-            : base(input)
-        {
-            variable_name = name;
-            formula = form;
-            options = opt;
-            reduce_result = opt.Contains("USE_BYTES");
-            disabled = false;
-        }
-
-        public string VariableName
-        {
-            get { return variable_name; }
-        }
-        public string Formula
-        {
-            get { return formula; }
-        }
-        public string Options
-        {
-            get { return options; }
-        }
-        public bool ReduceResult
-        {
-            get { return reduce_result; }
-            set { reduce_result = value; }
-        }
-        public bool Disabled
-        {
-            get { return disabled; }
-            set { disabled = value; }
-        }
-        public string OutputParameter
-        {
-            get { return output_parameter; }
-            set { output_parameter = value; }
-        }
-        public string DefaultValue
-        {
-            get { return default_value; }
-            set { default_value = value; }
-        }
-    }
-
-    public enum IniServerType
-    {
-        Developer,
-        Server,
-        Dedicated,
-        InternalUnitTest  // This will produce an unusable template file that is suitable testing on disparate hardware.
-    }
-
-    public class IniTemplate
-    {
-        #region Private
-        private string template;
-        private FormulaEngine fe;
-        private Queue output;
-        private IniServerType ist;
-
-        private void SetDefaults()
-        {
-            fe = new FormulaEngine();
-            output = new Queue();
-            EnableStrictMode = true;
-            EnableNetworking = true;
-            DefaultCharacterSet = "utf8";
-            InnoDBHomeDir = "";
-            DefaultStorageEngine = "INNODB";
-            Port = "3306";
-            SkipInnodb = false;
-            Reconfiguring = false;
-            IsValid = false;
-            OutputExists = false;
-            ServerType = IniServerType.Developer;
-            FoundExistingDataDir = false;
-        }
-
-        private bool OpenTemplate(string templateName)
-        {
-            bool great_success = false;
-
-            try
+  public class IniTemplateStatic
+  {
+    protected string line_as_read;
+
+    public IniTemplateStatic(string input)
+    {
+      line_as_read = input;
+    }
+
+    public string LineAsRead
+    {
+      get { return line_as_read; }
+    }
+  }
+
+  public class IniTemplateVariable : IniTemplateStatic
+  {
+    private string variable_name;
+    private string options;
+    private string output_parameter;
+    private string default_value;
+    private bool reduce_result;
+    private bool disabled;
+
+    public IniTemplateVariable(string input, string name, string form, string opt)
+      : base(input)
+    {
+      variable_name = name;
+      Formula = form;
+      options = opt;
+      reduce_result = opt.Contains("USE_BYTES");
+      disabled = false;
+    }
+
+    public string VariableName
+    {
+      get { return variable_name; }
+    }
+    public string Formula { get; set; }
+    public string Options
+    {
+      get { return options; }
+    }
+    public bool ReduceResult
+    {
+      get { return reduce_result; }
+      set { reduce_result = value; }
+    }
+    public bool Disabled
+    {
+      get { return disabled; }
+      set { disabled = value; }
+    }
+    public string OutputParameter
+    {
+      get { return output_parameter; }
+      set { output_parameter = value; }
+    }
+    public string DefaultValue
+    {
+      get { return default_value; }
+      set { default_value = value; }
+    }
+  }
+
+  public enum IniServerType
+  {
+    Developer,
+    Server,
+    Dedicated,
+    InternalUnitTest  // This will produce an unusable template file that is suitable testing on disparate hardware.
+  }
+
+  public class IniTemplate
+  {
+    #region Private
+  
+    private string template;
+    private FormulaEngine fe;
+    private Queue output;
+    private IniServerType ist;
+
+    private void SetDefaults()
+    {
+      fe = new FormulaEngine();
+      output = new Queue();
+      EnableStrictMode = true;
+      EnableNetworking = true;
+      DefaultCharacterSet = "utf8";
+      InnoDBHomeDir = "";
+      DefaultStorageEngine = "INNODB";
+      Port = "3306";
+      SkipInnodb = false;
+      Reconfiguring = false;
+      IsValid = false;
+      OutputExists = false;
+      ServerType = IniServerType.Developer;
+      FoundExistingDataDir = false;
+    }
+
+    /// <summary>
+    /// Parses the given configuration file, which can either be an instance of our template
+    /// or an existing configuration file. Keep in mind that we cannot rely on our template syntax
+    /// entirely as the user might have manually changed the configuration file for his server.
+    /// </summary>
+    private bool ParseConfigurationFile(string templateName)
+    {
+      bool greatSuccess = false;
+
+      try
+      {
+        StreamReader reader = new StreamReader(templateName);
+        string currentSection = "default";
+
+        while (!reader.EndOfStream)
+        {
+          string currentLine = reader.ReadLine();
+
+          if (currentLine.StartsWith("##")) // Template comment, do not output.
+            continue;
+
+          if (currentLine.StartsWith("# [")) // # [VARIABLE_NAME]="Formula", "Options"
+            ParseFormula(currentLine, reader);
+          else
+          {
+            bool processed = false;
+
+            // See if we enter a new section in the file. We need that later to translate
+            // configuration value names to our internal variable names.
+            Regex section = new Regex(@"\s*\[(?<section>[a-zA-Z]+)]");
+            Match sectionMatch = section.Match(currentLine);
+            if (sectionMatch.Success)
+              currentSection = sectionMatch.Groups["section"].Value.ToLowerInvariant();
+            else
             {
-                StreamReader reader = new StreamReader(templateName);
-                string current_line = null;
-
-                while (!reader.EndOfStream)
+              // Check for simple name=value pairs not associated with a formula and process them.
+              Regex nameValuePair = new Regex(@"(?<disabled>[#\s]+)?(?<name>[a-zA-Z_-]+)(=(?<value>.+)?)?");
+              Match match = nameValuePair.Match(currentLine);
+              if (match.Success)
+              {
+                // Process all those settings which can be set through the UI during the configuration
+                // step. Everything else will just get passed through.
+                // The list of supported var names might need to be passed in by the UI
+                string name = match.Groups["name"].Value.ToLowerInvariant();
+                string variableName = "";
+                switch (name)
                 {
-                    current_line = reader.ReadLine();
-
-                    if (current_line.StartsWith("##")) // Template comment, do not output
-                        continue;
-
-                    if (current_line.StartsWith("# [")) // # [VARIABLE_NAME]="Forumla", "Options"
-                    {
-                        Regex TemplateFormulaExp = new Regex(@"\[(?<var_name>[^@]+)\]=""(?<formula>[^""]+)""((?:,\s*"")(?<options>[^@]+)?(?:""))?");
-                        Match m = TemplateFormulaExp.Match(current_line);
-
-                        if (m.Success)
-                        {
-                            string variable_name = m.Groups["var_name"].Value;
-                            IniTemplateVariable itv = new IniTemplateVariable(current_line, variable_name, m.Groups["formula"].Value, m.Groups["options"].Value);
-
-                            if (variable_name != "STATE_CHANGE")
-                            {
-                                current_line = reader.ReadLine();
-                                Regex TemplateOutputFormat = new Regex(@"(?<disabled>[#\s]+)?(?<output>.+)=(?<default>.+)?");
-                                Match m2 = TemplateOutputFormat.Match(current_line);
-                                if (m2.Success)
-                                {
-                                    itv.DefaultValue = m2.Groups["default"].Value;
-                                    itv.Disabled = m2.Groups["disabled"].Value.Contains("#");
-                                    itv.OutputParameter = m2.Groups["output"].Value;
-                                }
-
-                                // Attempt to set values from template, just the basics.
-                                switch (itv.VariableName)
-                                {
-                                    case "BASE_DIR":
-                                        if (itv.DefaultValue != null)
-                                        {
-                                            string defaultValue = itv.DefaultValue.Replace('\"', ' ').Trim();
-                                            if (defaultValue.Length > 0)
-                                                BaseDir = defaultValue;
-                                        }
-                                        break;
-                                    case "DATA_DIR":
-                                        if (itv.DefaultValue != null)
-                                        {
-                                            string defaultValue = itv.DefaultValue.Replace('\"', ' ').Trim();
-                                            if (defaultValue.Length > 0)
-                                            {
-                                                defaultValue = defaultValue.Replace("\\data\\", "\\");
-                                                defaultValue = defaultValue.Replace("\\Data\\", "\\");
-                                                DataDir = defaultValue.Trim();
-                                            }
-                                        }
-                                        break;
-                                    case "CLIENT_PORT":
-                                    case "SERVER_PORT":
-                                        this.EnableNetworking = !itv.Disabled;
-                                        if (EnableNetworking && itv.DefaultValue != "")
-                                            Port = itv.DefaultValue;
-                                        break;
-                                    case "CLIENT_PIPE":
-                                    case "CLIENT_SOCKET":
-                                    case "SERVER_PIPE":
-                                    case "SERVER_SOCKET":
-                                    case "SERVER_SKIP":
-                                        this.EnableNetworking = itv.Disabled;
-                                        break;
-                                    case "INNODB_HOME":
-                                        if (itv.Disabled == false)
-                                        {
-                                            InnoDBHomeDir = itv.DefaultValue;
-                                        }
-                                        else
-                                        {
-                                            InnoDBHomeDir = "";
-                                        }
-                                        break;
-                                    case "SERVER_TYPE":
-                                        itv.Disabled = true;
-                                        switch (itv.DefaultValue)
-                                        {
-                                            case "1":
-                                                ServerType = IniServerType.Dedicated;
-                                                break;
-                                            case "2":
-                                                ServerType = IniServerType.Server;
-                                                break;
-                                            case "3":
-                                            default:
-                                                ServerType = IniServerType.Developer;
-                                                break;
-                                        }
-                                        break;
-                                    case "STATE_CHANGE":
-                                    case "SQL_MODE":
-                                    case "INNODB_LOG_FILE_SIZE":
-                                    case "SKIP_INNODB":
-                                        break;
-                                }
-                            }
-
-                            output.Enqueue(itv);
-                        }
-                    }
+                  case "port":
+                    if (currentSection == "client")
+                      variableName = "CLIENT_PORT";
                     else
-                    {
-                        output.Enqueue(new IniTemplateStatic(current_line));
-                    }
-                }
-
-                reader.Close();
-                reader.Dispose();
-
-                great_success = true;
-            }
-            catch
-            {
-                // Do cleanup.
-            }
-
-            return great_success;
-        }
-
-        private string ReduceBytesToString(double value)
-        {
-            string output = "";
-            int unit_type = 0;
-            char[] unit_names = new char[4] { ' ', 'K', 'M', 'G' };
-
-            while (value / 1024 >= 1.0)
-            {
-                double round_up = 0.0;
-                if (value % 1024 > 0)
-                    ++round_up;
-                value /= 1024;
-                value = Math.Round(value + round_up);
-                ++unit_type;
-            }
-
-            output += value.ToString();
-            if (unit_type >= 1)
-                output += unit_names[unit_type].ToString();
-
-            return output;
-        }
-        #endregion
-
-        #region Public
-        public IniTemplate(string base_dir, string data_dir, string template_name, string output_dir)
-        {
-            SetDefaults();
-            BaseDir = base_dir;
-            DataDir = data_dir;
-
-            ConfigurationFile = String.Format("{0}my.ini", output_dir);
-            if (File.Exists(ConfigurationFile))
-            {
-                // Create a backup of the existing file(s).
-                string datetime = DateTime.Now.GetDateTimeFormats('s')[0].Replace(':', '-');
-                string newConfig = String.Format("{0}my_{1}.ini", output_dir, datetime);
-
-                int i = 0;
-                while (File.Exists(newConfig))
-                {
-                    i += 1;
-                    newConfig = String.Format("{0}my_{1}_{2}.ini", output_dir, datetime, i.ToString());
-                }
+                      variableName = "SERVER_PORT";
+                    break;
+
+                  case "skip-networking":
+                    variableName = "SERVER_SKIP"; // Only possible with a server section.
+                    break;
+                }
+
+                if (variableName.Length > 0)
+                {
+                  processed = true;
+                  string value = match.Groups["value"].Value;
+                  IniTemplateVariable itv = new IniTemplateVariable(currentLine, variableName, value, "");
+                  itv.DefaultValue = value;
+                  itv.Disabled = match.Groups["disabled"].Value.Contains("#");
+                  itv.OutputParameter = match.Groups["name"].Value;
+
+                  switch (variableName)
+                  {
+                    case "SERVER_PORT":
+                      if (itv.DefaultValue != null)
+                        Port = value;
+                      EnableNetworking = !itv.Disabled;
+                      itv.Formula = "port";
+                      break;
+
+                    case "SERVER_SKIP":
+                      EnableNetworking = itv.Disabled;
+                      break;
+                  }
+                  output.Enqueue(itv);
+                }
+              }
+            }
+
+            // Anything else we just pipe through.
+            if (!processed)
+              output.Enqueue(new IniTemplateStatic(currentLine));
+          }
+        }
+
+        reader.Close();
+        reader.Dispose();
+
+        greatSuccess = true;
+      }
+      catch
+      {
+        // TODO: Do cleanup/logging.
+      }
+
+      return greatSuccess;
+    }
+
+    /// <summary>
+    /// Parses a single formula line plus another line following it where necessary.
+    /// </summary>
+    private void ParseFormula(string currentLine, StreamReader reader)
+    {
+      Regex TemplateFormulaExp = new Regex(@"\[(?<var_name>[^@]+)\]=""(?<formula>[^""]+)""((?:,\s*"")(?<options>[^@]+)?(?:""))?");
+      Match m = TemplateFormulaExp.Match(currentLine);
+
+      if (m.Success)
+      {
+        string variableName = m.Groups["var_name"].Value;
+        IniTemplateVariable itv = new IniTemplateVariable(currentLine, variableName, m.Groups["formula"].Value, m.Groups["options"].Value);
+
+        if (variableName != "STATE_CHANGE")
+        {
+          currentLine = reader.ReadLine();
+          Regex TemplateOutputFormat = new Regex(@"(?<disabled>[#\s]+)?(?<output>.+)=(?<default>.+)?");
+          Match m2 = TemplateOutputFormat.Match(currentLine);
+          if (m2.Success)
+          {
+            itv.DefaultValue = m2.Groups["default"].Value;
+            itv.Disabled = m2.Groups["disabled"].Value.Contains("#");
+            itv.OutputParameter = m2.Groups["output"].Value;
+          }
+
+          // Attempt to set values from template, just the basics.
+          switch (itv.VariableName)
+          {
+            case "BASE_DIR":
+              if (itv.DefaultValue != null)
+              {
+                string defaultValue = itv.DefaultValue.Replace('\"', ' ').Trim();
+                if (defaultValue.Length > 0)
+                  BaseDir = defaultValue;
+              }
+              break;
+
+            case "DATA_DIR":
+              if (itv.DefaultValue != null)
+              {
+                string defaultValue = itv.DefaultValue.Replace('\"', ' ').Trim();
+                if (defaultValue.Length > 0)
+                {
+                  defaultValue = defaultValue.Replace("\\data\\", "\\");
+                  defaultValue = defaultValue.Replace("\\Data\\", "\\");
+                  DataDir = defaultValue.Trim();
+                }
+              }
+              break;
+
+            case "CLIENT_PORT":
+            case "SERVER_PORT":
+              this.EnableNetworking = !itv.Disabled;
+              if (EnableNetworking && itv.DefaultValue != "")
+                Port = itv.DefaultValue;
+              break;
+
+            case "CLIENT_PIPE":
+            case "CLIENT_SOCKET":
+            case "SERVER_PIPE":
+            case "SERVER_SOCKET":
+            case "SERVER_SKIP":
+              this.EnableNetworking = itv.Disabled;
+              break;
+
+            case "INNODB_HOME":
+              if (!itv.Disabled)
+                InnoDBHomeDir = itv.DefaultValue;
+              else
+                InnoDBHomeDir = "";
+
+              break;
+
+            case "SERVER_TYPE":
+              itv.Disabled = true;
+              switch (itv.DefaultValue)
+              {
+                case "1":
+                  ServerType = IniServerType.Dedicated;
+                  break;
+
+                case "2":
+                  ServerType = IniServerType.Server;
+                  break;
+
+                default: // 3
+                  ServerType = IniServerType.Developer;
+                  break;
+              }
+              break;
+
+            case "STATE_CHANGE":
+            case "SQL_MODE":
+            case "INNODB_LOG_FILE_SIZE":
+            case "SKIP_INNODB":
+              break;
+          }
+        }
+        output.Enqueue(itv);
+      }
+    }
+
+    private string ReduceBytesToString(double value)
+    {
+      string output = "";
+      int unitType = 0;
+      char[] unitNames = new char[4] { ' ', 'K', 'M', 'G' };
+
+      while (value / 1024 >= 1.0)
+      {
+        double roundUp = 0.0;
+        if (value % 1024 > 0)
+          ++roundUp;
+        value /= 1024;
+        value = Math.Round(value + roundUp);
+        ++unitType;
+      }
+
+      output += value.ToString();
+      if (unitType >= 1)
+        output += unitNames[unitType].ToString();
+
+      return output;
+    }
+
+    #endregion
+
+    #region Public
+
+    public IniTemplate(string baseDir, string dataDir, string templateName, string outputDir)
+    {
+      SetDefaults();
+      BaseDir = baseDir;
+      DataDir = dataDir;
+
+      ConfigurationFile = String.Format("{0}my.ini", outputDir);
+      if (File.Exists(ConfigurationFile))
+      {
+        // Create a backup of the existing file(s).
+        string datetime = DateTime.Now.GetDateTimeFormats('s')[0].Replace(':', '-');
+        string newConfig = String.Format("{0}my_{1}.ini", outputDir, datetime);
+
+        int i = 0;
+        while (File.Exists(newConfig))
+        {
+          i += 1;
+          newConfig = String.Format("{0}my_{1}_{2}.ini", outputDir, datetime, i.ToString());
+        }
                 
-                File.Copy(ConfigurationFile, newConfig);
-                OutputExists = true;
-            }
-
-            IsValid = OpenTemplate(ConfigurationFile);
-            if (IsValid)
-            {
-                template = ConfigurationFile;
-                Reconfiguring = true;
-            }
-            else
-            {
-                template = template_name;
-                output.Clear();
-                IsValid = OpenTemplate(template);
-            }
-        }
-
-        public void ProcessTemplate()
-        {
-            fe.AssignFormulaVariable("basedir", String.Format("\"{0}\"", BaseDir));
-            fe.AssignFormulaVariable("datadir", String.Format("\"{0}data\\\"", DataDir));
-            fe.AssignFormulaVariable("port", Port);
-            fe.AssignFormulaVariable("default_storage_engine", DefaultStorageEngine);
-            fe.AssignFormulaVariable("default_character_set", DefaultCharacterSet);
-            fe.AssignFormulaVariable("myisam_percentage", MyisamUsage.ToString());
-            fe.AssignFormulaVariable("innodb_buffer_pool_size_percentage", InnoDBBPSUsage.ToString());
-            fe.AssignFormulaVariable("active_connections", NumberConnections.ToString());
-            fe.AssignFormulaVariable("query_cache_pct", UseQueryCache.ToString());
-
-            StreamWriter writer = new StreamWriter(ConfigurationFile);
-
-            foreach (object obj in output)
-            {
-                if (obj.GetType() == typeof(IniTemplateVariable))
-                {
-                    IniTemplateVariable itv = (IniTemplateVariable)obj;
-                    string result;
-                    fe.Parse(itv.Formula);
-                    result = fe.Evaluate();
-
-                    writer.WriteLine(itv.LineAsRead);
-                    switch (itv.VariableName)
-                    {
-                        case "STATE_CHANGE":
-                            // continue;
-                            break;
-                        case "CLIENT_PORT":
-                        case "SERVER_PORT":
-                            itv.Disabled = !this.EnableNetworking;
-                            break;
-                        case "CLIENT_PIPE":
-                        case "CLIENT_SOCKET":
-                        case "SERVER_PIPE":
-                        case "SERVER_SOCKET":
-                        case "SERVER_SKIP":
-                            itv.Disabled = this.EnableNetworking;
-                            break;
-                        case "SQL_MODE":
-                            itv.Disabled = true;
-                            break;
-                        case "INNODB_HOME":
-                            if (InnoDBHomeDir != "")
-                            {
-                                itv.Disabled = false;
-                                fe.AssignFormulaVariable("innodb_home", InnoDBHomeDir);
-                            }
-                            else
-                            {
-                                itv.Disabled = true;
-                            }
-                            break;
-                        case "INNODB_LOG_FILE_SIZE":
-                            if (itv.DefaultValue != "")
-                            {
-                                result = itv.DefaultValue;
-                                itv.ReduceResult = false;
-                            }
-                            break;
-                        case "SKIP_INNODB":
-                            itv.Disabled = SkipInnodb;
-                            break;
-                    }
-                    if (itv.VariableName != "STATE_CHANGE")
-                        writer.WriteLine((itv.Disabled ? "# " : "") + itv.OutputParameter + "=" + (itv.ReduceResult ? ReduceBytesToString(double.Parse(result)) : result));
-
-                }
-                else
-                {
-                    IniTemplateStatic its = (IniTemplateStatic)obj;
-                    writer.WriteLine(its.LineAsRead);
-                }
-            }
-
-            writer.Close();
-            writer.Dispose();
-        }
-
-        public IniServerType ServerType
-        {
-            get
-            {
-                return ist;
-            }
-            set
-            {
-                ist = value;
-
-                PerformanceCounter pc = new PerformanceCounter("Memory", "Available Bytes", "");
-                double system_available_memory = (double)pc.NextValue();
-                double mysql_memory_percentage = 0.08333; // By default, all servers should use 1/12 available system memory.
-
-                fe.AssignFormulaVariable("cpus", Environment.ProcessorCount.ToString());
-
-                switch (ist)
-                {
-                    case IniServerType.Dedicated:
-                        mysql_memory_percentage = 0.90;
-                        fe.AssignFormulaVariable("server_type", "1");
-                        break;
-                    case IniServerType.Server:
-                        mysql_memory_percentage = 0.50;
-                        fe.AssignFormulaVariable("server_type", "2");
-                        break;
-                    case IniServerType.InternalUnitTest:
-                        mysql_memory_percentage = 0;
-                        system_available_memory = 0.0;
-                        fe.AssignFormulaVariable("cpus", "0.0");
-                        fe.AssignFormulaVariable("server_type", "4");
-                        break;
-                    case IniServerType.Developer:
-                    default:
-                        fe.AssignFormulaVariable("server_type", "3");
-                        if (system_available_memory < (48 * 1024 * 1024))
-                        {
-                            system_available_memory = 48 * 1024 * 1024;
-                            mysql_memory_percentage = 1.0;
-                        }
-                        break;
-                }
-
-                fe.AssignFormulaVariable("memory", (system_available_memory * mysql_memory_percentage).ToString());
-            }
-        }
-
-        public double MyisamUsage { get; set; }
-
-        public double InnoDBBPSUsage { get; set; }
-
-        public double NumberConnections { get; set; }
-
-        public double UseQueryCache { get; set; }
-
-        public bool FoundExistingDataDir { get; set; }
-
-        public bool IsValid { get; private set; }
-
-        public bool Reconfiguring { get; private set; }
-
-        public bool OutputExists { get; private set; }
-
-        public bool EnableStrictMode { get; set; }
-
-        public bool EnableNetworking { get; set; }
-
-        public bool SkipInnodb { get; set; }
-
-        public string DefaultStorageEngine { get; set; }
-
-        public string DefaultCharacterSet { get; set; }
-
-        public string BaseDir { get; set; }
-
-        public string DataDir { get; set; }
-
-        public string InnoDBHomeDir { get; set; }
-
-        public string Port { get; set; }
-
-        public string ConfigurationFile { get; set; }
-
-        #endregion
-    }
-
-    public enum FormulaTokenType
-    {
-        None,
-        Number,
-        Constant,
-        Variable,
-        Assignment,
-        Plus,
-        Minus,
-        Multiply,
-        Divide,
-        Exponent,
-        UnaryMinus,
-        Sine,
-        Cosine,
-        Tangent,
-        Round,
-        Min,
-        Max,
-        LeftParenthesis,
-        RightParenthesis
-    }
-
-    public struct FormulaToken
-    {
-        public string TokenValue;
-        public FormulaTokenType TokenValueType;
-    }
-
-    public class FormulaEngine
-    {
-        private Dictionary<string, string> formula_variables;
-        private Queue output;
-        private Stack ops;
-        private string original_expression;
-        private string transition_expression;
-        private string postfix_expression;
-
-        public string OriginalExpression
-        {
-            get { return original_expression; }
-        }
-
-        public string TransitionExpression
-        {
-            get { return transition_expression; }
-        }
-
-        public string PostfixExpression
-        {
-            get { return postfix_expression; }
-        }
-
-        public FormulaEngine()
-        {
-            original_expression = string.Empty;
-            transition_expression = string.Empty;
-            postfix_expression = string.Empty;
-            formula_variables = new Dictionary<string, string>();
-        }
-
-        public void Parse(string Expression)
-        {
-            output = new Queue();
-            ops = new Stack();
-
-            original_expression = Expression;
-
-            string rpn_buffer = Expression;
-
-            // filter out the K, M, G unit specifiers.
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)K", " ${number} * 1024 ");
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)M", " ${number} * 1024 * 1024");
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)G", " ${number} * 1024 * 1024 * 1024");
-            rpn_buffer = rpn_buffer.ToLower();
-
-            // captures numbers. Anything like 11 or 22.34 is captured
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)", " ${number} ");
-            // captures these symbols: + - * / ^ ( )
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<ops>[+\-*/^:()])", " ${ops} ");
-            // captures constants, variables, and math fucntions.
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<var>([a-z_]+))", " ${var} ");
-            // trims up consecutive spaces and replace it with just one space
-            rpn_buffer = Regex.Replace(rpn_buffer, @"\s+", " ").Trim();
-
-            // The following chunk captures unary minus operations.
-            // 1) We replace every minus sign with the string "MINUS".
-            // 2) Then if we find a "MINUS" with a number or constant in front,
-            //    then it's a normal minus operation.
-            // 3) Otherwise, it's a unary minus operation.
-
-            // Step 1.
-            rpn_buffer = Regex.Replace(rpn_buffer, "-", "MINUS");
-            // Step 2. Looking for pi or e or generic number \d+(\.\d+)?
-            //rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>(pi|e|(\d+(\.\d+)?)))\s+MINUS", "${number} -");
-            rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>([a-z_]+|[)]|(\d+(\.\d+)?)))\s+MINUS", "${number} -");
-            // Step 3. Use the tilde ~ as the unary minus operator
-            rpn_buffer = Regex.Replace(rpn_buffer, "MINUS", "~");
-
-            transition_expression = rpn_buffer;
-
-            // tokenize it!
-            string[] parsed_tokens = rpn_buffer.Split(" ".ToCharArray());
-            int i = 0;
-            double token_value;
-            FormulaToken token, opstoken;
-            for (i = 0; i < parsed_tokens.Length; ++i)
-            {
-                token = new FormulaToken();
-                token.TokenValue = parsed_tokens[i];
-                token.TokenValueType = FormulaTokenType.None;
-
-                try
-                {
-                    token_value = double.Parse(parsed_tokens[i]);
-                    token.TokenValueType = FormulaTokenType.Number;
-                    // If the token is a number, then add it to the output queue.
-                    output.Enqueue(token);
-                }
-                catch
-                {
-                    switch (parsed_tokens[i])
-                    {
-                        case "+":
-                            token.TokenValueType = FormulaTokenType.Plus;
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // while there is an operator, o2, at the top of the stack
-                                while (IsOperatorToken(opstoken.TokenValueType))
-                                {
-                                    // pop o2 off the stack, onto the output queue;
-                                    output.Enqueue(ops.Pop());
-                                    if (ops.Count > 0)
-                                    {
-                                        opstoken = (FormulaToken)ops.Peek();
-                                    }
-                                    else
-                                    {
-                                        break;
-                                    }
-                                }
-                            }
-                            // push o1 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case "-":
-                            token.TokenValueType = FormulaTokenType.Minus;
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // while there is an operator, o2, at the top of the stack
-                                while (IsOperatorToken(opstoken.TokenValueType))
-                                {
-                                    // pop o2 off the stack, onto the output queue;
-                                    output.Enqueue(ops.Pop());
-                                    if (ops.Count > 0)
-                                    {
-                                        opstoken = (FormulaToken)ops.Peek();
-                                    }
-                                    else
-                                    {
-                                        break;
-                                    }
-                                }
-                            }
-                            // push o1 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case "*":
-                            token.TokenValueType = FormulaTokenType.Multiply;
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // while there is an operator, o2, at the top of the stack
-                                while (IsOperatorToken(opstoken.TokenValueType))
-                                {
-                                    if (opstoken.TokenValueType == FormulaTokenType.Plus || opstoken.TokenValueType == FormulaTokenType.Minus || opstoken.TokenValueType == FormulaTokenType.Assignment)
-                                    {
-                                        break;
-                                    }
-                                    else
-                                    {
-                                        // Once we're in here, the following algorithm condition is satisfied.
-                                        // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
-                                        // o1 is right-associative and its precedence is less than (lower precedence) that of o2,
-
-                                        // pop o2 off the stack, onto the output queue;
-                                        output.Enqueue(ops.Pop());
-                                        if (ops.Count > 0)
-                                        {
-                                            opstoken = (FormulaToken)ops.Peek();
-                                        }
-                                        else
-                                        {
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                            // push o1 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case "/":
-                            token.TokenValueType = FormulaTokenType.Divide;
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // while there is an operator, o2, at the top of the stack
-                                while (IsOperatorToken(opstoken.TokenValueType))
-                                {
-                                    if (opstoken.TokenValueType == FormulaTokenType.Plus || opstoken.TokenValueType == FormulaTokenType.Minus || opstoken.TokenValueType == FormulaTokenType.Assignment)
-                                    {
-                                        break;
-                                    }
-                                    else
-                                    {
-                                        // Once we're in here, the following algorithm condition is satisfied.
-                                        // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
-                                        // o1 is right-associative and its precedence is less than (lower precedence) that of o2,
-
-                                        // pop o2 off the stack, onto the output queue;
-                                        output.Enqueue(ops.Pop());
-                                        if (ops.Count > 0)
-                                        {
-                                            opstoken = (FormulaToken)ops.Peek();
-                                        }
-                                        else
-                                        {
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                            // push o1 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case "^":
-                            token.TokenValueType = FormulaTokenType.Exponent;
-                            // push o1 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case "~":
-                            token.TokenValueType = FormulaTokenType.UnaryMinus;
-                            // push o1 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case "(":
-                            token.TokenValueType = FormulaTokenType.LeftParenthesis;
-                            // If the token is a left parenthesis, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case ")":
-                            token.TokenValueType = FormulaTokenType.RightParenthesis;
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // Until the token at the top of the stack is a left parenthesis
-                                while (opstoken.TokenValueType != FormulaTokenType.LeftParenthesis)
-                                {
-                                    // pop operators off the stack onto the output queue
-                                    output.Enqueue(ops.Pop());
-                                    if (ops.Count > 0)
-                                    {
-                                        opstoken = (FormulaToken)ops.Peek();
-                                    }
-                                    else
-                                    {
-                                        // If the stack runs out without finding a left parenthesis,
-                                        // then there are mismatched parentheses.
-                                        throw new Exception("Unbalanced parenthesis!");
-                                    }
+        File.Copy(ConfigurationFile, newConfig);
+        OutputExists = true;
+      }
+
+      IsValid = ParseConfigurationFile(ConfigurationFile);
+      if (IsValid)
+      {
+        template = ConfigurationFile;
+        Reconfiguring = true;
+      }
+      else
+      {
+        template = templateName;
+        output.Clear();
+        IsValid = ParseConfigurationFile(template);
+      }
+    }
+
+    public void ProcessTemplate()
+    {
+      fe.AssignFormulaVariable("basedir", String.Format("\"{0}\"", BaseDir));
+      fe.AssignFormulaVariable("datadir", String.Format("\"{0}data\\\"", DataDir));
+      fe.AssignFormulaVariable("port", Port);
+      fe.AssignFormulaVariable("default_storage_engine", DefaultStorageEngine);
+      fe.AssignFormulaVariable("default_character_set", DefaultCharacterSet);
+      fe.AssignFormulaVariable("myisam_percentage", MyisamUsage.ToString());
+      fe.AssignFormulaVariable("innodb_buffer_pool_size_percentage", InnoDBBPSUsage.ToString());
+      fe.AssignFormulaVariable("active_connections", NumberConnections.ToString());
+      fe.AssignFormulaVariable("query_cache_pct", UseQueryCache.ToString());
+
+      StreamWriter writer = new StreamWriter(ConfigurationFile);
+
+      foreach (object obj in output)
+      {
+        if (obj is IniTemplateVariable)
+        {
+          IniTemplateVariable itv = obj as IniTemplateVariable;
+          fe.Parse(itv.Formula);
+          string result = fe.Evaluate();
+
+          //writer.WriteLine(itv.LineAsRead);
+          switch (itv.VariableName)
+          {
+            case "STATE_CHANGE":
+              // continue;
+              break;
+
+            case "CLIENT_PORT":
+            case "SERVER_PORT":
+              itv.Disabled = !this.EnableNetworking;
+              break;
+
+            case "CLIENT_PIPE":
+            case "CLIENT_SOCKET":
+            case "SERVER_PIPE":
+            case "SERVER_SOCKET":
+            case "SERVER_SKIP":
+              itv.Disabled = this.EnableNetworking;
+              break;
+
+            case "SQL_MODE":
+              itv.Disabled = true;
+              break;
+
+            case "INNODB_HOME":
+              if (InnoDBHomeDir != "")
+              {
+                itv.Disabled = false;
+                fe.AssignFormulaVariable("innodb_home", InnoDBHomeDir);
+              }
+              else
+                itv.Disabled = true;
+
+              break;
+
+            case "INNODB_LOG_FILE_SIZE":
+              if (itv.DefaultValue != "")
+              {
+                result = itv.DefaultValue;
+                itv.ReduceResult = false;
+              }
+              break;
+
+            case "SKIP_INNODB":
+              itv.Disabled = SkipInnodb;
+              break;
+          }
+          if (itv.VariableName != "STATE_CHANGE")
+          {
+            string assignment = "";
+            if (result.Length > 0)
+              assignment = "=" + (itv.ReduceResult ? ReduceBytesToString(double.Parse(result)) : result);
+            writer.WriteLine((itv.Disabled ? "# " : "") + itv.OutputParameter + assignment);
+          }
+        }
+        else
+        {
+          IniTemplateStatic its = (IniTemplateStatic)obj;
+          writer.WriteLine(its.LineAsRead);
+        }
+      }
+
+      writer.Close();
+      writer.Dispose();
+    }
+
+    public IniServerType ServerType
+    {
+      get
+      {
+        return ist;
+      }
+      set
+      {
+        ist = value;
+
+        PerformanceCounter pc = new PerformanceCounter("Memory", "Available Bytes", "");
+        double system_available_memory = (double)pc.NextValue();
+        double mysql_memory_percentage = 0.08333; // By default, all servers should use 1/12 available system memory.
+
+        fe.AssignFormulaVariable("cpus", Environment.ProcessorCount.ToString());
+
+        switch (ist)
+        {
+          case IniServerType.Dedicated:
+            mysql_memory_percentage = 0.90;
+            fe.AssignFormulaVariable("server_type", "1");
+            break;
+          case IniServerType.Server:
+            mysql_memory_percentage = 0.50;
+            fe.AssignFormulaVariable("server_type", "2");
+            break;
+          case IniServerType.InternalUnitTest:
+            mysql_memory_percentage = 0;
+            system_available_memory = 0.0;
+            fe.AssignFormulaVariable("cpus", "0.0");
+            fe.AssignFormulaVariable("server_type", "4");
+            break;
+
+          default: // IniServerType.Developer
+            fe.AssignFormulaVariable("server_type", "3");
+            if (system_available_memory < (48 * 1024 * 1024))
+            {
+              system_available_memory = 48 * 1024 * 1024;
+              mysql_memory_percentage = 1.0;
+            }
+            break;
+        }
+
+        fe.AssignFormulaVariable("memory", (system_available_memory * mysql_memory_percentage).ToString());
+      }
+    }
+
+    public double MyisamUsage { get; set; }
+
+    public double InnoDBBPSUsage { get; set; }
+
+    public double NumberConnections { get; set; }
+
+    public double UseQueryCache { get; set; }
+
+    public bool FoundExistingDataDir { get; set; }
+
+    public bool IsValid { get; private set; }
+
+    public bool Reconfiguring { get; private set; }
+
+    public bool OutputExists { get; private set; }
+
+    public bool EnableStrictMode { get; set; }
+
+    public bool EnableNetworking { get; set; }
+
+    public bool SkipInnodb { get; set; }
+
+    public string DefaultStorageEngine { get; set; }
+
+    public string DefaultCharacterSet { get; set; }
+
+    public string BaseDir { get; set; }
+
+    public string DataDir { get; set; }
+
+    public string InnoDBHomeDir { get; set; }
+
+    public string Port { get; set; }
+
+    public string ConfigurationFile { get; set; }
+
+    #endregion
+  }
+
+  public enum FormulaTokenType
+  {
+    None,
+    Number,
+    Constant,
+    Variable,
+    Assignment,
+    Plus,
+    Minus,
+    Multiply,
+    Divide,
+    Exponent,
+    UnaryMinus,
+    Sine,
+    Cosine,
+    Tangent,
+    Round,
+    Min,
+    Max,
+    LeftParenthesis,
+    RightParenthesis
+  }
+
+  public struct FormulaToken
+  {
+    public string TokenValue;
+    public FormulaTokenType TokenValueType;
+  }
+
+  public class FormulaEngine
+  {
+    private Dictionary<string, string> formula_variables;
+    private Queue output;
+    private Stack ops;
+    private string original_expression;
+    private string transition_expression;
+    private string postfix_expression;
+
+    public string OriginalExpression
+    {
+      get { return original_expression; }
+    }
+
+    public string TransitionExpression
+    {
+      get { return transition_expression; }
+    }
+
+    public string PostfixExpression
+    {
+      get { return postfix_expression; }
+    }
+
+    public FormulaEngine()
+    {
+      original_expression = string.Empty;
+      transition_expression = string.Empty;
+      postfix_expression = string.Empty;
+      formula_variables = new Dictionary<string, string>();
+    }
+
+    public void Parse(string Expression)
+    {
+      output = new Queue();
+      ops = new Stack();
+
+      original_expression = Expression;
+
+      string rpn_buffer = Expression;
+
+      // filter out the K, M, G unit specifiers.
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)K", " ${number} * 1024 ");
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)M", " ${number} * 1024 * 1024");
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)G", " ${number} * 1024 * 1024 * 1024");
+      rpn_buffer = rpn_buffer.ToLower();
+
+      // captures numbers. Anything like 11 or 22.34 is captured
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>\d+(\.\d+)?)", " ${number} ");
+      // captures these symbols: + - * / ^ ( )
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<ops>[+\-*/^:()])", " ${ops} ");
+      // captures constants, variables, and math functions.
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<var>([a-z_]+))", " ${var} ");
+      // trims up consecutive spaces and replace it with just one space
+      rpn_buffer = Regex.Replace(rpn_buffer, @"\s+", " ").Trim();
+
+      // The following chunk captures unary minus operations.
+      // 1) We replace every minus sign with the string "MINUS".
+      // 2) Then if we find a "MINUS" with a number or constant in front,
+      //    then it's a normal minus operation.
+      // 3) Otherwise, it's a unary minus operation.
+
+      // Step 1.
+      rpn_buffer = Regex.Replace(rpn_buffer, "-", "MINUS");
+      // Step 2. Looking for pi or e or generic number \d+(\.\d+)?
+      //rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>(pi|e|(\d+(\.\d+)?)))\s+MINUS", "${number} -");
+      rpn_buffer = Regex.Replace(rpn_buffer, @"(?<number>([a-z_]+|[)]|(\d+(\.\d+)?)))\s+MINUS", "${number} -");
+      // Step 3. Use the tilde ~ as the unary minus operator
+      rpn_buffer = Regex.Replace(rpn_buffer, "MINUS", "~");
+
+      transition_expression = rpn_buffer;
+
+      // tokenize it!
+      string[] parsed_tokens = rpn_buffer.Split(" ".ToCharArray());
+      int i = 0;
+      double token_value;
+      FormulaToken token, opstoken;
+      for (i = 0; i < parsed_tokens.Length; ++i)
+      {
+        token = new FormulaToken();
+        token.TokenValue = parsed_tokens[i];
+        token.TokenValueType = FormulaTokenType.None;
+
+        try
+        {
+          token_value = double.Parse(parsed_tokens[i]);
+          token.TokenValueType = FormulaTokenType.Number;
+          // If the token is a number, then add it to the output queue.
+          output.Enqueue(token);
+        }
+        catch
+        {
+          switch (parsed_tokens[i])
+          {
+            case "+":
+              token.TokenValueType = FormulaTokenType.Plus;
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+
+                // while there is an operator, o2, at the top of the stack
+                while (IsOperatorToken(opstoken.TokenValueType))
+                {
+                  // pop o2 off the stack, onto the output queue;
+                  output.Enqueue(ops.Pop());
+                  if (ops.Count > 0)
+                    opstoken = (FormulaToken)ops.Peek();
+                  else
+                    break;
+                }
+              }
+              // push o1 onto the operator stack.
+              ops.Push(token);
+              break;
+
+            case "-":
+              token.TokenValueType = FormulaTokenType.Minus;
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+
+                // while there is an operator, o2, at the top of the stack
+                while (IsOperatorToken(opstoken.TokenValueType))
+                {
+                  // pop o2 off the stack, onto the output queue;
+                  output.Enqueue(ops.Pop());
+                  if (ops.Count > 0)
+                    opstoken = (FormulaToken)ops.Peek();
+                  else
+                    break;
+                }
+              }
+              // push o1 onto the operator stack.
+              ops.Push(token);
+              break;
+
+            case "*":
+              token.TokenValueType = FormulaTokenType.Multiply;
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+
+                // while there is an operator, o2, at the top of the stack
+                while (IsOperatorToken(opstoken.TokenValueType))
+                {
+                  if (opstoken.TokenValueType == FormulaTokenType.Plus || opstoken.TokenValueType == FormulaTokenType.Minus || opstoken.TokenValueType == FormulaTokenType.Assignment)
+                    break;
+                  else
+                  {
+                    // Once we're in here, the following algorithm condition is satisfied.
+                    // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
+                    // o1 is right-associative and its precedence is less than (lower precedence) that of o2,
+
+                    // pop o2 off the stack, onto the output queue;
+                    output.Enqueue(ops.Pop());
+                    if (ops.Count > 0)
+                      opstoken = (FormulaToken)ops.Peek();
+                    else
+                      break;
+                  }
+                }
+              }
+              // push o1 onto the operator stack.
+              ops.Push(token);
+              break;
+
+            case "/":
+              token.TokenValueType = FormulaTokenType.Divide;
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+
+                // while there is an operator, o2, at the top of the stack
+                while (IsOperatorToken(opstoken.TokenValueType))
+                {
+                  if (opstoken.TokenValueType == FormulaTokenType.Plus || opstoken.TokenValueType == FormulaTokenType.Minus || opstoken.TokenValueType == FormulaTokenType.Assignment)
+                    break;
+                  else
+                  {
+                    // Once we're in here, the following algorithm condition is satisfied.
+                    // o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
+                    // o1 is right-associative and its precedence is less than (lower precedence) that of o2,
+
+                    // pop o2 off the stack, onto the output queue;
+                    output.Enqueue(ops.Pop());
+                    if (ops.Count > 0)
+                      opstoken = (FormulaToken)ops.Peek();
+                    else
+                      break;
+                  }
+                }
+              }
+              // push o1 onto the operator stack.
+              ops.Push(token);
+              break;
+              
+            case "^":
+              token.TokenValueType = FormulaTokenType.Exponent;
+              // push o1 onto the operator stack.
+              ops.Push(token);
+              break;
+
+            case "~":
+              token.TokenValueType = FormulaTokenType.UnaryMinus;
+              // push o1 onto the operator stack.
+              ops.Push(token);
+              break;
+
+            case "(":
+              token.TokenValueType = FormulaTokenType.LeftParenthesis;
+              
+              // If the token is a left parenthesis, then push it onto the stack.
+              ops.Push(token);
+              break;
+            
+            case ")":
+              token.TokenValueType = FormulaTokenType.RightParenthesis;
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+                // Until the token at the top of the stack is a left parenthesis
+                while (opstoken.TokenValueType != FormulaTokenType.LeftParenthesis)
+                {
+                  // pop operators off the stack onto the output queue
+                  output.Enqueue(ops.Pop());
+                  if (ops.Count > 0)
+                    opstoken = (FormulaToken)ops.Peek();
+                  else
+                  {
+                    // If the stack runs out without finding a left parenthesis,
+                    // then there are mismatched parentheses.
+                    throw new Exception("Unbalanced parenthesis!");
+                  }
                                     
-                                }
-                                // Pop the left parenthesis from the stack, but not onto the output queue.
-                                ops.Pop();
-                            }
-
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // If the token at the top of the stack is a function token
-                                if (IsFunctionToken(opstoken.TokenValueType))
-                                {
-                                    // pop it and onto the output queue.
-                                    output.Enqueue(ops.Pop());
-                                }
-                            }
-                            break;
-                        case "pi":
-                            token.TokenValueType = FormulaTokenType.Constant;
-                            // If the token is a number, then add it to the output queue.
-                            output.Enqueue(token);
-                            break;
-                        case "e":
-                            token.TokenValueType = FormulaTokenType.Constant;
-                            // If the token is a number, then add it to the output queue.
-                            output.Enqueue(token);
-                            break;
-                        case "sin":
-                            token.TokenValueType = FormulaTokenType.Sine;
-                            // If the token is a function token, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case "cos":
-                            token.TokenValueType = FormulaTokenType.Cosine;
-                            // If the token is a function token, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case "tan":
-                            token.TokenValueType = FormulaTokenType.Tangent;
-                            // If the token is a function token, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case "rnd":
-                            token.TokenValueType = FormulaTokenType.Round;
-                            // If the token is a funciton token, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case "max":
-                            token.TokenValueType = FormulaTokenType.Max;
-                            // If the token is a funciton token, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case "min":
-                            token.TokenValueType = FormulaTokenType.Min;
-                            // If the token is a funciton token, then push it onto the stack.
-                            ops.Push(token);
-                            break;
-                        case ":":
-                            // If the token is an assignment token, then push it onto the stack.
-                            token.TokenValueType = FormulaTokenType.Assignment;
-                            // push o0 onto the operator stack.
-                            ops.Push(token);
-                            break;
-                        case ",":
-                            if (ops.Count > 0)
-                            {
-                                opstoken = (FormulaToken)ops.Peek();
-                                // Until the token at the top of the stack is a left parenthesis
-                                while (opstoken.TokenValueType != FormulaTokenType.LeftParenthesis)
-                                {
-                                    // pop operators off the stack onto the output queue
-                                    output.Enqueue(ops.Pop());
-                                    if (ops.Count > 0)
-                                    {
-                                        opstoken = (FormulaToken)ops.Peek();
-                                    }
-                                    else
-                                    {
-                                        // If the stack runs out without finding a left parenthesis,
-                                        // then there are mismatched parentheses.
-                                        throw new Exception("Couldn't find function start!");
-                                    }
-                                }
-                            }
-                            break;
-                        default:
-                            if (Regex.IsMatch(parsed_tokens[i], @"[a-z_]+"))
-                            {
-                                token.TokenValueType = FormulaTokenType.Variable;
-                                output.Enqueue(token); // This is a variable.
-                            }
-                            break;
-                    }
-                }
-            }
-
-            // While there are still operator tokens in the stack:
-            while (ops.Count != 0)
-            {
-                opstoken = (FormulaToken)ops.Pop();
-                // If the operator token on the top of the stack is a parenthesis
-                if (opstoken.TokenValueType == FormulaTokenType.LeftParenthesis)
-                {
-                    // then there are mismatched parenthesis.
-                    throw new Exception("Unbalanced parenthesis!");
-                }
-                else
-                {
-                    // Pop the operator onto the output queue.
-                    output.Enqueue(opstoken);
-                }
-            }
-
-            postfix_expression = string.Empty;
-            foreach (object obj in output)
-            {
-                opstoken = (FormulaToken)obj;
-                postfix_expression += string.Format("{0} ", opstoken.TokenValue);
-            }
-        }
-
-        public string Evaluate()
-        {
-            Stack result = new Stack();
-
-            FormulaToken token = new FormulaToken();
-            FormulaToken operand1 = new FormulaToken();
-            FormulaToken operand2 = new FormulaToken();
-            FormulaToken result_token = new FormulaToken();
-            
-            // While there are input tokens left
-            foreach (object obj in output)
-            {
-                // Read the next token from input.
-                token = (FormulaToken)obj;
-                switch (token.TokenValueType)
-                {
-                    case FormulaTokenType.Number:
-                    case FormulaTokenType.Constant:
-                    case FormulaTokenType.Variable:
-                        result.Push(token);
-                        break;
-                    case FormulaTokenType.Assignment:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-                            if ( operand1.TokenValueType == FormulaTokenType.Variable && 
-                                (operand2.TokenValueType == FormulaTokenType.Number ||
-                                 operand2.TokenValueType == FormulaTokenType.Constant ||
-                                 operand2.TokenValueType == FormulaTokenType.Variable)
-                               )
-                                formula_variables[operand1.TokenValue] = GetTokenValue(operand2).ToString();
-                            else
-                                throw new Exception("Assignment error!");
-
-                            result.Push(operand1);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Plus:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = (GetTokenValue(operand2) + GetTokenValue(operand1)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Minus:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = (GetTokenValue(operand1) - GetTokenValue(operand2)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Multiply:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = (GetTokenValue(operand2) * GetTokenValue(operand1)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Divide:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = (GetTokenValue(operand1) / GetTokenValue(operand2)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Exponent:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = Math.Pow(GetTokenValue(operand1), GetTokenValue(operand2)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.UnaryMinus:
-                        if (result.Count >= 1)
-                        {
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = (-GetTokenValue(operand1)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Sine:
-                        if (result.Count >= 1)
-                        {
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = Math.Sin(GetTokenValue(operand1)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Cosine:
-                        if (result.Count >= 1)
-                        {
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = Math.Cos(GetTokenValue(operand1)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Tangent:
-                        if (result.Count >= 1)
-                        {
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = Math.Tan(GetTokenValue(operand1)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Round:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            result_token.TokenValueType = FormulaTokenType.Number;
-                            result_token.TokenValue = Math.Round((GetTokenValue(operand1) / GetTokenValue(operand2)) * GetTokenValue(operand2)).ToString();
-
-                            result.Push(result_token);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Max:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            if (GetTokenValue(operand1) >= GetTokenValue(operand2))
-                                result.Push(operand1);
-                            else
-                                result.Push(operand2);
-
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                    case FormulaTokenType.Min:
-                        if (result.Count >= 2)
-                        {
-                            operand2 = (FormulaToken)result.Pop();
-                            operand1 = (FormulaToken)result.Pop();
-
-                            if (GetTokenValue(operand1) <= GetTokenValue(operand2))
-                                result.Push(operand1);
-                            else
-                                result.Push(operand2);
-                        }
-                        else
-                            throw new Exception("Evaluation error!");
-                        break;
-                }
-            }
-
-            // If there is only one value in the stack
-            if (result.Count == 1)
-            {
-                // That value is the result of the calculation.
-                return GetTokenText((FormulaToken)result.Pop());
-            }
-            else
-            {
-                // If there are more values in the stack
-                // (Error) The user input too many values.
-                throw new Exception("Evaluation error!");
-            }
-        }
-
-        public void AssignFormulaVariable(string key_name, string value)
-        {
-            string variable_value;
-            formula_variables.TryGetValue(key_name, out variable_value);
-            if(variable_value != value)
-                formula_variables[key_name] = value;
-            return;
-        }
-
-        private string GetTokenText(FormulaToken token)
-        {
-            string token_value = String.Empty;
-
-            switch (token.TokenValueType)
-            {
-                case FormulaTokenType.Number:
-                    token_value = token.TokenValue;
-                    break;
-                case FormulaTokenType.Variable:
-                    if (!formula_variables.TryGetValue(token.TokenValue, out token_value))
-                        token_value = "0.0";
-                    break;
-                case FormulaTokenType.Constant:
-                    switch (token.TokenValue)
-                    {
-                        case "pi":
-                            token_value = Math.PI.ToString();
-                            break;
-                        case "e":
-                            token_value = Math.E.ToString();
-                            break;
-                    }
-                    break;
-            }
-
-            return token_value;
-        }
-
-        private double GetTokenValue(FormulaToken token)
-        {
-            return double.Parse(GetTokenText(token));
-        }
-
-        private bool IsOperatorToken(FormulaTokenType t)
-        {
-            bool result = false;
-            switch (t)
-            {
-                case FormulaTokenType.Plus:
-                case FormulaTokenType.Minus:
-                case FormulaTokenType.Multiply:
-                case FormulaTokenType.Divide:
-                case FormulaTokenType.Exponent:
-                case FormulaTokenType.UnaryMinus:
-                    result = true;
-                    break;
-                default:
-                    result = false;
-                    break;
-            }
-            return result;
-        }
-
-        private bool IsFunctionToken(FormulaTokenType t)
-        {
-            bool result = false;
-            switch (t)
-            {
-                case FormulaTokenType.Sine:
-                case FormulaTokenType.Cosine:
-                case FormulaTokenType.Tangent:
-                case FormulaTokenType.Round:
-                case FormulaTokenType.Max:
-                case FormulaTokenType.Min:
-                    result = true;
-                    break;
-                default:
-                    result = false;
-                    break;
-            }
-            return result;
-        }
-
-    }
+                }
+                // Pop the left parenthesis from the stack, but not onto the output queue.
+                ops.Pop();
+              }
+
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+                // If the token at the top of the stack is a function token
+                if (IsFunctionToken(opstoken.TokenValueType))
+                {
+                  // pop it and onto the output queue.
+                  output.Enqueue(ops.Pop());
+                }
+              }
+              break;
+              
+            case "pi":
+              token.TokenValueType = FormulaTokenType.Constant;
+              // If the token is a number, then add it to the output queue.
+              output.Enqueue(token);
+              break;
+
+            case "e":
+              token.TokenValueType = FormulaTokenType.Constant;
+              // If the token is a number, then add it to the output queue.
+              output.Enqueue(token);
+              break;
+
+            case "sin":
+              token.TokenValueType = FormulaTokenType.Sine;
+              // If the token is a function token, then push it onto the stack.
+              ops.Push(token);
+              break;
+
+            case "cos":
+              token.TokenValueType = FormulaTokenType.Cosine;
+              // If the token is a function token, then push it onto the stack.
+              ops.Push(token);
+              break;
+
+            case "tan":
+              token.TokenValueType = FormulaTokenType.Tangent;
+              // If the token is a function token, then push it onto the stack.
+              ops.Push(token);
+              break;
+
+            case "rnd":
+              token.TokenValueType = FormulaTokenType.Round;
+              // If the token is a function token, then push it onto the stack.
+              ops.Push(token);
+              break;
+
+            case "max":
+              token.TokenValueType = FormulaTokenType.Max;
+              // If the token is a function token, then push it onto the stack.
+              ops.Push(token);
+              break;
+
+            case "min":
+              token.TokenValueType = FormulaTokenType.Min;
+              // If the token is a function token, then push it onto the stack.
+              ops.Push(token);
+              break;
+
+            case ":":
+              // If the token is an assignment token, then push it onto the stack.
+              token.TokenValueType = FormulaTokenType.Assignment;
+              // push o0 onto the operator stack.
+              ops.Push(token);
+              break;
+
+            case ",":
+              if (ops.Count > 0)
+              {
+                opstoken = (FormulaToken)ops.Peek();
+                // Until the token at the top of the stack is a left parenthesis
+                while (opstoken.TokenValueType != FormulaTokenType.LeftParenthesis)
+                {
+                  // pop operators off the stack onto the output queue
+                  output.Enqueue(ops.Pop());
+                  if (ops.Count > 0)
+                    opstoken = (FormulaToken)ops.Peek();
+                  else
+                  {
+                    // If the stack runs out without finding a left parenthesis,
+                    // then there are mismatched parentheses.
+                    throw new Exception("Couldn't find function start!");
+                  }
+                }
+              }
+              break;
+
+            default:
+              if (Regex.IsMatch(parsed_tokens[i], @"[a-z_]+"))
+              {
+                token.TokenValueType = FormulaTokenType.Variable;
+                output.Enqueue(token); // This is a variable.
+              }
+              break;
+          }
+        }
+      }
+
+      // While there are still operator tokens in the stack:
+      while (ops.Count != 0)
+      {
+        opstoken = (FormulaToken)ops.Pop();
+        // If the operator token on the top of the stack is a parenthesis
+        if (opstoken.TokenValueType == FormulaTokenType.LeftParenthesis)
+        {
+          // then there are mismatched parenthesis.
+          throw new Exception("Unbalanced parenthesis!");
+        }
+        else
+        {
+          // Pop the operator onto the output queue.
+          output.Enqueue(opstoken);
+        }
+      }
+
+      postfix_expression = string.Empty;
+      foreach (object obj in output)
+      {
+        opstoken = (FormulaToken)obj;
+        postfix_expression += string.Format("{0} ", opstoken.TokenValue);
+      }
+    }
+
+    public string Evaluate()
+    {
+      Stack result = new Stack();
+
+      FormulaToken token = new FormulaToken();
+      FormulaToken operand1 = new FormulaToken();
+      FormulaToken operand2 = new FormulaToken();
+      FormulaToken result_token = new FormulaToken();
+            
+      // While there are input tokens left
+      foreach (object obj in output)
+      {
+        // Read the next token from input.
+        token = (FormulaToken)obj;
+        switch (token.TokenValueType)
+        {
+          case FormulaTokenType.Number:
+          case FormulaTokenType.Constant:
+          case FormulaTokenType.Variable:
+            result.Push(token);
+            break;
+
+          case FormulaTokenType.Assignment:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+              if ( operand1.TokenValueType == FormulaTokenType.Variable && 
+                (operand2.TokenValueType == FormulaTokenType.Number ||
+                  operand2.TokenValueType == FormulaTokenType.Constant ||
+                  operand2.TokenValueType == FormulaTokenType.Variable)
+                )
+                formula_variables[operand1.TokenValue] = GetTokenValue(operand2).ToString();
+              else
+                throw new Exception("Assignment error!");
+
+              result.Push(operand1);
+            }
+            else
+              throw new Exception("Evaluation error!");
+              
+            break;
+            
+          case FormulaTokenType.Plus:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = (GetTokenValue(operand2) + GetTokenValue(operand1)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Minus:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = (GetTokenValue(operand1) - GetTokenValue(operand2)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Multiply:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = (GetTokenValue(operand2) * GetTokenValue(operand1)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Divide:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = (GetTokenValue(operand1) / GetTokenValue(operand2)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Exponent:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = Math.Pow(GetTokenValue(operand1), GetTokenValue(operand2)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.UnaryMinus:
+            if (result.Count >= 1)
+            {
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = (-GetTokenValue(operand1)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Sine:
+            if (result.Count >= 1)
+            {
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = Math.Sin(GetTokenValue(operand1)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Cosine:
+            if (result.Count >= 1)
+            {
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = Math.Cos(GetTokenValue(operand1)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Tangent:
+            if (result.Count >= 1)
+            {
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = Math.Tan(GetTokenValue(operand1)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Round:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              result_token.TokenValueType = FormulaTokenType.Number;
+              result_token.TokenValue = Math.Round((GetTokenValue(operand1) / GetTokenValue(operand2)) * GetTokenValue(operand2)).ToString();
+
+              result.Push(result_token);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Max:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              if (GetTokenValue(operand1) >= GetTokenValue(operand2))
+                result.Push(operand1);
+              else
+                result.Push(operand2);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+
+          case FormulaTokenType.Min:
+            if (result.Count >= 2)
+            {
+              operand2 = (FormulaToken)result.Pop();
+              operand1 = (FormulaToken)result.Pop();
+
+              if (GetTokenValue(operand1) <= GetTokenValue(operand2))
+                result.Push(operand1);
+              else
+                result.Push(operand2);
+            }
+            else
+              throw new Exception("Evaluation error!");
+
+            break;
+        }
+      }
+
+      // No value on the stack means there is no value associated with a parameter.
+      if (result.Count == 0)
+        return "";
+
+      // If there is only one value in the stack...
+      if (result.Count == 1)
+      {
+        // ... that value is the result of the calculation.
+        return GetTokenText((FormulaToken)result.Pop());
+      }
+      else
+      {
+        // If there are more values in the stack
+        // (Error) The user input too many values.
+        throw new Exception("Evaluation error. Invalid number of arguments.");
+      }
+    }
+
+    public void AssignFormulaVariable(string key_name, string value)
+    {
+      string variable_value;
+      formula_variables.TryGetValue(key_name, out variable_value);
+      if(variable_value != value)
+        formula_variables[key_name] = value;
+      return;
+    }
+
+    private string GetTokenText(FormulaToken token)
+    {
+      string result = String.Empty;
+
+      switch (token.TokenValueType)
+      {
+        case FormulaTokenType.Number:
+          result = token.TokenValue;
+          break;
+
+        case FormulaTokenType.Variable:
+          if (!formula_variables.TryGetValue(token.TokenValue, out result))
+              result = "0.0";
+          break;
+
+        case FormulaTokenType.Constant:
+          switch (token.TokenValue)
+          {
+            case "pi":
+              result = Math.PI.ToString();
+              break;
+
+            case "e":
+              result = Math.E.ToString();
+              break;
+          }
+          break;
+      }
+
+      return result;
+    }
+
+    private double GetTokenValue(FormulaToken token)
+    {
+      return double.Parse(GetTokenText(token));
+    }
+
+    private bool IsOperatorToken(FormulaTokenType t)
+    {
+      bool result = false;
+      switch (t)
+      {
+        case FormulaTokenType.Plus:
+        case FormulaTokenType.Minus:
+        case FormulaTokenType.Multiply:
+        case FormulaTokenType.Divide:
+        case FormulaTokenType.Exponent:
+        case FormulaTokenType.UnaryMinus:
+          result = true;
+          break;
+
+        default:
+          result = false;
+          break;
+      }
+      return result;
+    }
+
+    private bool IsFunctionToken(FormulaTokenType t)
+    {
+      bool result = false;
+      switch (t)
+      {
+        case FormulaTokenType.Sine:
+        case FormulaTokenType.Cosine:
+        case FormulaTokenType.Tangent:
+        case FormulaTokenType.Round:
+        case FormulaTokenType.Max:
+        case FormulaTokenType.Min:
+          result = true;
+          break;
+
+        default:
+          result = false;
+          break;
+      }
+      return result;
+    }
+
+  }
 }

=== modified file 'StandardPlugins/Server/MysqlSCM.cs'
--- a/StandardPlugins/Server/MysqlSCM.cs	2011-03-30 13:40:12 +0000
+++ b/StandardPlugins/Server/MysqlSCM.cs	2011-05-03 14:12:50 +0000
@@ -79,6 +79,7 @@
       catch (Exception e)
       {
         Logger.LogException(e);
+        throw; // Rethrow the exception so the caller can handle this error case properly.
       }
     }
 
@@ -92,6 +93,7 @@
       catch (Exception e)
       {
         Logger.LogException(e);
+        throw;
       }
     }
 
@@ -107,7 +109,7 @@
       catch (Exception e)
       {
         Logger.LogException(e);
-        throw; // Rethrow the exception so the caller can handle this error case properly.
+        throw;
       }
     }
 
@@ -123,6 +125,7 @@
       catch (Exception e)
       {
         Logger.LogException(e);
+        throw;
       }
     }
 
@@ -141,6 +144,7 @@
       catch (Exception e)
       {
         Logger.LogException(e);
+        throw;
       }
     }
 
@@ -158,6 +162,7 @@
       catch (Exception e)
       {
         Logger.LogException(e);
+        throw;
       }
     }
 

=== modified file 'StandardPlugins/Server/ServerConfigPanel2.cs'
--- a/StandardPlugins/Server/ServerConfigPanel2.cs	2011-04-18 08:06:38 +0000
+++ b/StandardPlugins/Server/ServerConfigPanel2.cs	2011-05-03 14:12:50 +0000
@@ -61,24 +61,31 @@
     public override void Activate()
     {
       bool doingUpdate = (Controller.Owner.CurrentState == ProductState.UpdateSuccess);
-      if (Controller.Template != null && doingUpdate)
+      if (Controller.Template != null && (doingUpdate || Controller.Template.Reconfiguring))
       {
         Logger.LogInformation("Preparing update configuration.");
         enableTCPIP.Checked = Controller.Template.EnableNetworking;
         enableTCPIP_CheckedChanged(null, null);
-        if (enableTCPIP.Checked)
-          portNumberEdit.Text = Controller.Template.Port;
+        portNumberEdit.Text = Controller.Template.Port;
+        currentPort = Int32.Parse(Controller.Template.Port);
 
         if (!String.IsNullOrEmpty(Controller.ServiceName))
         {
           originalServiceName = Controller.ServiceName;
-
           serviceNameEdit.Text = Controller.ServiceName;
-          serviceNameEdit.Enabled = false;
-          serviceErrorSign.Visible = false;
-          createService.Checked = true;
-          createService.Enabled = false;
+
+          // If we are reconfiguring/updating and the service name is already used
+          // then the service already exists. Don't allow changing it now.
+          if (!ServiceNameAvailable(originalServiceName))
+          {
+            serviceNameEdit.Enabled = false;
+            serviceErrorSign.Visible = false;
+            createService.Checked = true;
+            createService.Enabled = false;
+          }
         }
+        else
+          SetDefaultServiceName();
       }
       else
       {

=== modified file 'StandardPlugins/StandardPlugins.csproj'
--- a/StandardPlugins/StandardPlugins.csproj	2011-04-07 18:04:48 +0000
+++ b/StandardPlugins/StandardPlugins.csproj	2011-05-03 14:12:50 +0000
@@ -74,6 +74,7 @@
     <EmbeddedResource Include="Properties\Resources.resx">
       <Generator>ResXFileCodeGenerator</Generator>
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
     </EmbeddedResource>
     <EmbeddedResource Include="Server\ServerConfigPanel1.resx">
       <DependentUpon>ServerConfigPanel1.cs</DependentUpon>

=== modified file 'WexInstaller.Core/LoggerListener.cs'
--- a/WexInstaller.Core/LoggerListener.cs	2011-05-02 12:40:37 +0000
+++ b/WexInstaller.Core/LoggerListener.cs	2011-05-03 14:12:50 +0000
@@ -41,7 +41,7 @@
       // (e.g. via Switch User or via terminal services).
       string logFile = String.Format("{0}\\{1} installer.log", logPath, Environment.UserName);
       if (File.Exists(logFile))
-        BackupLogFile(logPath, logFile);
+        BackupLogFile(logFile);
       textFile = new TextWriterTraceListener(logFile);
       foreach (string msg in buffer)
         textFile.Write(msg);
@@ -54,7 +54,7 @@
     /// oldest log file if the upper limit of files is reached.
     /// The maximum number of files can be configured via the config file, but not more than 100.
     /// </summary>
-    private void BackupLogFile(string logPath, string logFile)
+    private void BackupLogFile(string logFile)
     {
       int maxCount = Math.Min(InstallerConfiguration.MaxLogCount, 100);
       if (maxCount < 2)

=== modified file 'common/config.xml'
--- a/common/config.xml	2011-04-28 19:51:03 +0000
+++ b/common/config.xml	2011-05-03 14:12:50 +0000
@@ -5,15 +5,17 @@
       <URL>http://wb.mysql.com/installer/products.xml</URL>
     </UpdateURL>
   </UpdateURLs>
-  <UpdateTimeoutMilliseconds>7000</UpdateTimeoutMilliseconds>
+  <UpdateTimeoutMilliseconds>10000</UpdateTimeoutMilliseconds>
   <UpdateCheckFrequency>7</UpdateCheckFrequency>
   <ProductCachePath>C:\ProgramData\MySQL\MySQL Installer\Product Cache\</ProductCachePath>
-  <InstallationRoot>C:\Program Files\MySQL\</InstallationRoot>
+  <InstallationRoot></InstallationRoot>
   <LicenseAgreement>1</LicenseAgreement>
+  <SendSystemInfo>1</SendSystemInfo>
   <Location>
-    <X>246</X>
-    <Y>84</Y>
+    <X>605</X>
+    <Y>240</Y>
   </Location>
   <ProductCode></ProductCode>
-  <CurrentUserDPI>0</CurrentUserDPI>
+  <ActiveCatalog></ActiveCatalog>
+  <MaxLogCount>100</MaxLogCount>
 </Configuration>
\ No newline at end of file


Attachment: [text/bzr-bundle] bzr/mike.lischke@oracle.com-20110503141250-mcs0kpolainjyizq.bundle
Thread
bzr commit into wex-installer-1.0 branch (mike.lischke:456) Mike Lischke3 May