From 9a386d25f4e8a7ce10a9d44115e8dc9b675a9544 Mon Sep 17 00:00:00 2001
From: chylex <contact@chylex.com>
Date: Mon, 29 Jul 2024 16:57:33 +0200
Subject: [PATCH] Add project files before Git

---
 .gitignore                                    |   3 +
 AppCalc/App.cs                                | 235 ++++++++++++++++++
 AppCalc/AppCalc.csproj                        |  57 +++++
 AppCalc/Operators.cs                          |  28 +++
 AppCalc/Properties/AssemblyInfo.cs            |  35 +++
 AppConv/App.cs                                |  49 ++++
 AppConv/AppConv.csproj                        |  69 +++++
 AppConv/General/DecimalUnitConverterBase.cs   | 126 ++++++++++
 AppConv/General/DecimalUnitConverterSimple.cs |  66 +++++
 AppConv/General/IUnitType.cs                  |   5 +
 AppConv/Properties/AssemblyInfo.cs            |  35 +++
 AppConv/Units/Angle.cs                        |  29 +++
 AppConv/Units/Area.cs                         |  43 ++++
 AppConv/Units/Length.cs                       |  84 +++++++
 AppConv/Units/Radix.cs                        | 124 +++++++++
 AppConv/Units/Storage.cs                      |  29 +++
 AppConv/Units/Temperature.cs                  | 102 ++++++++
 AppConv/Units/Volume.cs                       |  28 +++
 AppConv/Units/Weight.cs                       |  25 ++
 AppConv/Utils/RadixConversion.cs              |  78 ++++++
 AppConv/Utils/SI.cs                           |  89 +++++++
 AppMeme/App.cs                                |  25 ++
 AppMeme/AppMeme.csproj                        |  56 +++++
 AppMeme/Properties/AssemblyInfo.cs            |  35 +++
 AppWindows/App.cs                             |  26 ++
 AppWindows/AppSys.csproj                      |  59 +++++
 AppWindows/Handlers/HandlerApps.cs            |  58 +++++
 AppWindows/Handlers/HandlerProcesses.cs       |  49 ++++
 AppWindows/IHandler.cs                        |   8 +
 AppWindows/Properties/AssemblyInfo.cs         |  35 +++
 Base/Base.csproj                              |  55 ++++
 Base/Command.cs                               |  44 ++++
 Base/CommandEventArgs.cs                      |  11 +
 Base/CommandException.cs                      |   8 +
 Base/IApp.cs                                  |   8 +
 Base/MatchConfidence.cs                       |   8 +
 Base/Properties/AssemblyInfo.cs               |  35 +++
 Base/Utils/RegexUtils.cs                      |  23 ++
 Query.sln                                     |  60 +++++
 Query/Controls/QueryHistoryLog.Designer.cs    |  57 +++++
 Query/Controls/QueryHistoryLog.cs             |  43 ++++
 Query/Controls/QueryTextBox.Designer.cs       |  61 +++++
 Query/Controls/QueryTextBox.cs                | 158 ++++++++++++
 Query/Core/CommandHistory.cs                  |  33 +++
 Query/Core/CommandProcessor.cs                |  65 +++++
 Query/Core/KeyboardHook.cs                    |  64 +++++
 Query/MainForm.Designer.cs                    | 135 ++++++++++
 Query/MainForm.cs                             | 146 +++++++++++
 Query/MainForm.resx                           | 219 ++++++++++++++++
 Query/Program.cs                              |  13 +
 Query/Properties/AssemblyInfo.cs              |  35 +++
 Query/Properties/Resources.Designer.cs        |  62 +++++
 Query/Properties/Resources.resx               | 117 +++++++++
 Query/Properties/Settings.Designer.cs         |  26 ++
 Query/Properties/Settings.settings            |   7 +
 Query/Query.csproj                            | 118 +++++++++
 icon.ico                                      | Bin 0 -> 2462 bytes
 57 files changed, 3301 insertions(+)
 create mode 100644 AppCalc/App.cs
 create mode 100644 AppCalc/AppCalc.csproj
 create mode 100644 AppCalc/Operators.cs
 create mode 100644 AppCalc/Properties/AssemblyInfo.cs
 create mode 100644 AppConv/App.cs
 create mode 100644 AppConv/AppConv.csproj
 create mode 100644 AppConv/General/DecimalUnitConverterBase.cs
 create mode 100644 AppConv/General/DecimalUnitConverterSimple.cs
 create mode 100644 AppConv/General/IUnitType.cs
 create mode 100644 AppConv/Properties/AssemblyInfo.cs
 create mode 100644 AppConv/Units/Angle.cs
 create mode 100644 AppConv/Units/Area.cs
 create mode 100644 AppConv/Units/Length.cs
 create mode 100644 AppConv/Units/Radix.cs
 create mode 100644 AppConv/Units/Storage.cs
 create mode 100644 AppConv/Units/Temperature.cs
 create mode 100644 AppConv/Units/Volume.cs
 create mode 100644 AppConv/Units/Weight.cs
 create mode 100644 AppConv/Utils/RadixConversion.cs
 create mode 100644 AppConv/Utils/SI.cs
 create mode 100644 AppMeme/App.cs
 create mode 100644 AppMeme/AppMeme.csproj
 create mode 100644 AppMeme/Properties/AssemblyInfo.cs
 create mode 100644 AppWindows/App.cs
 create mode 100644 AppWindows/AppSys.csproj
 create mode 100644 AppWindows/Handlers/HandlerApps.cs
 create mode 100644 AppWindows/Handlers/HandlerProcesses.cs
 create mode 100644 AppWindows/IHandler.cs
 create mode 100644 AppWindows/Properties/AssemblyInfo.cs
 create mode 100644 Base/Base.csproj
 create mode 100644 Base/Command.cs
 create mode 100644 Base/CommandEventArgs.cs
 create mode 100644 Base/CommandException.cs
 create mode 100644 Base/IApp.cs
 create mode 100644 Base/MatchConfidence.cs
 create mode 100644 Base/Properties/AssemblyInfo.cs
 create mode 100644 Base/Utils/RegexUtils.cs
 create mode 100644 Query.sln
 create mode 100644 Query/Controls/QueryHistoryLog.Designer.cs
 create mode 100644 Query/Controls/QueryHistoryLog.cs
 create mode 100644 Query/Controls/QueryTextBox.Designer.cs
 create mode 100644 Query/Controls/QueryTextBox.cs
 create mode 100644 Query/Core/CommandHistory.cs
 create mode 100644 Query/Core/CommandProcessor.cs
 create mode 100644 Query/Core/KeyboardHook.cs
 create mode 100644 Query/MainForm.Designer.cs
 create mode 100644 Query/MainForm.cs
 create mode 100644 Query/MainForm.resx
 create mode 100644 Query/Program.cs
 create mode 100644 Query/Properties/AssemblyInfo.cs
 create mode 100644 Query/Properties/Resources.Designer.cs
 create mode 100644 Query/Properties/Resources.resx
 create mode 100644 Query/Properties/Settings.Designer.cs
 create mode 100644 Query/Properties/Settings.settings
 create mode 100644 Query/Query.csproj
 create mode 100644 icon.ico

diff --git a/.gitignore b/.gitignore
index 40da635..072d145 100644
--- a/.gitignore
+++ b/.gitignore
@@ -396,3 +396,6 @@ FodyWeavers.xsd
 
 # JetBrains Rider
 *.sln.iml
+
+# Custom
+/.idea/
diff --git a/AppCalc/App.cs b/AppCalc/App.cs
new file mode 100644
index 0000000..f51d0cc
--- /dev/null
+++ b/AppCalc/App.cs
@@ -0,0 +1,235 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using Base;
+
+namespace AppCalc{
+    public sealed class App : IApp{
+        private static readonly Regex RegexValidCharacters = new Regex(@"^[\s\d\.\-+*/%^]+$", RegexOptions.Compiled);
+        private static readonly Regex RegexTokenSeparator = new Regex(@"((?<!\d)-?(((\d+)?\.\d+(\.\.\.)?)|\d+))|[^\d\s]", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
+        private static readonly Regex RegexRecurringDecimal = new Regex(@"\b(?:(\d+?\.\d{0,}?)(\d+?)\2+|([\d+?\.]*))\b", RegexOptions.Compiled);
+
+        private static readonly char[] SplitSpace = { ' ' };
+
+        public string[] RecognizedNames => new string[]{
+            "calc",
+            "calculate",
+            "calculator"
+        };
+        
+        public MatchConfidence GetConfidence(Command cmd){
+            return RegexValidCharacters.IsMatch(cmd.Text) ? MatchConfidence.Possible : MatchConfidence.None;
+        }
+
+        string IApp.ProcessCommand(Command cmd){
+            return ParseAndProcessExpression(cmd.Text);
+        }
+
+        private static string ParseAndProcessExpression(string text){
+            // text = RegexBalancedParentheses.Replace(text, match => " "+ParseAndProcessExpression(match.Groups[1].Value)+" "); // parens are handled as apps
+
+            string expression = RegexTokenSeparator.Replace(text, match => " "+match.Value+" ");
+            string[] tokens = expression.Split(SplitSpace, StringSplitOptions.RemoveEmptyEntries);
+
+            decimal result = ProcessExpression(tokens);
+
+            if (Math.Abs(result-decimal.Round(result)) < 0.0000000000000000000000000010M){
+                return decimal.Round(result).ToString(CultureInfo.InvariantCulture);
+            }
+
+            string res = result.ToString(CultureInfo.InvariantCulture);
+            bool hasDecimalPoint = decimal.Round(result) != result;
+
+            if (res.Length == 30 && hasDecimalPoint && res.IndexOf('.') < 15){ // Length 30 uses all available bytes
+                res = res.Substring(0, res.Length-1);
+
+                Match match = RegexRecurringDecimal.Match(res);
+
+                if (match.Groups[2].Success){
+                    string repeating = match.Groups[2].Value;
+
+                    StringBuilder build = new StringBuilder(34);
+                    build.Append(match.Groups[1].Value);
+
+                    do{
+                        build.Append(repeating);
+                    }while(build.Length+repeating.Length <= res.Length);
+
+                    return build.Append(repeating.Substring(0, 1+build.Length-res.Length)).Append("...").ToString();
+                }
+            }
+            else if (hasDecimalPoint){
+                res = res.TrimEnd('0');
+            }
+
+            return res;
+        }
+
+        private static decimal ProcessExpression(string[] tokens){
+            bool isPostfix;
+
+            if (tokens.Length < 3){
+                isPostfix = false;
+            }
+            else{
+                try{
+                    ParseNumberToken(tokens[0]);
+                }catch(CommandException){
+                    throw new CommandException("Prefix notation is not supported.");
+                }
+
+                try{
+                    ParseNumberToken(tokens[1]);
+                    isPostfix = true;
+                }catch(CommandException){
+                    isPostfix = false;
+                }
+            }
+
+            if (isPostfix){
+                return ProcessPostfixExpression(tokens);
+            }
+            else{
+                return ProcessPostfixExpression(ConvertInfixToPostfix(tokens));
+            }
+        }
+
+        private static IEnumerable<string> ConvertInfixToPostfix(IEnumerable<string> tokens){
+            Stack<string> operators = new Stack<string>();
+
+            foreach(string token in tokens){
+                if (Operators.With2Operands.Contains(token)){
+                    int currentPrecedence = Operators.GetPrecedence(token);
+                    bool currentRightAssociative = Operators.IsRightAssociative(token);
+
+                    while(operators.Count > 0){
+                        int topPrecedence = Operators.GetPrecedence(operators.Peek());
+
+                        if ((currentRightAssociative && currentPrecedence < topPrecedence) || (!currentRightAssociative && currentPrecedence <= topPrecedence)){
+                            yield return operators.Pop();
+                        }
+                        else{
+                            break;
+                        }
+                    }
+
+                    operators.Push(token);
+                }
+                else{
+                    yield return ParseNumberToken(token).ToString(CultureInfo.InvariantCulture);
+                }
+            }
+
+            while(operators.Count > 0){
+                yield return operators.Pop();
+            }
+        }
+
+        private static decimal ProcessPostfixExpression(IEnumerable<string> tokens){
+            Stack<decimal> stack = new Stack<decimal>();
+
+            foreach(string token in tokens){
+                decimal operand1, operand2;
+
+                if (token == "-" && stack.Count == 1){
+                    operand2 = stack.Pop();
+                    operand1 = 0M;
+                }
+                else if (Operators.With2Operands.Contains(token)){
+                    if (stack.Count < 2){
+                        throw new CommandException("Incorrect syntax, not enough numbers in stack.");
+                    }
+
+                    operand2 = stack.Pop();
+                    operand1 = stack.Pop();
+                }
+                else{
+                    operand1 = operand2 = 0M;
+                }
+
+                switch(token){
+                    case "+": stack.Push(operand1+operand2); break;
+                    case "-": stack.Push(operand1-operand2); break;
+                    case "*": stack.Push(operand1*operand2); break;
+                    
+                    case "/":
+                        if (operand2 == 0M){
+                            throw new CommandException("Cannot divide by zero.");
+                        }
+
+                        stack.Push(operand1/operand2);
+                        break;
+
+                    case "%":
+                        if (operand2 == 0M){
+                            throw new CommandException("Cannot divide by zero.");
+                        }
+
+                        stack.Push(operand1%operand2);
+                        break;
+
+                    case "^":
+                        if (operand1 == 0M && operand2 == 0M){
+                            throw new CommandException("Cannot evaluate 0 to the power of 0.");
+                        }
+                        else if (operand1 < 0M && Math.Abs(operand2) < 1M){
+                            throw new CommandException("Cannot evaluate a root of a negative number.");
+                        }
+
+                        try{
+                            stack.Push((decimal)Math.Pow((double)operand1, (double)operand2));
+                        }catch(OverflowException ex){
+                            throw new CommandException("Number overflow.", ex);
+                        }
+
+                        break;
+
+                    default:
+                        stack.Push(ParseNumberToken(token));
+                        break;
+                }
+            }
+
+            if (stack.Count != 1){
+                throw new CommandException("Incorrect syntax, too many numbers in stack.");
+            }
+
+            return stack.Pop();
+        }
+
+        private static decimal ParseNumberToken(string token){
+            string str = token;
+
+            if (str.StartsWith("-.")){
+                str = "-0"+str.Substring(1);
+            }
+            else if (str[0] == '.'){
+                str = "0"+str;
+            }
+
+            if (str.EndsWith("...")){
+                string truncated = str.Substring(0, str.Length-3);
+
+                if (truncated.IndexOf('.') != -1){
+                    str = truncated;
+                }
+            }
+
+            decimal value;
+
+            if (decimal.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out value)){
+                if (value.ToString(CultureInfo.InvariantCulture) != str){
+                    throw new CommandException("Provided number is outside of decimal range: "+token);
+                }
+
+                return value;
+            }
+            else{
+                throw new CommandException("Invalid token, expected a number: "+token);
+            }
+        }
+    }
+}
diff --git a/AppCalc/AppCalc.csproj b/AppCalc/AppCalc.csproj
new file mode 100644
index 0000000..2b5093a
--- /dev/null
+++ b/AppCalc/AppCalc.csproj
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{C7A21640-CAF3-40E8-AA6A-793181BD28AA}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>AppCalc</RootNamespace>
+    <AssemblyName>AppCalc</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App.cs" />
+    <Compile Include="Operators.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Base\Base.csproj">
+      <Project>{66CF4F71-50DD-4C65-AB96-35D1193FFB50}</Project>
+      <Name>Base</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/AppCalc/Operators.cs b/AppCalc/Operators.cs
new file mode 100644
index 0000000..2bb7b38
--- /dev/null
+++ b/AppCalc/Operators.cs
@@ -0,0 +1,28 @@
+namespace AppCalc{
+    internal static class Operators{
+        internal static readonly string[] With2Operands = { "+", "-", "*", "/", "%", "^" };
+
+        internal static int GetPrecedence(string token){
+            switch(token){
+                case "^":
+                    return 4;
+
+                case "*":
+                case "/":
+                case "%":
+                    return 3;
+
+                case "+":
+                case "-":
+                    return 2;
+
+                default:
+                    return 1;
+            }
+        }
+
+        internal static bool IsRightAssociative(string token){
+            return token == "^";
+        }
+    }
+}
diff --git a/AppCalc/Properties/AssemblyInfo.cs b/AppCalc/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e4d69bc
--- /dev/null
+++ b/AppCalc/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// 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("AppCalc")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AppCalc")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("8e0868ef-ce49-4d8b-b496-bf59f38e21bd")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/AppConv/App.cs b/AppConv/App.cs
new file mode 100644
index 0000000..cbc6523
--- /dev/null
+++ b/AppConv/App.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Linq;
+using AppConv.General;
+using AppConv.Units;
+using Base;
+
+namespace AppConv{
+    public sealed class App : IApp{
+        private static readonly IUnitType[] Processors = {
+            new Temperature(),
+            new Weight(),
+            new Length(),
+            new Area(),
+            new Volume(),
+            new Angle(),
+            new Storage(),
+            new Radix()
+        };
+
+        public string[] RecognizedNames => new string[]{
+            "conv",
+            "convert"
+        };
+        
+        public MatchConfidence GetConfidence(Command cmd){
+            return cmd.Text.IndexOf(" to ", StringComparison.InvariantCultureIgnoreCase) != -1 ? MatchConfidence.Possible : MatchConfidence.None;
+        }
+
+        public string ProcessCommand(Command cmd){
+            string[] data = cmd.Text.Split(new string[]{ " to " }, 2, StringSplitOptions.None);
+
+            string src = data[0].Trim();
+            string dst = data[1].Trim();
+
+            if (src.Length == 0 || dst.Length == 0){
+                throw new CommandException("Unrecognized conversion app syntax.");
+            }
+
+            string result = string.Empty;
+            IUnitType used = Processors.FirstOrDefault(processor => processor.TryProcess(src, dst, out result));
+
+            if (used == null){
+                throw new CommandException("Could not recognize conversion units.");
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/AppConv/AppConv.csproj b/AppConv/AppConv.csproj
new file mode 100644
index 0000000..a5dea09
--- /dev/null
+++ b/AppConv/AppConv.csproj
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1AC5280A-81D1-4E02-9122-DB358734FFB4}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>AppConv</RootNamespace>
+    <AssemblyName>AppConv</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App.cs" />
+    <Compile Include="General\DecimalUnitConverterBase.cs" />
+    <Compile Include="General\DecimalUnitConverterSimple.cs" />
+    <Compile Include="Units\Storage.cs" />
+    <Compile Include="Units\Angle.cs" />
+    <Compile Include="Units\Area.cs" />
+    <Compile Include="Utils\RadixConversion.cs" />
+    <Compile Include="Utils\SI.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Units\Radix.cs" />
+    <Compile Include="Units\Volume.cs" />
+    <Compile Include="Units\Length.cs" />
+    <Compile Include="Units\Temperature.cs" />
+    <Compile Include="General\IUnitType.cs" />
+    <Compile Include="Units\Weight.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Base\Base.csproj">
+      <Project>{66CF4F71-50DD-4C65-AB96-35D1193FFB50}</Project>
+      <Name>Base</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/AppConv/General/DecimalUnitConverterBase.cs b/AppConv/General/DecimalUnitConverterBase.cs
new file mode 100644
index 0000000..fa40fb7
--- /dev/null
+++ b/AppConv/General/DecimalUnitConverterBase.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppConv.General{
+    internal abstract class DecimalUnitConverterBase<T> : IUnitType where T : struct{
+        internal sealed class DecimalFuncMap : Dictionary<T, Func<decimal, decimal>>{
+            public DecimalFuncMap(){}
+            public DecimalFuncMap(int capacity) : base(capacity){}
+        }
+
+        internal sealed class NameMap : Dictionary<string, T>{
+            public NameMap(){}
+            public NameMap(int capacity) : base(capacity){}
+        }
+
+        protected abstract NameMap Names { get; }
+        protected abstract DecimalFuncMap ConvertTo { get; }
+        protected abstract DecimalFuncMap ConvertFrom { get; }
+
+        protected virtual int Precision{
+            get{
+                return 0;
+            }
+        }
+
+        protected virtual bool CaseCheck{
+            get{
+                return false;
+            }
+        }
+
+        protected virtual NumberStyles NumberStyle{
+            get{
+                return NumberStyles.Float & ~NumberStyles.AllowLeadingSign;
+            }
+        }
+
+        protected virtual string ProcessSrc(string src){
+            return src;
+        }
+
+        protected virtual string ProcessDst(string dst){
+            return dst;
+        }
+
+        protected abstract bool IsValueInvalid(T value);
+
+        protected virtual decimal Convert(decimal value, T from, T to){
+            return ConvertFrom[to](ConvertTo[from](value));
+        }
+
+        protected virtual string Format(decimal value){
+            if (Precision > 0){
+                decimal truncated = decimal.Truncate(value);
+
+                if (value == truncated){
+                    return truncated.ToString(CultureInfo.InvariantCulture);
+                }
+            }
+
+            int decimalPlaces = Precision;
+
+            if (Math.Abs(value) < 1M){
+                double fractionalPart = (double)Math.Abs(value%1M);
+                int fractionalZeroCount = -(int)Math.Ceiling(Math.Log(fractionalPart, 10D));
+
+                decimalPlaces = Math.Min(28, fractionalZeroCount+Precision);
+            }
+
+            string result = decimal.Round(value, decimalPlaces, MidpointRounding.ToEven).ToString(CultureInfo.InvariantCulture);
+
+            if (decimalPlaces > 0){
+                result = result.TrimEnd('0').TrimEnd('.');
+            }
+
+            return result;
+        }
+        
+        public bool TryProcess(string src, string dst, out string result){
+            src = ProcessSrc(src);
+            dst = ProcessDst(dst);
+
+            KeyValuePair<string, T>[] pairs = new KeyValuePair<string, T>[2];
+
+            for(int index = 0; index < 2; index++){
+                string str = index == 0 ? src : dst;
+
+                if (CaseCheck){
+                    List<KeyValuePair<string, T>> list = Names.Where(kvp => str.EndsWith(kvp.Key, StringComparison.InvariantCultureIgnoreCase) && (str.Length == kvp.Key.Length || !char.IsLetter(str[str.Length-kvp.Key.Length-1]))).ToList();
+
+                    if (list.Count == 1){
+                        pairs[index] = list[0];
+                    }
+                    else{
+                        pairs[index] = list.FirstOrDefault(kvp => str.EndsWith(kvp.Key, StringComparison.InvariantCulture));
+                    }
+                }
+                else{
+                    pairs[index] = Names.FirstOrDefault(kvp => str.EndsWith(kvp.Key, StringComparison.InvariantCultureIgnoreCase) && (str.Length == kvp.Key.Length || !char.IsLetter(str[str.Length-kvp.Key.Length-1])));
+                }
+
+                if (IsValueInvalid(pairs[index].Value)){
+                    result = string.Empty;
+                    return false;
+                }
+
+                if (index == 0){
+                    src = src.Substring(0, src.Length-pairs[index].Key.Length).TrimEnd();
+                }
+            }
+
+            decimal value;
+
+            if (decimal.TryParse(src, NumberStyle, CultureInfo.InvariantCulture, out value)){
+                result = Format(Convert(value, pairs[0].Value, pairs[1].Value));
+                return true;
+            }
+            else{
+                result = string.Empty;
+                return false;
+            }
+        }
+    }
+}
diff --git a/AppConv/General/DecimalUnitConverterSimple.cs b/AppConv/General/DecimalUnitConverterSimple.cs
new file mode 100644
index 0000000..4e14561
--- /dev/null
+++ b/AppConv/General/DecimalUnitConverterSimple.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace AppConv.General{
+    internal abstract class DecimalUnitConverterSimple<T> : DecimalUnitConverterBase<T> where T : struct{
+        // ReSharper disable once StaticMemberInGenericType
+        private static readonly Func<decimal, decimal> FuncNoChange = val => val;
+
+        private readonly NameMap UnitNames = new NameMap();
+        private readonly DecimalFuncMap MapFrom = new DecimalFuncMap();
+        private readonly DecimalFuncMap MapTo = new DecimalFuncMap();
+
+        private int invalidUnitObject = -1;
+        
+        protected sealed override NameMap Names{
+            get{
+                return UnitNames;
+            }
+        }
+
+        protected sealed override DecimalFuncMap ConvertFrom{
+            get{
+                return MapFrom;
+            }
+        }
+
+        protected sealed override DecimalFuncMap ConvertTo{
+            get{
+                return MapTo;
+            }
+        }
+
+        protected override int Precision{
+            get{
+                return 3;
+            }
+        }
+
+        protected override bool CaseCheck{
+            get{
+                return true;
+            }
+        }
+
+        protected void AddUnit(T unitObject, params string[] names){
+            foreach(string name in names){
+                UnitNames.Add(name, unitObject);
+            }
+
+            ConvertFrom.Add(unitObject, FuncNoChange);
+            ConvertTo.Add(unitObject, FuncNoChange);
+        }
+
+        protected void SetUnitFactor(T unitObject, decimal factor){
+            ConvertFrom[unitObject] = val => val*factor;
+            ConvertTo[unitObject] = val => val/factor;
+        }
+
+        protected void SetInvalidUnitObject(T unitObject){
+            this.invalidUnitObject = (int)(object)unitObject;
+        }
+
+        protected sealed override bool IsValueInvalid(T value){
+            return (int)(object)value == invalidUnitObject;
+        }
+    }
+}
diff --git a/AppConv/General/IUnitType.cs b/AppConv/General/IUnitType.cs
new file mode 100644
index 0000000..9dcf3f7
--- /dev/null
+++ b/AppConv/General/IUnitType.cs
@@ -0,0 +1,5 @@
+namespace AppConv.General{
+    internal interface IUnitType{
+        bool TryProcess(string src, string dst, out string result);
+    }
+}
diff --git a/AppConv/Properties/AssemblyInfo.cs b/AppConv/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d6d4592
--- /dev/null
+++ b/AppConv/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// 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("AppConv")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AppConv")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("485d80d3-c780-4264-ae08-b35c599aa73e")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/AppConv/Units/Angle.cs b/AppConv/Units/Angle.cs
new file mode 100644
index 0000000..2d949ab
--- /dev/null
+++ b/AppConv/Units/Angle.cs
@@ -0,0 +1,29 @@
+using System;
+using AppConv.General;
+
+namespace AppConv.Units {
+    internal class Angle : DecimalUnitConverterSimple<Angle.Units>{
+        internal enum Units{
+            Invalid = 0, Degree, Radian, Gradian
+        }
+
+        protected override int Precision{
+            get{
+                return 4;
+            }
+        }
+
+        public Angle(){
+            AddUnit(Units.Degree, "deg", "degree", "degrees", "arc degree", "arc degrees", "arcdegree", "arcdegrees", "°");
+            AddUnit(Units.Radian, "rad", "radian", "radians");
+            AddUnit(Units.Gradian, "grad", "grade", "gon", "gradian", "gradians");
+
+            SetUnitFactor(Units.Radian, (decimal)Math.PI/180M);
+            SetUnitFactor(Units.Gradian, 10M/9M);
+
+            SetInvalidUnitObject(Units.Invalid);
+        }
+
+        // TODO convert degree notation 15°24'9"
+    }
+}
diff --git a/AppConv/Units/Area.cs b/AppConv/Units/Area.cs
new file mode 100644
index 0000000..4e4efc8
--- /dev/null
+++ b/AppConv/Units/Area.cs
@@ -0,0 +1,43 @@
+using AppConv.General;
+
+namespace AppConv.Units{
+    internal class Area : DecimalUnitConverterSimple<Area.Units>{
+        internal enum Units{
+            Invalid = 0, SquareMM, SquareCM, SquareDM, SquareM, SquareKM, SquareMile, SquareYard, SquareFoot, SquareInch, Acre, Centiare, Deciare, Are, Decare, Hectare
+        }
+
+        public Area(){
+            AddUnit(Units.SquareMM, "mm2", "square mm", "square millimeter", "square millimeters", "square millimetre", "square millimetres");
+            AddUnit(Units.SquareCM, "cm2", "square cm", "square centimeter", "square centimeters", "square centimetre", "square centimetres");
+            AddUnit(Units.SquareDM, "dm2", "square dm", "square decimeter", "square decimeters", "square decimetre", "square decimetres");
+            AddUnit(Units.SquareM, "m2", "square m", "square meter", "square meters", "square metre", "square metres");
+            AddUnit(Units.SquareKM, "km2", "square km", "square kilometer", "square kilometers", "square kilometre", "square kilometres");
+            AddUnit(Units.SquareMile, "mi2", "sq mi", "sq mile", "sq miles", "square mi", "square mile", "square miles");
+            AddUnit(Units.SquareYard, "yd2", "sq yd", "sq yard", "sq yards", "square yd", "square yard", "square yards");
+            AddUnit(Units.SquareFoot, "ft2", "sq ft", "sq foot", "sq feet", "square ft", "square foot", "square feet");
+            AddUnit(Units.SquareInch, "in2", "sq in", "sq inch", "sq inches", "square in", "square inch", "square inches");
+            AddUnit(Units.Acre, "ac", "acre", "acres");
+            AddUnit(Units.Centiare, "ca", "centiare", "centiares");
+            AddUnit(Units.Deciare, "da", "deciare", "deciares"); // da is not canon but w/e
+            AddUnit(Units.Are, "a", "are", "ares");
+            AddUnit(Units.Decare, "daa", "decare", "decares");
+            AddUnit(Units.Hectare, "ha", "hectare", "hectares");
+
+            SetUnitFactor(Units.SquareMM, 1E+6M);
+            SetUnitFactor(Units.SquareCM, 1E+4M);
+            SetUnitFactor(Units.SquareDM, 1E+2M);
+            SetUnitFactor(Units.SquareKM, 1E-6M);
+            SetUnitFactor(Units.SquareMile, 3.8610215854245E-7M);
+            SetUnitFactor(Units.SquareYard, 1.1959900463011M);
+            SetUnitFactor(Units.SquareFoot, 10.76391041671M);
+            SetUnitFactor(Units.SquareInch, 1550.0031000062M);
+            SetUnitFactor(Units.Acre, 2.4710538146717E-4M);
+            SetUnitFactor(Units.Deciare, 1E-1M);
+            SetUnitFactor(Units.Are, 1E-2M);
+            SetUnitFactor(Units.Decare, 1E-3M);
+            SetUnitFactor(Units.Hectare, 1E-4M);
+
+            SetInvalidUnitObject(Units.Invalid);
+        }
+    }
+}
diff --git a/AppConv/Units/Length.cs b/AppConv/Units/Length.cs
new file mode 100644
index 0000000..f307e53
--- /dev/null
+++ b/AppConv/Units/Length.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using AppConv.General;
+using AppConv.Utils;
+
+namespace AppConv.Units{
+    internal class Length : DecimalUnitConverterSimple<Length.Units>{
+        internal enum Units{
+            Invalid = 0, Meter, Inch, Foot, Yard, Mile
+        }
+
+        private static readonly string[] NamesInch = { "in", "inch", "inches", "\"", "''" };
+        private static readonly string[] NamesFoot = { "ft", "foot", "feet", "'" };
+
+        public Length(){
+            AddUnit(Units.Meter, "m", "meter", "metre", "meters", "metres");
+            AddUnit(Units.Inch, NamesInch);
+            AddUnit(Units.Foot, NamesFoot);
+            AddUnit(Units.Yard, "yd", "yard", "yards");
+            AddUnit(Units.Mile, "mi", "mile", "miles");
+
+            SetUnitFactor(Units.Inch, 39.37007874M);
+            SetUnitFactor(Units.Foot, 3.280839895M);
+            SetUnitFactor(Units.Yard, 1.093613298M);
+            SetUnitFactor(Units.Mile, 0.0006213711922M);
+
+            SetInvalidUnitObject(Units.Invalid);
+
+            SI.AddSupport(typeof(Units), Units.Meter, new []{ "m" }, new []{ "meter", "metre", "meters", "metres" }, ConvertFrom, ConvertTo, Names);
+        }
+
+        protected override string ProcessSrc(string src){
+            string updatedStr = src;
+
+            updatedStr = updatedStr.Replace("&", " ");
+            updatedStr = updatedStr.Replace(",", " ");
+
+            string inchName = NamesInch.FirstOrDefault(name => src.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1);
+
+            if (inchName == null){
+                return src;
+            }
+
+            int inchIndex = src.IndexOf(inchName, StringComparison.OrdinalIgnoreCase);
+            updatedStr = updatedStr.Remove(inchIndex, inchName.Length).Insert(inchIndex, new string(' ', inchName.Length));
+
+            string footName = NamesFoot.FirstOrDefault(name => updatedStr.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1);
+
+            if (footName == null){
+                return src;
+            }
+
+            int footIndex = updatedStr.IndexOf(footName, StringComparison.OrdinalIgnoreCase);
+            updatedStr = updatedStr.Remove(footIndex, footName.Length).Insert(footIndex, new string(' ', footName.Length));
+
+            string[] tokens = updatedStr.Split(new char[]{ ' ' }, StringSplitOptions.RemoveEmptyEntries);
+            decimal[] numbers = new decimal[2];
+            int numberIndex = 0;
+
+            foreach(string token in tokens){
+                decimal number;
+
+                if (decimal.TryParse(token.Trim(), NumberStyle, CultureInfo.InvariantCulture, out number)){
+                    if (numberIndex < numbers.Length){
+                        numbers[numberIndex++] = number;
+                    }
+                    else{
+                        return src;
+                    }
+                }
+            }
+
+            if (numberIndex != numbers.Length){
+                return src;
+            }
+
+            decimal srcFeet = numbers[footIndex < inchIndex ? 0 : 1];
+            decimal srcInches = numbers[inchIndex < footIndex ? 0 : 1];
+
+            return srcInches+srcFeet*12M+" in";
+        }
+    }
+}
diff --git a/AppConv/Units/Radix.cs b/AppConv/Units/Radix.cs
new file mode 100644
index 0000000..7fca362
--- /dev/null
+++ b/AppConv/Units/Radix.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AppConv.General;
+using AppConv.Utils;
+using Base;
+
+namespace AppConv.Units{
+    internal class Radix : IUnitType{
+        private static readonly Dictionary<string, int> RadixDescriptions = new Dictionary<string, int>{
+            { "UNARY", 1 },
+            { "BINARY", 2 },
+            { "BIN", 2 },
+            { "TERNARY", 3 },
+            { "QUATERNARY", 4 },
+            { "QUINARY", 5 },
+            { "SENARY", 6 },
+            { "OCTAL", 8 },
+            { "OCT", 8 },
+            { "DECIMAL", 10 },
+            { "DEC", 10 },
+            { "UNDECIMAL", 11 },
+            { "DUODECIMAL", 12 },
+            { "DOZENAL", 12 },
+            { "TRIDECIMAL", 13 },
+            { "TETRADECIMAL", 14 },
+            { "PENTADECIMAL", 15 },
+            { "HEXADECIMAL", 16 },
+            { "HEX", 16 }
+        };
+
+        static Radix(){
+            for(int baseNumber = 1; baseNumber <= 16; baseNumber++){
+                RadixDescriptions.Add("RADIX "+baseNumber, baseNumber);
+                RadixDescriptions.Add("BASE "+baseNumber, baseNumber);
+            }
+        }
+
+        public bool TryProcess(string src, string dst, out string result){
+            int targetBase;
+
+            if (!RadixDescriptions.TryGetValue(dst.ToUpperInvariant(), out targetBase)){
+                result = string.Empty;
+                return false;
+            }
+
+            string contents;
+            int sourceBase;
+
+            if (!ParseSrc(src, out contents, out sourceBase)){
+                result = string.Empty;
+                return false;
+            }
+
+            if (contents[0] == '-'){
+                throw new CommandException("Negative numbers are not supported.");
+            }
+            else if (!RadixConversion.IsBaseValid(sourceBase) || !RadixConversion.IsBaseValid(targetBase)){
+                throw new CommandException("Only bases between 1 and 16 allowed.");
+            }
+            else if (!RadixConversion.IsNumberValid(contents, sourceBase)){
+                throw new CommandException("The input is not a valid base "+sourceBase+" number: "+contents);
+            }
+
+            if (sourceBase == targetBase){
+                result = src;
+                return true;
+            }
+
+            try{
+                result = RadixConversion.Do(contents, sourceBase, targetBase);
+            }catch(OverflowException){
+                throw new CommandException("The number has overflown.");
+            }
+
+            return true;
+        }
+
+        private static bool ParseSrc(string src, out string sourceContent, out int sourceBase){
+            if (src.All(chr => chr >= '0' && chr <= '9')){
+                sourceContent = src;
+                sourceBase = 10;
+                return true;
+            }
+
+            string upper = src.ToUpperInvariant();
+
+            if (upper.StartsWith("0X")){
+                sourceContent = upper.Substring(2);
+                sourceBase = 16;
+                return true;
+            }
+
+            if (upper.StartsWith("0B")){
+                sourceContent = upper.Substring(2);
+                sourceBase = 2;
+                return true;
+            }
+
+            int fromIndex = src.IndexOf("FROM", StringComparison.InvariantCultureIgnoreCase);
+
+            if (fromIndex != -1){
+                src = src.Remove(fromIndex, 4);
+            }
+
+            foreach(KeyValuePair<string, int> kvp in RadixDescriptions){
+                if (src.StartsWith(kvp.Key, StringComparison.InvariantCultureIgnoreCase)){
+                    sourceContent = src.Substring(kvp.Key.Length).Trim();
+                    sourceBase = kvp.Value;
+                    return true;
+                }
+                else if (src.EndsWith(kvp.Key, StringComparison.InvariantCultureIgnoreCase)){
+                    sourceContent = src.Substring(0, src.Length-kvp.Key.Length).Trim();
+                    sourceBase = kvp.Value;
+                    return true;
+                }
+            }
+
+            sourceContent = string.Empty;
+            sourceBase = 0;
+            return false;
+        } 
+    }
+}
diff --git a/AppConv/Units/Storage.cs b/AppConv/Units/Storage.cs
new file mode 100644
index 0000000..3addcdc
--- /dev/null
+++ b/AppConv/Units/Storage.cs
@@ -0,0 +1,29 @@
+using System;
+using AppConv.General;
+using AppConv.Utils;
+
+namespace AppConv.Units {
+    internal class Storage : DecimalUnitConverterSimple<Storage.Units>{
+        internal enum Units{
+            Invalid = 0, Byte, Bit
+        }
+
+        public Storage(){
+            AddUnit(Units.Byte, "B", "byte", "bytes");
+            AddUnit(Units.Bit, "b", "bit", "bits");
+
+            SetUnitFactor(Units.Bit, 8M);
+
+            SetInvalidUnitObject(Units.Invalid);
+
+            SI.ExtededProperties bitConversionProperties = new SI.ExtededProperties{
+                FactorPredicate = factor => factor > 0 && factor%3 == 0,
+                FromFunctionGenerator = exponent => () => (decimal)Math.Pow(1024, -(int)(exponent/3)),
+                ToFunctionGenerator = exponent => () => (decimal)Math.Pow(1024, (int)(exponent/3))
+            };
+
+            SI.AddSupportCustom(typeof(Units), Units.Byte, new []{ "B" }, new []{ "byte", "bytes" }, ConvertFrom, ConvertTo, Names, bitConversionProperties);
+            SI.AddSupportCustom(typeof(Units), Units.Bit, new []{ "b" }, new []{ "bit", "bits" }, ConvertFrom, ConvertTo, Names, bitConversionProperties);
+        }
+    }
+}
diff --git a/AppConv/Units/Temperature.cs b/AppConv/Units/Temperature.cs
new file mode 100644
index 0000000..d7d7a97
--- /dev/null
+++ b/AppConv/Units/Temperature.cs
@@ -0,0 +1,102 @@
+using System.Globalization;
+using System.Text.RegularExpressions;
+using AppConv.General;
+using Base.Utils;
+
+namespace AppConv.Units{
+    internal class Temperature : DecimalUnitConverterBase<Temperature.Units>{
+        internal enum Units{
+            Invalid = 0, Celsius, Kelvin, Fahrenheit, Rankine, Delisle, Newton, Reaumur, Romer
+        }
+
+        private static readonly NameMap UnitNames = new NameMap(21){
+            { "C", Units.Celsius },
+            { "Celsius", Units.Celsius },
+            { "K", Units.Kelvin },
+            { "Kelvin", Units.Kelvin },
+            { "F", Units.Fahrenheit },
+            { "Fahrenheit", Units.Fahrenheit },
+            { "R", Units.Rankine },
+            { "Ra", Units.Rankine },
+            { "Rankine", Units.Rankine },
+            { "De", Units.Delisle },
+            { "Delisle", Units.Delisle },
+            { "N", Units.Newton },
+            { "Newton", Units.Newton },
+            { "Re", Units.Reaumur },
+            { "Ré", Units.Reaumur },
+            { "Reaumur", Units.Reaumur },
+            { "Réaumur", Units.Reaumur },
+            { "Ro", Units.Romer },
+            { "Rø", Units.Romer },
+            { "Romer", Units.Romer },
+            { "Rømer", Units.Romer }
+        };
+
+        private static readonly DecimalFuncMap FromCelsius = new DecimalFuncMap(8){
+            { Units.Celsius, val => val },
+            { Units.Kelvin, val => val+273.15M },
+            { Units.Fahrenheit, val => val*1.8M+32M },
+            { Units.Rankine, val => (val+273.15M)*1.8M },
+            { Units.Delisle, val => (100M-val)*1.5M },
+            { Units.Newton, val => val*0.33M },
+            { Units.Reaumur, val => val*0.8M },
+            { Units.Romer, val => val*0.525M+7.5M }
+        };
+
+        private static readonly DecimalFuncMap ToCelsius = new DecimalFuncMap(8){
+            { Units.Celsius, val => val },
+            { Units.Kelvin, val => val-273.15M },
+            { Units.Fahrenheit, val => (val-32M)*5M/9M },
+            { Units.Rankine, val => (val-491.67M)*5M/9M },
+            { Units.Delisle, val => 100M-val*2M/3M },
+            { Units.Newton, val => val*100M/33M },
+            { Units.Reaumur, val => val*1.25M },
+            { Units.Romer, val => (val-7.5M)*40M/21M }
+        };
+
+        private static readonly Regex RegexCleanup = new Regex("deg(?:rees?)?|°", RegexUtils.Text);
+
+        protected override NameMap Names{
+            get{
+                return UnitNames;
+            }
+        }
+
+        protected override DecimalFuncMap ConvertFrom{
+            get{
+                return FromCelsius;
+            }
+        }
+
+        protected override DecimalFuncMap ConvertTo{
+            get{
+                return ToCelsius;
+            }
+        }
+
+        protected override int Precision{
+            get{
+                return 2;
+            }
+        }
+
+        protected override NumberStyles NumberStyle{
+            get{
+                return NumberStyles.Float;
+            }
+        }
+
+        protected override string ProcessSrc(string src){
+            return RegexCleanup.Replace(src, "");
+        }
+
+        protected override string ProcessDst(string dst){
+            return RegexCleanup.Replace(dst, "");
+        }
+
+        protected override bool IsValueInvalid(Units value){
+            return value == Units.Invalid;
+        }
+    }
+}
diff --git a/AppConv/Units/Volume.cs b/AppConv/Units/Volume.cs
new file mode 100644
index 0000000..154b11f
--- /dev/null
+++ b/AppConv/Units/Volume.cs
@@ -0,0 +1,28 @@
+using AppConv.General;
+using AppConv.Utils;
+
+namespace AppConv.Units{
+    internal class Volume : DecimalUnitConverterSimple<Volume.Units>{
+        internal enum Units{
+            Invalid = 0, Liter, CubicMM, CubicCM, CubicDM, CubicM, CubicKM
+        }
+
+        public Volume(){
+            AddUnit(Units.Liter, "l", "liter", "liters", "litre", "litres");
+            AddUnit(Units.CubicMM, "mm3", "cubic mm", "cubic millimeter", "cubic millimeters", "cubic millimetre", "cubic millimetres");
+            AddUnit(Units.CubicCM, "cm3", "cubic cm", "cubic centimeter", "cubic centimeters", "cubic centimetre", "cubic centimetres");
+            AddUnit(Units.CubicDM, "dm3", "cubic dm", "cubic decimeter", "cubic decimeters", "cubic decimetre", "cubic decimetres");
+            AddUnit(Units.CubicM, "m3", "cubic m", "cubic meter", "cubic meters", "cubic metre", "cubic metres");
+            AddUnit(Units.CubicKM, "km3", "cubic km", "cubic kilometer", "cubic kilometers", "cubic kilometre", "cubic kilometres");
+
+            SetUnitFactor(Units.CubicMM, 1000000M);
+            SetUnitFactor(Units.CubicCM, 1000M);
+            SetUnitFactor(Units.CubicM, 0.001M);
+            SetUnitFactor(Units.CubicKM, 1E-12M);
+
+            SetInvalidUnitObject(Units.Invalid);
+
+            SI.AddSupport(typeof(Units), Units.Liter, new []{ "l" }, new []{ "liter", "litre", "liters", "litres" }, ConvertFrom, ConvertTo, Names);
+        }
+    }
+}
diff --git a/AppConv/Units/Weight.cs b/AppConv/Units/Weight.cs
new file mode 100644
index 0000000..35896f8
--- /dev/null
+++ b/AppConv/Units/Weight.cs
@@ -0,0 +1,25 @@
+using AppConv.General;
+using AppConv.Utils;
+
+namespace AppConv.Units {
+    internal class Weight : DecimalUnitConverterSimple<Weight.Units>{
+        internal enum Units{
+            Invalid = 0, Gram, Pound, Ounce, Stone
+        }
+
+        public Weight(){
+            AddUnit(Units.Gram, "g", "gram", "grams");
+            AddUnit(Units.Pound, "lb", "lbs", "pound", "pounds");
+            AddUnit(Units.Ounce, "oz", "ounce", "ounces");
+            AddUnit(Units.Stone, "st", "stone", "stones");
+
+            SetUnitFactor(Units.Pound, 0.0022046226218M);
+            SetUnitFactor(Units.Ounce, 0.03527396195M);
+            SetUnitFactor(Units.Stone, 0.0001574730444177697M);
+
+            SetInvalidUnitObject(Units.Invalid);
+
+            SI.AddSupport(typeof(Units), Units.Gram, new []{ "g" }, new []{ "gram", "grams" }, ConvertFrom, ConvertTo, Names);
+        }
+    }
+}
diff --git a/AppConv/Utils/RadixConversion.cs b/AppConv/Utils/RadixConversion.cs
new file mode 100644
index 0000000..dcdb4ae
--- /dev/null
+++ b/AppConv/Utils/RadixConversion.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+namespace AppConv.Utils{
+    internal static class RadixConversion{
+        private const string Characters = "0123456789ABCDEF";
+
+        public static bool IsBaseValid(int checkedBase){
+            return checkedBase >= 1 && checkedBase <= 16;
+        }
+
+        public static bool IsNumberValid(string contents, int checkedBase){
+            if (checkedBase == 1){
+                return contents.All(chr => chr == '1');
+            }
+
+            if (IsBaseValid(checkedBase)){
+                return contents.Select(chr => Characters.IndexOf(char.ToUpper(chr))).All(index => index != -1 && index < checkedBase);
+            }
+
+            return false;
+        }
+
+        public static string Do(string contents, int fromBase, int toBase){ // TODO biginteger
+            if (fromBase == 1){
+                contents = contents.Length.ToString(CultureInfo.InvariantCulture);
+                fromBase = 10;
+            }
+
+            long wip;
+
+            if (fromBase == 10){
+                wip = long.Parse(contents, NumberStyles.None, CultureInfo.InvariantCulture);
+            }
+            else{
+                wip = 0;
+
+                for(int chr = 0; chr < contents.Length; chr++){
+                    int index = Characters.IndexOf(char.ToUpperInvariant(contents[chr]));
+
+                    if (index > 0){
+                        wip += index*(long)Math.Pow(fromBase, contents.Length-chr-1);
+
+                        if (wip < 0){
+                            throw new OverflowException();
+                        }
+                    }
+                }
+            }
+
+            if (toBase == 1){
+                if (wip <= int.MaxValue){
+                    return new string('1', (int)wip);
+                }
+                else{
+                    throw new OverflowException();
+                }
+            }
+            else if (wip < toBase){
+                return Characters[(int)wip].ToString();
+            }
+            else{
+                StringBuilder converted = new StringBuilder();
+
+                while(wip >= toBase){
+                    int index = (int)(wip%toBase);
+                    converted.Insert(0, Characters[index]);
+
+                    wip = wip/toBase;
+                }
+
+                return converted.Insert(0, Characters[(int)wip]).ToString();
+            }
+        }
+    }
+}
diff --git a/AppConv/Utils/SI.cs b/AppConv/Utils/SI.cs
new file mode 100644
index 0000000..5c027e2
--- /dev/null
+++ b/AppConv/Utils/SI.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using AppConv.General;
+
+namespace AppConv.Utils{
+    internal static class SI{
+        private static readonly List<Tuple<string, string, int>> Factors = new List<Tuple<string, string, int>>{
+            new Tuple<string, string, int>("yotta", "Y", 24),
+            new Tuple<string, string, int>("zetta", "Z", 21),
+            new Tuple<string, string, int>("exa", "E", 18),
+            new Tuple<string, string, int>("peta", "P", 15),
+            new Tuple<string, string, int>("tera", "T", 12),
+            new Tuple<string, string, int>("giga", "G", 9),
+            new Tuple<string, string, int>("mega", "M", 6),
+            new Tuple<string, string, int>("kilo", "k", 3),
+            new Tuple<string, string, int>("hecto", "h", 2),
+            new Tuple<string, string, int>("deca", "da", 1),
+            new Tuple<string, string, int>("deci", "d", -1),
+            new Tuple<string, string, int>("centi", "c", -2),
+            new Tuple<string, string, int>("milli", "m", -3),
+            new Tuple<string, string, int>("micro", "μ", -6),
+            new Tuple<string, string, int>("nano", "n", -9),
+            new Tuple<string, string, int>("pico", "p", -12),
+            new Tuple<string, string, int>("femto", "f", -15),
+            new Tuple<string, string, int>("atto", "a", -18),
+            new Tuple<string, string, int>("zepto", "z", -21),
+            new Tuple<string, string, int>("yocto", "y", -24)
+        };
+
+        public static void AddSupport<T>(Type enumType, T unitObject, string[] unitShortNames, string[] unitLongNames, DecimalUnitConverterBase<T>.DecimalFuncMap funcFrom, DecimalUnitConverterBase<T>.DecimalFuncMap funcTo, DecimalUnitConverterBase<T>.NameMap nameMap) where T : struct{
+            int enumCounter = 1000+Factors.Count*(int)(object)unitObject;
+
+            Func<decimal, decimal> convertFrom = funcFrom[unitObject];
+            Func<decimal, decimal> convertTo = funcTo[unitObject];
+
+            foreach(Tuple<string, string, int> factor in Factors){
+                T enumObject = (T)(object)enumCounter++;
+                int exponent = factor.Item3;
+
+                foreach(string unitShortName in unitShortNames){
+                    nameMap.Add(factor.Item2+unitShortName, enumObject);
+                }
+
+                foreach(string unitLongName in unitLongNames){
+                    nameMap.Add(factor.Item1+unitLongName, enumObject);
+                }
+                
+                funcFrom.Add(enumObject, val => convertFrom(val)*(decimal)Math.Pow(10, -exponent));
+                funcTo.Add(enumObject, val => convertTo(val)*(decimal)Math.Pow(10, exponent));
+            }
+        }
+
+        public static void AddSupportCustom<T>(Type enumType, T unitObject, string[] unitShortNames, string[] unitLongNames, DecimalUnitConverterBase<T>.DecimalFuncMap funcFrom, DecimalUnitConverterBase<T>.DecimalFuncMap funcTo, DecimalUnitConverterBase<T>.NameMap nameMap, ExtededProperties extendedProps) where T : struct{
+            int enumCounter = 1000+Factors.Count*(int)(object)unitObject;
+
+            Func<decimal, decimal> convertFrom = funcFrom[unitObject];
+            Func<decimal, decimal> convertTo = funcTo[unitObject];
+
+            foreach(Tuple<string, string, int> factor in Factors){
+                if (extendedProps.FactorPredicate != null && !extendedProps.FactorPredicate(factor.Item3)){
+                    continue;
+                }
+
+                T enumObject = (T)(object)enumCounter++;
+                int exponent = factor.Item3;
+
+                foreach(string unitShortName in unitShortNames){
+                    nameMap.Add(factor.Item2+unitShortName, enumObject);
+                }
+
+                foreach(string unitLongName in unitLongNames){
+                    nameMap.Add(factor.Item1+unitLongName, enumObject);
+                }
+
+                Func<decimal> genFrom = extendedProps.FromFunctionGenerator(exponent);
+                Func<decimal> genTo = extendedProps.ToFunctionGenerator(exponent);
+                
+                funcFrom.Add(enumObject, val => convertFrom(val)*genFrom());
+                funcTo.Add(enumObject, val => convertTo(val)*genTo());
+            }
+        }
+
+        internal class ExtededProperties{
+            public Predicate<int> FactorPredicate { get; set; }
+            public Func<int, Func<decimal>> FromFunctionGenerator { get; set; }
+            public Func<int, Func<decimal>> ToFunctionGenerator { get; set; }
+        }
+    }
+}
diff --git a/AppMeme/App.cs b/AppMeme/App.cs
new file mode 100644
index 0000000..e85740a
--- /dev/null
+++ b/AppMeme/App.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using Base;
+
+namespace AppMeme{
+    public sealed class App : IApp{
+        private static readonly Dictionary<string, string> Map = new Dictionary<string, string>{
+            { "shrug", @"¯\_(ツ)_/¯" },
+            { "lenny", @"( ͡° ͜ʖ ͡°)" },
+            { "flip", @"(╯°□°)╯︵ ┻━┻" },
+            { "tableflip", @"(╯°□°)╯︵ ┻━┻" }
+        };
+
+        public string[] RecognizedNames => new string[]{
+            "meme"
+        };
+        
+        public MatchConfidence GetConfidence(Command cmd){
+            return Map.ContainsKey(cmd.Text) ? MatchConfidence.Full : MatchConfidence.None;
+        }
+
+        public string ProcessCommand(Command cmd){
+            return Map[cmd.Text];
+        }
+    }
+}
diff --git a/AppMeme/AppMeme.csproj b/AppMeme/AppMeme.csproj
new file mode 100644
index 0000000..2bee676
--- /dev/null
+++ b/AppMeme/AppMeme.csproj
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>AppMeme</RootNamespace>
+    <AssemblyName>AppMeme</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Base\Base.csproj">
+      <Project>{66CF4F71-50DD-4C65-AB96-35D1193FFB50}</Project>
+      <Name>Base</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/AppMeme/Properties/AssemblyInfo.cs b/AppMeme/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..874cb7e
--- /dev/null
+++ b/AppMeme/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// 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("AppMeme")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AppMeme")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6665ef00-1862-4afd-8172-a2c1d0d98141")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/AppWindows/App.cs b/AppWindows/App.cs
new file mode 100644
index 0000000..bd44abd
--- /dev/null
+++ b/AppWindows/App.cs
@@ -0,0 +1,26 @@
+using System.Linq;
+using AppSys.Handlers;
+using Base;
+
+namespace AppSys{
+    public sealed class App : IApp{
+        private static readonly IHandler[] Handlers = {
+            new HandlerProcesses(),
+            new HandlerApps()
+        };
+
+        public string[] RecognizedNames => new string[]{
+            "sys",
+            "os",
+            "win"
+        };
+
+        public MatchConfidence GetConfidence(Command cmd){
+            return Handlers.Any(handler => handler.Matches(cmd)) ? MatchConfidence.Full : MatchConfidence.None;
+        }
+
+        public string ProcessCommand(Command cmd){
+            return Handlers.First(handler => handler.Matches(cmd)).Handle(cmd);
+        }
+    }
+}
diff --git a/AppWindows/AppSys.csproj b/AppWindows/AppSys.csproj
new file mode 100644
index 0000000..f2a8257
--- /dev/null
+++ b/AppWindows/AppSys.csproj
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{E71AFA58-A144-4170-AF7B-05730C04CF59}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>AppSys</RootNamespace>
+    <AssemblyName>AppSys</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App.cs" />
+    <Compile Include="Handlers\HandlerApps.cs" />
+    <Compile Include="Handlers\HandlerProcesses.cs" />
+    <Compile Include="IHandler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Base\Base.csproj">
+      <Project>{66CF4F71-50DD-4C65-AB96-35D1193FFB50}</Project>
+      <Name>Base</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/AppWindows/Handlers/HandlerApps.cs b/AppWindows/Handlers/HandlerApps.cs
new file mode 100644
index 0000000..7fcabba
--- /dev/null
+++ b/AppWindows/Handlers/HandlerApps.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Base;
+
+namespace AppSys.Handlers {
+    internal class HandlerApps : IHandler{
+        private static readonly string PathSystem = Environment.GetFolderPath(Environment.SpecialFolder.System);
+
+        private static readonly Dictionary<string, ProcessStartInfo> Mappings = new Dictionary<string, ProcessStartInfo>{
+            { "audio", new ProcessStartInfo{
+                FileName = Path.Combine(PathSystem, "control.exe"),
+                Arguments = "mmsys.cpl"
+            } },
+
+            { "programs", new ProcessStartInfo{
+                FileName = Path.Combine(PathSystem, "control.exe"),
+                Arguments = "appwiz.cpl"
+            } },
+
+            { "system", new ProcessStartInfo{
+                FileName = Path.Combine(PathSystem, "control.exe"),
+                Arguments = "sysdm.cpl"
+            } },
+
+            { "environment", new ProcessStartInfo{
+                FileName = Path.Combine(PathSystem, "rundll32.exe"),
+                Arguments = "sysdm.cpl,EditEnvironmentVariables"
+            } }
+        };
+
+        private static readonly Dictionary<string, string> Substitutions = new Dictionary<string, string>{
+            { "sounds", "audio" },
+            { "apps", "programs" },
+            { "appwiz", "programs" },
+            { "env", "environment" },
+            { "envvars", "environment" },
+            { "vars", "environment" },
+            { "variables", "environment" }
+        };
+
+        public bool Matches(Command cmd){
+            return Mappings.ContainsKey(cmd.Text) || Substitutions.ContainsKey(cmd.Text);
+        }
+
+        public string Handle(Command cmd){
+            string key;
+
+            if (!Substitutions.TryGetValue(cmd.Text, out key)){
+                key = cmd.Text;
+            }
+
+            using(Process.Start(Mappings[key])){}
+            return null;
+        }
+    }
+}
diff --git a/AppWindows/Handlers/HandlerProcesses.cs b/AppWindows/Handlers/HandlerProcesses.cs
new file mode 100644
index 0000000..68ced96
--- /dev/null
+++ b/AppWindows/Handlers/HandlerProcesses.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Diagnostics;
+using System.Text;
+using Base;
+
+namespace AppSys.Handlers{
+    internal class HandlerProcesses : IHandler{
+        public bool Matches(Command cmd){
+            return cmd.Text.StartsWith("kill ", StringComparison.InvariantCultureIgnoreCase);
+        }
+
+        public string Handle(Command cmd){
+            string[] processNames = cmd.Text.Substring("kill ".Length).Split(',', ';');
+            int succeeded = 0, failed = 0;
+
+            foreach(string processName in processNames){
+                try{
+                    Process[] processes = Process.GetProcessesByName(processName.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase) ? processName.Substring(0, processName.Length-4) : processName);
+
+                    foreach(Process process in processes){
+                        try{
+                            process.Kill();
+                            ++succeeded;
+                        }catch{
+                            ++failed;
+                        }
+
+                        process.Close();
+                    }
+                }catch{
+                    ++failed;
+                }
+            }
+
+            if (succeeded == 0 && failed == 0 && (cmd.Text.Equals("kill me", StringComparison.InvariantCultureIgnoreCase) || cmd.Text.StartsWith("kill me ", StringComparison.InvariantCultureIgnoreCase) || cmd.Text.StartsWith("kill me,", StringComparison.InvariantCultureIgnoreCase))){
+                return "No.";
+            }
+
+            StringBuilder build = new StringBuilder();
+            build.Append("Killed ").Append(succeeded).Append(" process").Append(succeeded == 1 ? "" : "es");
+
+            if (failed > 0){
+                build.Append(", failed ").Append(failed);
+            }
+
+            return build.Append('.').ToString();
+        }
+    }
+}
diff --git a/AppWindows/IHandler.cs b/AppWindows/IHandler.cs
new file mode 100644
index 0000000..f0f0710
--- /dev/null
+++ b/AppWindows/IHandler.cs
@@ -0,0 +1,8 @@
+using Base;
+
+namespace AppSys{
+    internal interface IHandler{
+        bool Matches(Command cmd);
+        string Handle(Command cmd);
+    }
+}
diff --git a/AppWindows/Properties/AssemblyInfo.cs b/AppWindows/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..94ccb76
--- /dev/null
+++ b/AppWindows/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// 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("AppSys")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AppSys")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a4e72ee4-e061-487f-a663-165aca805e55")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Base/Base.csproj b/Base/Base.csproj
new file mode 100644
index 0000000..80bb6e8
--- /dev/null
+++ b/Base/Base.csproj
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{66CF4F71-50DD-4C65-AB96-35D1193FFB50}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Base</RootNamespace>
+    <AssemblyName>Base</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Command.cs" />
+    <Compile Include="CommandEventArgs.cs" />
+    <Compile Include="CommandException.cs" />
+    <Compile Include="IApp.cs" />
+    <Compile Include="MatchConfidence.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utils\RegexUtils.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/Base/Command.cs b/Base/Command.cs
new file mode 100644
index 0000000..d358b2b
--- /dev/null
+++ b/Base/Command.cs
@@ -0,0 +1,44 @@
+using System.Linq;
+using System.Text.RegularExpressions;
+using Base.Utils;
+
+namespace Base{
+    public sealed class Command{
+        private static readonly Regex RegexBalancedBrackets = new Regex(RegexUtils.Balance(@"\[", @"\]"), RegexOptions.Compiled);
+        private static readonly Regex RegexBalancedParentheses = new Regex(RegexUtils.Balance(@"\(", @"\)"), RegexOptions.Compiled);
+
+        public string Text { get; private set; }
+
+        public string PotentialAppName{
+            get{
+               int firstSpace = Text.IndexOf(' ');
+
+                if (firstSpace == -1){
+                    return null;
+                }
+
+                string firstToken = Text.Substring(0, firstSpace);
+
+                if (!firstToken.All(char.IsLetter)){
+                    return null;
+                }
+
+                return firstToken;
+            }
+        }
+
+        public bool IsSingleToken{
+            get{
+                return Text.IndexOf(' ') == -1;
+            }
+        }
+
+        public Command(string text){
+            this.Text = text;
+        }
+
+        public Command ReplaceBrackets(MatchEvaluator evaluator){
+            return new Command(RegexBalancedParentheses.Replace(RegexBalancedBrackets.Replace(Text, evaluator), evaluator));
+        }
+    }
+}
diff --git a/Base/CommandEventArgs.cs b/Base/CommandEventArgs.cs
new file mode 100644
index 0000000..8afae24
--- /dev/null
+++ b/Base/CommandEventArgs.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Base{
+    public class CommandEventArgs : EventArgs{
+        public Command Command { get; private set; }
+
+        public CommandEventArgs(string text){
+            this.Command = new Command(text);
+        }
+    }
+}
diff --git a/Base/CommandException.cs b/Base/CommandException.cs
new file mode 100644
index 0000000..58aa207
--- /dev/null
+++ b/Base/CommandException.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Base{
+    public class CommandException : Exception{
+        public CommandException(string message) : base(message){}
+        public CommandException(string message, Exception innerException) : base(message,innerException){}
+    }
+}
diff --git a/Base/IApp.cs b/Base/IApp.cs
new file mode 100644
index 0000000..57a8a50
--- /dev/null
+++ b/Base/IApp.cs
@@ -0,0 +1,8 @@
+namespace Base{
+    public interface IApp{
+        string[] RecognizedNames { get; }
+
+        MatchConfidence GetConfidence(Command cmd);
+        string ProcessCommand(Command cmd);
+    }
+}
diff --git a/Base/MatchConfidence.cs b/Base/MatchConfidence.cs
new file mode 100644
index 0000000..82b53e3
--- /dev/null
+++ b/Base/MatchConfidence.cs
@@ -0,0 +1,8 @@
+namespace Base{
+    public enum MatchConfidence{
+        None = 0,
+        Low = 1,
+        Possible = 2,
+        Full = 3
+    }
+}
diff --git a/Base/Properties/AssemblyInfo.cs b/Base/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..bfb38eb
--- /dev/null
+++ b/Base/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// 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("Base")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Base")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f7bbfcb0-16a1-47e4-9adb-515cb6d9e5af")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Base/Utils/RegexUtils.cs b/Base/Utils/RegexUtils.cs
new file mode 100644
index 0000000..d02b754
--- /dev/null
+++ b/Base/Utils/RegexUtils.cs
@@ -0,0 +1,23 @@
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Base.Utils{
+    public static class RegexUtils{
+        public static readonly RegexOptions Text = RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled;
+
+        public static string Balance(string escapedStart, string escapedEnd){ // \(((?>[^()]+|\((?<n>)|\)(?<-n>))+(?(n)(?!)))\)
+            return new StringBuilder()
+                .Append(escapedStart)
+                .Append(@"((?>[^")
+                .Append(escapedStart)
+                .Append(escapedEnd)
+                .Append(@"]+|")
+                .Append(escapedStart)
+                .Append(@"(?<n>)|")
+                .Append(escapedEnd)
+                .Append(@"(?<-n>))+(?(n)(?!)))")
+                .Append(escapedEnd)
+                .ToString();
+        }
+    }
+}
diff --git a/Query.sln b/Query.sln
new file mode 100644
index 0000000..4960893
--- /dev/null
+++ b/Query.sln
@@ -0,0 +1,60 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.40629.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Query", "Query\Query.csproj", "{1A2176AF-3885-4619-8F85-4C751A5ABA8F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Base", "Base\Base.csproj", "{66CF4F71-50DD-4C65-AB96-35D1193FFB50}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{6434DC0B-7270-4002-857B-53F8839C9CA6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCalc", "AppCalc\AppCalc.csproj", "{C7A21640-CAF3-40E8-AA6A-793181BD28AA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppConv", "AppConv\AppConv.csproj", "{1AC5280A-81D1-4E02-9122-DB358734FFB4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppMeme", "AppMeme\AppMeme.csproj", "{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppSys", "AppWindows\AppSys.csproj", "{E71AFA58-A144-4170-AF7B-05730C04CF59}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1A2176AF-3885-4619-8F85-4C751A5ABA8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1A2176AF-3885-4619-8F85-4C751A5ABA8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1A2176AF-3885-4619-8F85-4C751A5ABA8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1A2176AF-3885-4619-8F85-4C751A5ABA8F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{66CF4F71-50DD-4C65-AB96-35D1193FFB50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{66CF4F71-50DD-4C65-AB96-35D1193FFB50}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{66CF4F71-50DD-4C65-AB96-35D1193FFB50}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{66CF4F71-50DD-4C65-AB96-35D1193FFB50}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C7A21640-CAF3-40E8-AA6A-793181BD28AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C7A21640-CAF3-40E8-AA6A-793181BD28AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C7A21640-CAF3-40E8-AA6A-793181BD28AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C7A21640-CAF3-40E8-AA6A-793181BD28AA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1AC5280A-81D1-4E02-9122-DB358734FFB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1AC5280A-81D1-4E02-9122-DB358734FFB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1AC5280A-81D1-4E02-9122-DB358734FFB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1AC5280A-81D1-4E02-9122-DB358734FFB4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E71AFA58-A144-4170-AF7B-05730C04CF59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E71AFA58-A144-4170-AF7B-05730C04CF59}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E71AFA58-A144-4170-AF7B-05730C04CF59}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E71AFA58-A144-4170-AF7B-05730C04CF59}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{C7A21640-CAF3-40E8-AA6A-793181BD28AA} = {6434DC0B-7270-4002-857B-53F8839C9CA6}
+		{1AC5280A-81D1-4E02-9122-DB358734FFB4} = {6434DC0B-7270-4002-857B-53F8839C9CA6}
+		{4E27ADC4-FCBE-451E-A1F9-8050DA22A6E1} = {6434DC0B-7270-4002-857B-53F8839C9CA6}
+		{E71AFA58-A144-4170-AF7B-05730C04CF59} = {6434DC0B-7270-4002-857B-53F8839C9CA6}
+	EndGlobalSection
+EndGlobal
diff --git a/Query/Controls/QueryHistoryLog.Designer.cs b/Query/Controls/QueryHistoryLog.Designer.cs
new file mode 100644
index 0000000..2858324
--- /dev/null
+++ b/Query/Controls/QueryHistoryLog.Designer.cs
@@ -0,0 +1,57 @@
+namespace Query.Controls {
+    partial class QueryHistoryLog {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing) {
+            if (disposing && (components != null)) {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component 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.container = new System.Windows.Forms.FlowLayoutPanel();
+            this.SuspendLayout();
+            // 
+            // container
+            // 
+            this.container.AutoScroll = true;
+            this.container.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.container.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
+            this.container.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
+            this.container.Location = new System.Drawing.Point(0, 0);
+            this.container.Name = "container";
+            this.container.Size = new System.Drawing.Size(150, 150);
+            this.container.TabIndex = 0;
+            this.container.WrapContents = false;
+            // 
+            // QueryHistoryLog
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 22F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.Color.Transparent;
+            this.Controls.Add(this.container);
+            this.Font = new System.Drawing.Font("Consolas", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+            this.Name = "QueryHistoryLog";
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.FlowLayoutPanel container;
+    }
+}
diff --git a/Query/Controls/QueryHistoryLog.cs b/Query/Controls/QueryHistoryLog.cs
new file mode 100644
index 0000000..2859b71
--- /dev/null
+++ b/Query/Controls/QueryHistoryLog.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace Query.Controls{
+    sealed partial class QueryHistoryLog : UserControl{
+        public enum EntryType{
+            UserInput, CommandResult, Information, Error
+        }
+
+        private static readonly Dictionary<EntryType, Color> EntryColorMap = new Dictionary<EntryType, Color>{
+            { EntryType.UserInput, Color.FromArgb(160, 160, 160) },
+            { EntryType.CommandResult, Color.FromArgb(240, 240, 240) },
+            { EntryType.Information, Color.FromArgb(160, 255, 140) },
+            { EntryType.Error, Color.FromArgb(255, 40, 40) }
+        };
+
+        public QueryHistoryLog(){
+            InitializeComponent();
+        }
+
+        public void AddEntry(string text, EntryType type){
+            int width = container.Width-SystemInformation.VerticalScrollBarWidth;
+
+            Label label = new Label{
+                AutoSize = true,
+                Font = container.Font,
+                ForeColor = EntryColorMap[type],
+                Text = text,
+                Margin = new Padding(0,1,0,1),
+                MaximumSize = new Size(width, 0),
+                Width = width
+            };
+
+            container.Controls.Add(label);
+            container.AutoScrollPosition = new Point(0, container.VerticalScroll.Maximum);
+        }
+
+        public void ClearEntries(){
+            container.Controls.Clear();
+        }
+    }
+}
diff --git a/Query/Controls/QueryTextBox.Designer.cs b/Query/Controls/QueryTextBox.Designer.cs
new file mode 100644
index 0000000..46234f2
--- /dev/null
+++ b/Query/Controls/QueryTextBox.Designer.cs
@@ -0,0 +1,61 @@
+namespace Query.Controls {
+    partial class QueryTextBox {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing) {
+            if (disposing && (components != null)) {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component 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.tb = new CustomTextBox();
+            this.SuspendLayout();
+            // 
+            // tb
+            // 
+            this.tb.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.tb.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(36)))), ((int)(((byte)(36)))), ((int)(((byte)(36)))));
+            this.tb.BorderStyle = System.Windows.Forms.BorderStyle.None;
+            this.tb.Font = new System.Drawing.Font("Consolas", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+            this.tb.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
+            this.tb.Location = new System.Drawing.Point(5, 6);
+            this.tb.Margin = new System.Windows.Forms.Padding(5);
+            this.tb.Name = "tb";
+            this.tb.Size = new System.Drawing.Size(509, 23);
+            this.tb.TabIndex = 0;
+            // 
+            // QueryTextBox
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(36)))), ((int)(((byte)(36)))), ((int)(((byte)(36)))));
+            this.Controls.Add(this.tb);
+            this.Name = "QueryTextBox";
+            this.Size = new System.Drawing.Size(519, 33);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private CustomTextBox tb;
+    }
+}
diff --git a/Query/Controls/QueryTextBox.cs b/Query/Controls/QueryTextBox.cs
new file mode 100644
index 0000000..38a2013
--- /dev/null
+++ b/Query/Controls/QueryTextBox.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using Base;
+using Query.Core;
+
+namespace Query.Controls{
+    sealed partial class QueryTextBox : UserControl{
+        public event EventHandler<CommandEventArgs> CommandRan;
+
+        private CommandHistory history;
+        private Action<string> log;
+
+        public QueryTextBox(){
+            InitializeComponent();
+        }
+
+        public void Setup(CommandHistory historyObj, Action<string> logFunc){
+            this.history = historyObj;
+            this.log = logFunc;
+        }
+
+        private void OnCommandRan(){
+            CommandRan?.Invoke(this, new CommandEventArgs(tb.Text));
+        }
+
+        private sealed class CustomTextBox : TextBox{
+            private string lastInputStr = string.Empty;
+            private int lastInputPos = 0;
+            
+            private bool doResetHistoryMemory;
+            private bool lastArrowShift;
+            private int historyOffset;
+
+            public CustomTextBox(){
+                TextChanged += CustomTextBox_TextChanged;
+            }
+
+            protected override void OnKeyDown(KeyEventArgs e){
+                QueryTextBox input = (QueryTextBox)Parent;
+                CommandHistory history = input.history;
+
+                Keys key = e.KeyCode;
+                bool handled = false;
+
+                switch(key){
+                    case Keys.Enter:
+                        if (Text != string.Empty){
+                            input.OnCommandRan();
+
+                            Text = string.Empty;
+                            doResetHistoryMemory = true;
+                            handled = true;
+                        }
+
+                        break;
+
+                    case Keys.Up:
+                        if (lastArrowShift != e.Shift){
+                            lastArrowShift = e.Shift;
+                            historyOffset = 0;
+                        }
+                        
+                        --historyOffset;
+                        
+                        if (InsertFromHistory(e.Shift ? history.Results : history.Queries)){
+                            ++historyOffset;
+                        }
+
+                        handled = true;
+                        break;
+
+                    case Keys.Down:
+                        if (lastArrowShift != e.Shift){
+                            lastArrowShift = e.Shift;
+                            historyOffset = 0;
+                        }
+
+                        ++historyOffset;
+                        
+                        if (InsertFromHistory(e.Shift ? history.Results : history.Queries)){
+                            --historyOffset;
+                        }
+
+                        handled = true;
+                        break;
+
+                    case Keys.C:
+                        if (e.Modifiers == Keys.Control){
+                            if (SelectionLength == 0 && history.Results.Count > 0){
+                                Clipboard.SetText(history.Results.Last(), TextDataFormat.UnicodeText);
+                                input.log("Copied to clipboard.");
+                                handled = true;
+                            }
+                        }
+
+                        break;
+                }
+                
+                if (!handled && key != Keys.ControlKey && key != Keys.ShiftKey && key != Keys.Menu){
+                    doResetHistoryMemory = true;
+                }
+                
+                e.Handled = e.SuppressKeyPress = handled;
+                base.OnKeyDown(e);
+            }
+
+            protected override void OnKeyUp(KeyEventArgs e){
+                base.OnKeyUp(e);
+
+                if (doResetHistoryMemory){
+                    doResetHistoryMemory = false;
+                    ResetHistoryMemory();
+                }
+            }
+
+            private void CustomTextBox_TextChanged(object sender, EventArgs e){
+                ResetHistoryMemory();
+            }
+
+            // Management
+
+            private void ResetHistoryMemory(){
+                lastInputStr = Text;
+                lastInputPos = SelectionStart;
+                historyOffset = 0;
+            }
+
+            private bool InsertFromHistory(IList<string> collection){
+                if (collection.Count == 0){
+                    return true;
+                }
+                
+                int index = collection.Count + historyOffset;
+                bool wasClamped = false;
+
+                if (index < 0){
+                    index = 0;
+                    wasClamped = true;
+                }
+                else if (index >= collection.Count){
+                    index = collection.Count - 1;
+                    wasClamped = true;
+                }
+                
+                TextChanged -= CustomTextBox_TextChanged;
+
+                Text = lastInputStr.Insert(lastInputPos, collection[index]);
+                SelectionStart = lastInputPos + collection[index].Length;
+                SelectionLength = 0;
+
+                TextChanged += CustomTextBox_TextChanged;
+                return wasClamped;
+            }
+        }
+    }
+}
diff --git a/Query/Core/CommandHistory.cs b/Query/Core/CommandHistory.cs
new file mode 100644
index 0000000..e715949
--- /dev/null
+++ b/Query/Core/CommandHistory.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+namespace Query.Core{
+    sealed class CommandHistory{
+        private readonly List<string> queries = new List<string>();
+        private readonly List<string> results = new List<string>();
+
+        public IList<string> Queries{
+            get{
+                return queries;
+            }
+        }
+
+        public IList<string> Results{
+            get{
+                return results;
+            }
+        }
+
+        public void AddQuery(string text){
+            queries.Add(text);
+        }
+
+        public void AddResult(string text){
+            results.Add(text);
+        }
+
+        public void Clear(){
+            queries.Clear();
+            results.Clear();
+        }
+    }
+}
diff --git a/Query/Core/CommandProcessor.cs b/Query/Core/CommandProcessor.cs
new file mode 100644
index 0000000..2c1b912
--- /dev/null
+++ b/Query/Core/CommandProcessor.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Base;
+
+namespace Query.Core{
+    sealed class CommandProcessor{
+        private readonly Dictionary<string, IApp> appNames = new Dictionary<string, IApp>(8);
+        private readonly HashSet<IApp> appSet = new HashSet<IApp>();
+        
+        public Func<string, bool> SingleTokenProcessor { get; set; }
+
+        public void AddApp<T>() where T : IApp, new(){
+            IApp app = new T();
+
+            foreach(string name in app.RecognizedNames){
+                appNames.Add(name, app);
+                appSet.Add(app);
+            }
+        }
+
+        public string Run(Command cmd){
+            cmd = cmd.ReplaceBrackets(match => Run(new Command(match.Groups[1].Value)));
+
+            string appName = cmd.PotentialAppName;
+            IApp app;
+            
+            if (appName != null && appNames.TryGetValue(appName.ToLowerInvariant(), out app)){
+                return app.ProcessCommand(new Command(cmd.Text.Substring(appName.Length+1)));
+            }
+
+            if (cmd.IsSingleToken && SingleTokenProcessor != null && SingleTokenProcessor(cmd.Text)){
+                return null;
+            }
+
+            var list = appSet.Select(iapp => new { App = iapp, Confidence = iapp.GetConfidence(cmd) }).OrderByDescending(obj => obj.Confidence).Where(obj => obj.Confidence != MatchConfidence.None).ToList();
+
+            if (list.Count == 0){
+                throw new CommandException("Could not find any suitable app, please write the app name and press Up Arrow.");
+            }
+            else if (list.Count == 1){
+                app = list[0].App;
+            }
+            else{
+                List<IApp> plausible = new List<IApp>{ list[0].App };
+                MatchConfidence topConfidence = list[0].Confidence;
+
+                for(int index = 1; index < list.Count; index++){
+                    if (list[index].Confidence == topConfidence){
+                        plausible.Add(list[index].App);
+                    }
+                }
+
+                if (plausible.Count == 1){
+                    app = plausible.First();
+                }
+                else{
+                    throw new CommandException("Command is ambiguous, please write the app name and press Up Arrow. Suggested apps: "+string.Join(", ",plausible.Select(iapp => iapp.RecognizedNames.First())));
+                }
+            }
+
+            return app.ProcessCommand(cmd);
+        }
+    }
+}
diff --git a/Query/Core/KeyboardHook.cs b/Query/Core/KeyboardHook.cs
new file mode 100644
index 0000000..c282263
--- /dev/null
+++ b/Query/Core/KeyboardHook.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+namespace Query.Core{
+    sealed class KeyboardHook{
+        public event EventHandler Triggered;
+        
+        // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
+        private readonly NativeMethods.HookProc keyboardHookDelegate;
+        private IntPtr keyboardHook;
+        
+        public KeyboardHook(){
+            keyboardHookDelegate = KeyboardHookProc;
+        }
+
+        public void StartHook(){
+            if (keyboardHook != IntPtr.Zero){
+                NativeMethods.UnhookWindowsHookEx(keyboardHook);
+            }
+
+            keyboardHook = NativeMethods.SetWindowsHookEx(NativeMethods.WH_KEYBOARD_LL, keyboardHookDelegate, IntPtr.Zero, 0);
+        }
+
+        public void StopHook(){
+            if (keyboardHook != IntPtr.Zero){
+                NativeMethods.UnhookWindowsHookEx(keyboardHook);
+                keyboardHook = IntPtr.Zero;
+            }
+        }
+
+        private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam){
+            if (wParam == (IntPtr)NativeMethods.WM_KEYDOWN){
+                Keys key = (Keys)Marshal.ReadInt32(lParam);
+
+                if ((key == Keys.LWin || key == Keys.RWin) && Control.ModifierKeys.HasFlag(Keys.Control)){
+                    Triggered?.Invoke(this, EventArgs.Empty);
+                    return NativeMethods.HookHandled;
+                }
+            }
+
+            return NativeMethods.CallNextHookEx(keyboardHook, nCode, wParam, lParam);
+        }
+
+        private static class NativeMethods{
+            public const int WH_KEYBOARD_LL = 13;
+            public const int WM_KEYDOWN = 0x0100;
+            public const int WM_KEYUP = 0x0101;
+
+            public static readonly IntPtr HookHandled = new IntPtr(-1);
+
+            public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
+
+            [DllImport("user32.dll")]
+            public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
+
+            [DllImport("user32.dll")]
+            public static extern bool UnhookWindowsHookEx(IntPtr idHook);
+
+            [DllImport("user32.dll")]
+            public static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
+        }
+    }
+}
diff --git a/Query/MainForm.Designer.cs b/Query/MainForm.Designer.cs
new file mode 100644
index 0000000..90b7ad0
--- /dev/null
+++ b/Query/MainForm.Designer.cs
@@ -0,0 +1,135 @@
+namespace Query {
+    partial class MainForm {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing) {
+            if (disposing && (components != null)) {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #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.components = new System.ComponentModel.Container();
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
+            this.queryLog = new Query.Controls.QueryHistoryLog();
+            this.queryBox = new Query.Controls.QueryTextBox();
+            this.trayIcon = new System.Windows.Forms.NotifyIcon(this.components);
+            this.contextMenuTray = new System.Windows.Forms.ContextMenuStrip(this.components);
+            this.showToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.hookToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.contextMenuTray.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // queryLog
+            // 
+            this.queryLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.queryLog.BackColor = System.Drawing.Color.Transparent;
+            this.queryLog.Font = new System.Drawing.Font("Consolas", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+            this.queryLog.Location = new System.Drawing.Point(5, 5);
+            this.queryLog.Margin = new System.Windows.Forms.Padding(5);
+            this.queryLog.Name = "queryLog";
+            this.queryLog.Size = new System.Drawing.Size(522, 192);
+            this.queryLog.TabIndex = 1;
+            // 
+            // queryBox
+            // 
+            this.queryBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.queryBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(36)))), ((int)(((byte)(36)))), ((int)(((byte)(36)))));
+            this.queryBox.Location = new System.Drawing.Point(0, 202);
+            this.queryBox.Margin = new System.Windows.Forms.Padding(0);
+            this.queryBox.Name = "queryBox";
+            this.queryBox.Size = new System.Drawing.Size(532, 33);
+            this.queryBox.TabIndex = 0;
+            // 
+            // trayIcon
+            // 
+            this.trayIcon.ContextMenuStrip = this.contextMenuTray;
+            this.trayIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("trayIcon.Icon")));
+            this.trayIcon.Text = "Query";
+            this.trayIcon.Visible = true;
+            this.trayIcon.Click += new System.EventHandler(this.trayIcon_Click);
+            // 
+            // contextMenuTray
+            // 
+            this.contextMenuTray.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.showToolStripMenuItem,
+            this.hookToolStripMenuItem,
+            this.exitToolStripMenuItem});
+            this.contextMenuTray.Name = "contextMenuTray";
+            this.contextMenuTray.ShowImageMargin = false;
+            this.contextMenuTray.ShowItemToolTips = false;
+            this.contextMenuTray.Size = new System.Drawing.Size(128, 92);
+            // 
+            // showToolStripMenuItem
+            // 
+            this.showToolStripMenuItem.Name = "showToolStripMenuItem";
+            this.showToolStripMenuItem.Size = new System.Drawing.Size(127, 22);
+            this.showToolStripMenuItem.Text = "Show";
+            this.showToolStripMenuItem.Click += new System.EventHandler(this.showToolStripMenuItem_Click);
+            // 
+            // hookToolStripMenuItem
+            // 
+            this.hookToolStripMenuItem.Name = "hookToolStripMenuItem";
+            this.hookToolStripMenuItem.Size = new System.Drawing.Size(127, 22);
+            this.hookToolStripMenuItem.Text = "Hook";
+            this.hookToolStripMenuItem.Click += new System.EventHandler(this.hookToolStripMenuItem_Click);
+            // 
+            // exitToolStripMenuItem
+            // 
+            this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
+            this.exitToolStripMenuItem.Size = new System.Drawing.Size(127, 22);
+            this.exitToolStripMenuItem.Text = "Exit";
+            this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
+            // 
+            // MainForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+            this.ClientSize = new System.Drawing.Size(532, 235);
+            this.ControlBox = false;
+            this.Controls.Add(this.queryLog);
+            this.Controls.Add(this.queryBox);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.Name = "MainForm";
+            this.ShowInTaskbar = false;
+            this.Text = "Query";
+            this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
+            this.Shown += new System.EventHandler(this.MainForm_Shown);
+            this.contextMenuTray.ResumeLayout(false);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private Query.Controls.QueryTextBox queryBox;
+        private Controls.QueryHistoryLog queryLog;
+        private System.Windows.Forms.NotifyIcon trayIcon;
+        private System.Windows.Forms.ContextMenuStrip contextMenuTray;
+        private System.Windows.Forms.ToolStripMenuItem showToolStripMenuItem;
+        private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
+        private System.Windows.Forms.ToolStripMenuItem hookToolStripMenuItem;
+    }
+}
\ No newline at end of file
diff --git a/Query/MainForm.cs b/Query/MainForm.cs
new file mode 100644
index 0000000..60c7c1d
--- /dev/null
+++ b/Query/MainForm.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using Base;
+using Query.Controls;
+using Query.Core;
+
+namespace Query{
+    partial class MainForm : Form{
+        private readonly CommandProcessor processor;
+        private readonly CommandHistory history;
+
+        private readonly Timer focusTimer;
+        private readonly KeyboardHook keyboardHook;
+
+        private bool isLoaded;
+
+        public MainForm(){
+            InitializeComponent();
+
+            processor = new CommandProcessor{
+                SingleTokenProcessor = ProcessSingleToken
+            };
+
+            processor.AddApp<AppCalc.App>();
+            processor.AddApp<AppConv.App>();
+            processor.AddApp<AppMeme.App>();
+            processor.AddApp<AppSys.App>();
+
+            history = new CommandHistory();
+            queryBox.Setup(history, str => queryLog.AddEntry(str, QueryHistoryLog.EntryType.Information));
+
+            keyboardHook = new KeyboardHook();
+            keyboardHook.Triggered += keyboardHook_Triggered;
+
+            focusTimer = new Timer{
+                Interval = 1
+            };
+
+            focusTimer.Tick += focusTimer_Tick;
+
+            Disposed += MainForm_Disposed;
+            queryBox.CommandRan += queryBox_CommandRan;
+        }
+
+        private void SetShown(bool show){
+            if (show){
+                focusTimer.Start();
+            }
+            else{
+                Hide();
+            }
+        }
+
+        private void MainForm_Shown(object sender, EventArgs e){
+            Rectangle screenRect = Screen.PrimaryScreen.WorkingArea;
+            Location = new Point(screenRect.X + screenRect.Width - Width, screenRect.Y + screenRect.Height - Height);
+
+            if (!isLoaded){
+                isLoaded = true;
+                keyboardHook.StartHook();
+            }
+        }
+
+        private void MainForm_Deactivate(object sender, EventArgs e){
+            SetShown(false);
+        }
+
+        private void MainForm_Disposed(object sender, EventArgs e){
+            keyboardHook.StopHook();
+        }
+
+        private void trayIcon_Click(object sender, EventArgs e){
+            if (((MouseEventArgs)e).Button == MouseButtons.Left){
+                SetShown(true);
+            }
+        }
+
+        private void showToolStripMenuItem_Click(object sender, EventArgs e){
+            SetShown(true);
+        }
+
+        private void hookToolStripMenuItem_Click(object sender, EventArgs e){
+            keyboardHook.StopHook();
+            keyboardHook.StartHook();
+        }
+
+        private void exitToolStripMenuItem_Click(object sender, EventArgs e){
+            Application.Exit();
+        }
+
+        private void keyboardHook_Triggered(object sender, EventArgs e){
+            SetShown(!Visible);
+        }
+
+        private void focusTimer_Tick(object sender, EventArgs e){
+            WindowState = FormWindowState.Minimized;
+            Show();
+            Activate();
+            WindowState = FormWindowState.Normal;
+
+            queryBox.Focus();
+            focusTimer.Stop();
+        }
+
+        private void queryBox_CommandRan(object sender, CommandEventArgs e){
+            try{
+                string result = processor.Run(e.Command);
+                
+                if (result != null){
+                    queryLog.AddEntry("> "+e.Command.Text, QueryHistoryLog.EntryType.UserInput);
+                    history.AddQuery(e.Command.Text);
+
+                    queryLog.AddEntry(result, QueryHistoryLog.EntryType.CommandResult);
+                    history.AddResult(result);
+                }
+            }catch(CommandException ex){
+                queryLog.AddEntry("> "+e.Command.Text, QueryHistoryLog.EntryType.UserInput);
+                history.AddQuery(e.Command.Text);
+
+                queryLog.AddEntry(ex.Message, QueryHistoryLog.EntryType.Error);
+            }
+        }
+
+        private bool ProcessSingleToken(string token){
+            switch(token){
+                case "exit":
+                case "quit":
+                    Application.Exit();
+                    return true;
+
+                case "clear":
+                    queryLog.ClearEntries();
+                    history.Clear();
+                    return true;
+
+                case "hide":
+                    Hide();
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+    }
+}
diff --git a/Query/MainForm.resx b/Query/MainForm.resx
new file mode 100644
index 0000000..a73ff59
--- /dev/null
+++ b/Query/MainForm.resx
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    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">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <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" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </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>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="trayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="contextMenuTray.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>112, 17</value>
+  </metadata>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="trayIcon.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAABAAEAGBgAAAEAIACICQAAFgAAACgAAAAYAAAAMAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAkJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA////
+        ////////QEBA////////////QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA////
+        /////////////0BAQP9AQED/QEBA/0BAQP9AQED/QEBA////////////QEBA////////////QEBA/0BA
+        QP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP////////////////9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA/0BAQP9AQED/////////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA////
+        /////////////0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP////////////////9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/////////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/////////
+        ////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP////////////////9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA////
+        /////////////0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/////////////////QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BA
+        QP////////////////9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/////////////////0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8AAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAA
+        AEEAAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAA
+        AEE=
+</value>
+  </data>
+  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAABAAEAGBgAAAEAIACICQAAFgAAACgAAAAYAAAAMAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAkJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA////
+        ////////QEBA////////////QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA////
+        /////////////0BAQP9AQED/QEBA/0BAQP9AQED/QEBA////////////QEBA////////////QEBA/0BA
+        QP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP////////////////9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA/0BAQP9AQED/////////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA////
+        /////////////0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP////////////////9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/////////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/////////
+        ////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP////////////////9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA////
+        /////////////0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/////////////////QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BA
+        QP////////////////9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/////////////////0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP9AQED/QEBA////////////QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP9AQED/QEBA/0BA
+        QP9AQED/QEBA/0BAQP9AQED/QEBA/0BAQP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQk
+        JP8kJCT/JCQk/yQkJP8kJCT/JCQk/yQkJP8AAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAA
+        AEEAAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAAAEEAAABBAAAAQQAA
+        AEE=
+</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Query/Program.cs b/Query/Program.cs
new file mode 100644
index 0000000..4f388cb
--- /dev/null
+++ b/Query/Program.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Windows.Forms;
+
+namespace Query{
+    static class Program{
+        [STAThread]
+        private static void Main(){
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new MainForm());
+        }
+    }
+}
diff --git a/Query/Properties/AssemblyInfo.cs b/Query/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e87d336
--- /dev/null
+++ b/Query/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// 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("Query")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Query")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4523d47a-d88d-49d9-b4db-b4ae213cd2b8")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Query/Properties/Resources.Designer.cs b/Query/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..01793dd
--- /dev/null
+++ b/Query/Properties/Resources.Designer.cs
@@ -0,0 +1,62 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Query.Properties {
+
+
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if ((resourceMan == null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Query.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}
diff --git a/Query/Properties/Resources.resx b/Query/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Query/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    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">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </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="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <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>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/Query/Properties/Settings.Designer.cs b/Query/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..1d10fe5
--- /dev/null
+++ b/Query/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Query.Properties {
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default {
+            get {
+                return defaultInstance;
+            }
+        }
+    }
+}
diff --git a/Query/Properties/Settings.settings b/Query/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/Query/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>
diff --git a/Query/Query.csproj b/Query/Query.csproj
new file mode 100644
index 0000000..3fbc3f3
--- /dev/null
+++ b/Query/Query.csproj
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1A2176AF-3885-4619-8F85-4C751A5ABA8F}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Query</RootNamespace>
+    <AssemblyName>Query</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Controls\QueryHistoryLog.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Controls\QueryHistoryLog.Designer.cs">
+      <DependentUpon>QueryHistoryLog.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Controls\QueryTextBox.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Controls\QueryTextBox.Designer.cs">
+      <DependentUpon>QueryTextBox.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Core\CommandHistory.cs" />
+    <Compile Include="Core\CommandProcessor.cs" />
+    <Compile Include="MainForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainForm.Designer.cs">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Core\KeyboardHook.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="MainForm.resx">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\AppCalc\AppCalc.csproj">
+      <Project>{c7a21640-caf3-40e8-aa6a-793181bd28aa}</Project>
+      <Name>AppCalc</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\AppConv\AppConv.csproj">
+      <Project>{1ac5280a-81d1-4e02-9122-db358734ffb4}</Project>
+      <Name>AppConv</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\AppMeme\AppMeme.csproj">
+      <Project>{4e27adc4-fcbe-451e-a1f9-8050da22a6e1}</Project>
+      <Name>AppMeme</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\AppWindows\AppSys.csproj">
+      <Project>{e71afa58-a144-4170-af7b-05730c04cf59}</Project>
+      <Name>AppSys</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Base\Base.csproj">
+      <Project>{66cf4f71-50dd-4c65-ab96-35d1193ffb50}</Project>
+      <Name>Base</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/icon.ico b/icon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..bb78ae6944425c2a28ae41cf057531b1e5571142
GIT binary patch
literal 2462
zcmeH}F$#b%3`M`A7Z68>4vrq7-p*Us1QY@io5TtZM!uAgydUGBKu6a&g6<Qx9vA@3
zBuZf+abAm*Qu$@uLC(3fkhbp@Y-ZH><%l~!StHLLKKE%Jk}1y?KG(?5JhXgmKWAUm
z!^)37hld~W@bbMLU*mh<vuA!Un|EpDN7z<=lx^WZVSD&o8<BPY5w>OiDEI8s=Ku58
L?>zk%t#4`v?6?kK

literal 0
HcmV?d00001