From 373eb7051410d0d7a1bcdbc93e9cc34f2951333d Mon Sep 17 00:00:00 2001
From: Scott Gasch <scott.gasch@gmail.com>
Date: Wed, 1 Jun 2016 19:42:52 -0700
Subject: [PATCH 1/1] Initial checkin of typhoon UI project.

---
 App.ico               | Bin 0 -> 1078 bytes
 AssemblyInfo.cs       |  58 +++++
 Form1.cs              | 542 ++++++++++++++++++++++++++++++++++++++++++
 Form1.resx            | 108 +++++++++
 typhoonUI.csproj      | 112 +++++++++
 typhoonUI.csproj.user |  48 ++++
 typhoonUI.sln         |  21 ++
 7 files changed, 889 insertions(+)
 create mode 100644 App.ico
 create mode 100644 AssemblyInfo.cs
 create mode 100644 Form1.cs
 create mode 100644 Form1.resx
 create mode 100644 typhoonUI.csproj
 create mode 100644 typhoonUI.csproj.user
 create mode 100644 typhoonUI.sln

diff --git a/App.ico b/App.ico
new file mode 100644
index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6
GIT binary patch
literal 1078
zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w
zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1
z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj
zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<cQetc!+$5J+aVZ&1f
Qa92%&%o_p!1^%7_Ps0Y#2><{9

literal 0
HcmV?d00001

diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs
new file mode 100644
index 0000000..177a4f0
--- /dev/null
+++ b/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/Form1.cs b/Form1.cs
new file mode 100644
index 0000000..766ac22
--- /dev/null
+++ b/Form1.cs
@@ -0,0 +1,542 @@
+/**
+ * Copyright (c) Lynn J. Gasch
+ * 7/17/04
+ * Redmond, Washington
+ * 
+ * typhoonUI displays the contents of an xml file in a tree control.
+ * It was developed to support chess programming, but can really be
+ * used for any xml file you wish.
+ * 
+ * Xml nodes that do not have children should be written within
+ * a single tag, as &lt; tag anAttrib="value" /> so that they can 
+ * be displayed on a single line (node) of the tree.
+ * 
+ * Tags starting with "FEN" can be used to lauch chess board
+ * viewers with the board value (they must use the single-line
+ * formatting as described above to trigger this functionality). 
+ * 
+ * This app is pretty special purpose and I'm sure there are plenty
+ * of ways to break it with various inputs. I coded it up in a few
+ * hours and it meets our needs. 
+ */
+
+using System;
+using System.Drawing;
+using System.Collections;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Data;
+using System.Xml;
+using System.IO;
+using System.Diagnostics;
+using System.Text;
+
+namespace typhoonUI
+{
+	// TODO: write tag for eval; Write evals dumps to file
+	// and retrieve the text into a separate text block 
+	// on selection of the node
+	// TODO: command line file launch
+	// TODO: speed up loading
+
+	/// <summary>
+	/// Summary description for Form1.
+	/// </summary>
+	public class Form1 : System.Windows.Forms.Form
+	{
+		#region Private Fields
+
+		/// <summary>
+		/// inserted between tag names and their values for display
+		/// in the tree. For tags that have no children other than their
+		/// values, list them in the xml as 
+		/// &lt; tag attrib="something to display" /> and they will only
+		/// take up one tree node and be listed as 
+		/// tag something to display.
+		/// </summary>
+		private const string VALUE_SEPARATOR = " ";
+
+		/// <summary>
+		/// Use this tag name to identify the board configuration node
+		/// in your xml. This will provide menu item and double-clicking
+		/// to launch the position in a viewer that you can specify.
+		/// </summary>
+		private const string TAG_BOARD = "FEN";
+
+		/// <summary>
+		/// name of a tag for which the first attrib should be added to its parent
+		/// node text. If it's the only child, the node itself will be skipped
+		/// </summary>
+		private const string TAG_SCORE = "score";
+
+		/// <summary>
+		/// Attributes named tip will be set as tool tip text for the node
+		/// </summary>
+		private const string ATTRIB_TIP = "tip";
+
+		/// <summary>
+		/// an attrib name to denote request for boldfacing the text.
+		/// In order for the text to be displayed, it must be the frst attrib.
+		/// </summary>
+		private const string ATTRIB_BOLD = "bold";
+
+		/// <summary>
+		/// Name of a (reusable) file that is written with the board
+		/// position and used as a command arg to the board viewer app.
+		/// </summary>
+		private const string POSITION_FILE_NAME = "boardConfigFile.txt";
+
+		/// <summary>
+		/// Windows designer generated code
+		/// </summary>
+		private System.Windows.Forms.MainMenu mainMenu1;
+		private System.Windows.Forms.MenuItem menuItem1;
+		private System.Windows.Forms.MenuItem menuItem2;
+		private System.Windows.Forms.TreeView _treeView1;
+
+		/// <summary>
+		/// appears when right-clicking on a "board" node. See
+		/// BOARD_TAG_NAME
+		/// </summary>
+		private System.Windows.Forms.ContextMenu _contextMenu;
+
+		/// <summary>
+		/// Path to the viewer app, to be collected from the user.
+		/// TODO: allow the user to enter it into the Path environment 
+		/// variable and just attempt to run it; only request path
+		/// if fail to run.
+		/// </summary>
+		private string _boardViewerAppPath = null;
+
+		/// <summary>
+		/// the view app process, so we can kill it if another board
+		/// is to be viewed
+		/// </summary>
+		private Process _process = null;
+
+		/// <summary>
+		/// local dir for writing the board position file for input 
+		/// into the viewer app.
+		/// </summary>
+		private string _applicationDir;
+
+		/// <summary>
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.Container components = null;
+
+		/// <summary>
+		/// for displaying long or multi-line text
+		/// </summary>
+		private ToolTip _tip;
+
+		private string _tipText;
+
+		#endregion
+
+		#region Construction / Destruction
+
+		/// <summary>
+		/// The main thing
+		/// </summary>
+		public Form1(string startFile)
+		{
+			//
+			// Required for Windows Form Designer support
+			//
+			InitializeComponent();
+
+			// create the context menu that will be used for board nodes
+			_contextMenu = new ContextMenu();
+			MenuItem item = new MenuItem("View board");
+			item.Click += new EventHandler(OnViewBoardMenuClicked);
+			_contextMenu.MenuItems.Add(item);
+
+			_applicationDir = Path.GetDirectoryName(
+				Application.ExecutablePath);
+
+			_tip = new ToolTip();
+			_tipText = string.Empty;
+			_tip.SetToolTip(_treeView1, _tipText);
+
+			if ((startFile != null) && (startFile.Length > 0))
+				Display(startFile);
+		}
+
+		/// <summary>
+		/// Clean up any resources being used.
+		/// </summary>
+		protected override void Dispose( bool disposing )
+		{
+			if( disposing )
+			{
+				KillProcess();
+				if (components != null) 
+				{
+					components.Dispose();
+				}
+			}
+			base.Dispose( disposing );
+		}
+
+		
+		#endregion
+
+		#region Windows Form Designer generated code
+		/// <summary>
+		/// Required method for Designer support - do not modify
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.mainMenu1 = new System.Windows.Forms.MainMenu();
+			this.menuItem1 = new System.Windows.Forms.MenuItem();
+			this.menuItem2 = new System.Windows.Forms.MenuItem();
+			this._treeView1 = new System.Windows.Forms.TreeView();
+			this.SuspendLayout();
+			// 
+			// mainMenu1
+			// 
+			this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+																					  this.menuItem1});
+			// 
+			// menuItem1
+			// 
+			this.menuItem1.Index = 0;
+			this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+																					  this.menuItem2});
+			this.menuItem1.Text = "File";
+			// 
+			// menuItem2
+			// 
+			this.menuItem2.Index = 0;
+			this.menuItem2.Text = "Open";
+			this.menuItem2.Click += new System.EventHandler(this.OnOpenMenuClick);
+			// 
+			// _treeView1
+			// 
+			this._treeView1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+				| System.Windows.Forms.AnchorStyles.Left) 
+				| System.Windows.Forms.AnchorStyles.Right);
+			this._treeView1.HideSelection = false;
+			this._treeView1.ImageIndex = -1;
+			this._treeView1.Name = "_treeView1";
+			this._treeView1.SelectedImageIndex = -1;
+			this._treeView1.Size = new System.Drawing.Size(680, 600);
+			this._treeView1.TabIndex = 0;
+			this._treeView1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnTreeViewMouseDown);
+			this._treeView1.DoubleClick += new System.EventHandler(this.OnTreeViewDoubleClick);
+			this._treeView1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnTreeViewMouseMove);
+			// 
+			// Form1
+			// 
+			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+			this.ClientSize = new System.Drawing.Size(680, 598);
+			this.Controls.AddRange(new System.Windows.Forms.Control[] {
+																		  this._treeView1});
+			this.Menu = this.mainMenu1;
+			this.Name = "Form1";
+			this.Text = "Scott\'s Move Tree";
+			this.ResumeLayout(false);
+
+		}
+		#endregion
+
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		[STAThread]
+		static void Main(string[] args) 
+		{
+			string filename = string.Empty;
+			if (args.Length > 0)
+				filename = args[0];
+
+			Application.Run(new Form1(filename));
+		}
+
+		/// <summary>
+		/// Use Xml support to load and parse the indicated xml doc.
+		/// Populate tree control with it.
+		/// </summary>
+		/// <param name="filename">path to the xml file to load</param>
+		private void Display(string filename)
+		{
+			_treeView1.BeginUpdate();
+			try
+			{
+				XmlDocument doc = new XmlDocument();
+				doc.Load(filename);
+				_treeView1.Nodes.Clear();
+				TreeNode root = new TreeNode(doc.DocumentElement.Name);
+				_treeView1.Nodes.Add(root);
+				// recursively add all
+				StringBuilder builder = new StringBuilder();
+				foreach(XmlNode node in doc.DocumentElement.ChildNodes)
+				{
+					AddNode(node, ref root, ref builder);
+				}
+			}
+			catch(Exception e)
+			{
+				MessageBox.Show(this, e.Message + "\r\n" +
+					e.StackTrace, "Error", 
+					MessageBoxButtons.OK, MessageBoxIcon.Error);
+			}
+			_treeView1.EndUpdate();
+		}
+
+		/// <summary>
+		/// Recursively add nodes to the tree. 
+		/// </summary>
+		/// <param name="element">the current info to add; corresponds
+		/// to the parent node so that we are adding its children.</param>
+		/// <param name="parent">parent node in the tree</param>
+		/// <param name="builder">on;y create one instance of string builder
+		/// and use it for text manipulation</param>
+		/// <remarks>Nodes that don't have any nested nodes (other than their
+		/// own "value") should be written in the form 
+		/// &lt; tagName attrib="Attrib value" />
+		/// In this case, the tag name and the first attrib value are
+		/// shown in one line (in one node) in the tree. NOTE: any
+		/// additional tags are ignored. (the attrib value is not required).
+		/// </remarks>
+		private void AddNode(XmlNode element, ref TreeNode parent,
+			ref StringBuilder builder)
+		{
+			builder.Length = 0;
+			string text = element.Name;
+
+			// special cases:
+			//  - score: append parent text with score instead of adding 
+			//    it as a node. 
+			//  - any with attribs - append first attrib val to node text
+			//		- bold - (must be first attrib) - boldface the node
+			//		- tip - (any attrib) - set as the tag of the node for tooltip
+
+			if (text.Equals(TAG_SCORE))
+			{
+				builder.Append(parent.Text);
+				builder.Append(VALUE_SEPARATOR);
+				builder.Append(TAG_SCORE);
+				builder.Append(" ");
+				builder.Append(element.Attributes[0].Value);
+				parent.Text = builder.ToString();
+				// done
+			}
+			else
+			{
+				builder.Append(text);
+				XmlAttributeCollection coll = element.Attributes;
+				int numAttribs = coll.Count;
+				XmlAttribute attrib = null;
+				if (numAttribs > 0)
+				{
+					attrib = coll[0];
+					// append the tag name with the first attrib value
+					builder.Append(VALUE_SEPARATOR);
+					builder.Append(attrib.Value);
+				}
+				TreeNode node = new TreeNode(builder.ToString());
+
+				if ((attrib != null) && attrib.Name.Equals(ATTRIB_BOLD))
+					node.ForeColor = Color.Red;
+				if (numAttribs > 1)
+				{								
+					attrib = coll[1];
+					if (attrib.Name.Equals(ATTRIB_TIP))
+					{
+						node.Tag = attrib.Value;
+					}
+				}
+
+				parent.Nodes.Add(node);	
+
+				foreach (XmlElement child in element.ChildNodes)
+				{
+					AddNode(child, ref node, ref builder);
+				}
+			}
+		}
+
+		/// <summary>
+		/// Gets and saves the path to the viewer app from the user.
+		/// </summary>
+		private DialogResult SetViewerAppPath()
+		{
+			DialogResult result = DialogResult.OK;
+			if (_boardViewerAppPath == null)
+			{
+				result = MessageBox.Show(this, 
+					"Please set path to Winboard or XBoard viewer app",
+					"Input requested", MessageBoxButtons.OKCancel, 
+					MessageBoxIcon.Question);
+				if ( result == DialogResult.OK)
+				{
+					OpenFileDialog browse = new OpenFileDialog();
+					browse.Filter = "Executable files (*.exe)|*.exe";
+					browse.Multiselect = false;
+					result = browse.ShowDialog(this);
+					if (result == DialogResult.OK)
+					{
+						_boardViewerAppPath = browse.FileName;
+					}
+				}
+			}
+			return result;
+		}
+
+		/// <summary>
+		/// Closes the viewer app
+		/// </summary>
+		private void KillProcess()
+		{
+			if (_process != null)
+			{
+				if (!_process.HasExited)
+				{
+					if (!_process.CloseMainWindow())
+						_process.Kill();
+				}
+				_process = null;
+			}
+		}
+
+		/// <summary>
+		/// Writes board position to file and calls the viewer app with it.
+		/// </summary>
+		/// <param name="text">text of the board node, starting with the 
+		/// "board" tag and separator</param>
+		private void ViewBoard(string text)
+		{
+			string boardCode = text.Substring(TAG_BOARD.Length
+				+ VALUE_SEPARATOR.Length);
+			StreamWriter f = new StreamWriter(new FileStream(
+				Path.Combine(_applicationDir, POSITION_FILE_NAME),
+				FileMode.Create, FileAccess.Write));
+			f.WriteLine(boardCode);
+			f.Close();
+
+			if (SetViewerAppPath() == DialogResult.OK)
+			{
+
+				try
+				{
+					KillProcess();
+					ProcessStartInfo pInfo = 
+						new ProcessStartInfo(_boardViewerAppPath);
+					pInfo.Arguments = 
+						"/mode editposition /ncp /top /coords /size small /lpf " +
+						Path.Combine(_applicationDir, POSITION_FILE_NAME);
+
+					_process = new Process();
+					_process.StartInfo = pInfo;
+					_process.Start();
+				}
+				catch(Exception)
+				{
+					MessageBox.Show(this, "Unable to run viewer app", "Error", 
+						MessageBoxButtons.OK, MessageBoxIcon.Error);
+					_boardViewerAppPath = null;
+					_process = null;
+				}
+			}
+		}
+
+
+		#region Event Handlers
+
+		/// <summary>
+		/// Handler for File | Open menu. Get the xml file to load.
+		/// </summary>
+		/// <param name="sender">ignored</param>
+		/// <param name="e">ignored</param>
+		private void OnOpenMenuClick(object sender, System.EventArgs e)
+		{
+			OpenFileDialog dialog = new  OpenFileDialog();
+			dialog.Multiselect = false;
+			dialog.Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*";
+			if (dialog.ShowDialog(this) == DialogResult.OK)
+			{
+				Display(dialog.FileName);
+			}
+		}
+
+		/// <summary>
+		/// Handles mouse down. if right-click on "board" node, 
+		/// displays board context menu.
+		/// </summary>
+		/// <param name="sender">ignored</param>
+		/// <param name="e">select the tree node at the click
+		/// coords</param>
+		private void OnTreeViewMouseDown(object sender, MouseEventArgs e)
+		{
+			// this doesn't automatically happen
+			_treeView1.SelectedNode = _treeView1.GetNodeAt(e.X, e.Y);
+			if (e.Button.Equals(MouseButtons.Right))
+			{
+				string text = _treeView1.SelectedNode.Text;
+				if (text.StartsWith(TAG_BOARD))
+				{
+					_treeView1.ContextMenu = _contextMenu;
+				}
+			}
+		}
+
+		/// <summary>
+		/// when view board menu item chosen, writes the selected board 
+		/// position to a file and calls the viewer app.
+		/// </summary>
+		/// <param name="sender">ignored</param>
+		/// <param name="e">ignored</param>
+		private void OnViewBoardMenuClicked(object sender, EventArgs e)
+		{
+			string text = _treeView1.SelectedNode.Text;
+			if (text.StartsWith(TAG_BOARD))
+			{
+				ViewBoard(text);
+			}
+			_treeView1.ContextMenu = null;
+		}
+
+		/// <summary>
+		/// If double-click a "board" node, calls the viewer 
+		/// for the position
+		/// </summary>
+		/// <param name="sender"></param>
+		/// <param name="e"></param>
+		private void OnTreeViewDoubleClick(object sender, System.EventArgs e)
+		{
+			string text = _treeView1.SelectedNode.Text;
+			if (text.StartsWith(TAG_BOARD))
+			{
+				ViewBoard(text);
+			}
+		}
+
+		/// <summary>
+		/// set tooltip if over a node with a displayable tag 
+		/// </summary>
+		/// <param name="sender">ignored</param>
+		/// <param name="e">holds mouse position</param>
+		private void OnTreeViewMouseMove(object sender, MouseEventArgs e)
+		{
+			TreeNode node = _treeView1.GetNodeAt(e.X, e.Y);
+			string tag = string.Empty;
+			if ((node != null) && (node.Tag != null))
+			{
+				tag = (string)node.Tag;
+			}
+			if (!tag.Equals(_tipText))
+			{
+				_tipText = tag;
+				_tip.SetToolTip(_treeView1, _tipText);
+			}
+		}
+
+
+		#endregion
+
+
+	}
+}
diff --git a/Form1.resx b/Form1.resx
new file mode 100644
index 0000000..3d2bdb8
--- /dev/null
+++ b/Form1.resx
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+            Microsoft ResX Schema 
+        
+            Version 1.3
+                
+            The primary goals of this format is to allow a simple XML format 
+            that is mostly human readable. The generation and parsing of the 
+            various data types are done through the TypeConverter classes 
+            associated with the data types.
+        
+            Example:
+        
+                ... ado.net/XML headers & schema ...
+                <resheader name="resmimetype">text/microsoft-resx</resheader>
+                <resheader name="version">1.3</resheader>
+                <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+                <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+                <data name="Name1">this is my long string</data>
+                <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+                <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+                    [base64 mime encoded serialized .NET Framework object]
+                </data>
+                <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+                    [base64 mime encoded string representing a byte array form of the .NET Framework object]
+                </data>
+        
+            There are any number of "resheader" rows that contain simple 
+            name/value pairs.
+            
+            Each data row contains a name, and value. The row also contains a 
+            type or mimetype. Type corresponds to a .NET class that support 
+            text/value conversion through the TypeConverter architecture. 
+            Classes that don't support this are serialized and stored with the 
+            mimetype set.
+                     
+            The mimetype is used for serialized objects, and tells the 
+            ResXResourceReader how to depersist the object. This is currently not 
+            extensible. For a given mimetype the value must be set accordingly:
+        
+            Note - application/x-microsoft.net.object.binary.base64 is the format 
+                   that the ResXResourceWriter will generate, however the reader can 
+                   read any of the formats listed below.
+        
+            mimetype: application/x-microsoft.net.object.binary.base64
+            value   : The object must be serialized with 
+                    : System.Serialization.Formatters.Binary.BinaryFormatter
+                    : and then encoded with base64 encoding.
+        
+            mimetype: application/x-microsoft.net.object.soap.base64
+            value   : The object must be serialized with 
+                    : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+                    : and then encoded with base64 encoding.
+            mimetype: application/x-microsoft.net.object.bytearray.base64
+            value   : The object must be serialized into a byte array 
+                    : using a System.ComponentModel.TypeConverter
+                    : and then encoded with base64 encoding.
+        -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>1.3</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="mainMenu1.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </data>
+  <data name="$this.Name">
+    <value>Form1</value>
+  </data>
+  <data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>33</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/typhoonUI.csproj b/typhoonUI.csproj
new file mode 100644
index 0000000..d4c48d8
--- /dev/null
+++ b/typhoonUI.csproj
@@ -0,0 +1,112 @@
+<VisualStudioProject>
+    <CSHARP
+        ProjectType = "Local"
+        ProductVersion = "7.0.9466"
+        SchemaVersion = "1.0"
+        ProjectGuid = "{6A1EA114-F59A-4598-A2E1-147B732DD135}"
+    >
+        <Build>
+            <Settings
+                ApplicationIcon = "App.ico"
+                AssemblyKeyContainerName = ""
+                AssemblyName = "typhoonUI"
+                AssemblyOriginatorKeyFile = ""
+                DefaultClientScript = "JScript"
+                DefaultHTMLPageLayout = "Grid"
+                DefaultTargetSchema = "IE50"
+                DelaySign = "false"
+                OutputType = "WinExe"
+                RootNamespace = "typhoonUI"
+                StartupObject = ""
+            >
+                <Config
+                    Name = "Debug"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "DEBUG;TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "true"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "true"
+                    Optimize = "false"
+                    OutputPath = "bin\Debug\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+                <Config
+                    Name = "Release"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "false"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    Optimize = "true"
+                    OutputPath = "bin\Release\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+            </Settings>
+            <References>
+                <Reference
+                    Name = "System"
+                    AssemblyName = "System"
+                    HintPath = "..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+                />
+                <Reference
+                    Name = "System.Data"
+                    AssemblyName = "System.Data"
+                    HintPath = "..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+                />
+                <Reference
+                    Name = "System.Drawing"
+                    AssemblyName = "System.Drawing"
+                    HintPath = "..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
+                />
+                <Reference
+                    Name = "System.Windows.Forms"
+                    AssemblyName = "System.Windows.Forms"
+                    HintPath = "..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
+                />
+                <Reference
+                    Name = "System.XML"
+                    AssemblyName = "System.Xml"
+                    HintPath = "..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+                />
+            </References>
+        </Build>
+        <Files>
+            <Include>
+                <File
+                    RelPath = "App.ico"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "AssemblyInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "Form1.cs"
+                    SubType = "Form"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "Form1.resx"
+                    DependentUpon = "Form1.cs"
+                    BuildAction = "EmbeddedResource"
+                />
+            </Include>
+        </Files>
+    </CSHARP>
+</VisualStudioProject>
+
diff --git a/typhoonUI.csproj.user b/typhoonUI.csproj.user
new file mode 100644
index 0000000..e31ed2b
--- /dev/null
+++ b/typhoonUI.csproj.user
@@ -0,0 +1,48 @@
+<VisualStudioProject>
+    <CSHARP>
+        <Build>
+            <Settings ReferencePath = "" >
+                <Config
+                    Name = "Debug"
+                    EnableASPDebugging = "false"
+                    EnableASPXDebugging = "false"
+                    EnableUnmanagedDebugging = "false"
+                    EnableSQLServerDebugging = "false"
+                    RemoteDebugEnabled = "false"
+                    RemoteDebugMachine = ""
+                    StartAction = "Project"
+                    StartArguments = ""
+                    StartPage = ""
+                    StartProgram = ""
+                    StartURL = ""
+                    StartWorkingDirectory = ""
+                    StartWithIE = "true"
+                />
+                <Config
+                    Name = "Release"
+                    EnableASPDebugging = "false"
+                    EnableASPXDebugging = "false"
+                    EnableUnmanagedDebugging = "false"
+                    EnableSQLServerDebugging = "false"
+                    RemoteDebugEnabled = "false"
+                    RemoteDebugMachine = ""
+                    StartAction = "Project"
+                    StartArguments = ""
+                    StartPage = ""
+                    StartProgram = ""
+                    StartURL = ""
+                    StartWorkingDirectory = ""
+                    StartWithIE = "true"
+                />
+            </Settings>
+        </Build>
+        <OtherProjectSettings
+            CopyProjectDestinationFolder = ""
+            CopyProjectUncPath = ""
+            CopyProjectOption = "0"
+            ProjectView = "ProjectFiles"
+            ProjectTrust = "0"
+        />
+    </CSHARP>
+</VisualStudioProject>
+
diff --git a/typhoonUI.sln b/typhoonUI.sln
new file mode 100644
index 0000000..1b3179d
--- /dev/null
+++ b/typhoonUI.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "typhoonUI", "typhoonUI.csproj", "{6A1EA114-F59A-4598-A2E1-147B732DD135}"
+EndProject
+Global
+	GlobalSection(SolutionConfiguration) = preSolution
+		ConfigName.0 = Debug
+		ConfigName.1 = Release
+	EndGlobalSection
+	GlobalSection(ProjectDependencies) = postSolution
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{6A1EA114-F59A-4598-A2E1-147B732DD135}.Debug.ActiveCfg = Debug|.NET
+		{6A1EA114-F59A-4598-A2E1-147B732DD135}.Debug.Build.0 = Debug|.NET
+		{6A1EA114-F59A-4598-A2E1-147B732DD135}.Release.ActiveCfg = Release|.NET
+		{6A1EA114-F59A-4598-A2E1-147B732DD135}.Release.Build.0 = Release|.NET
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal
-- 
2.49.0