diff --git a/DesertPaintLab.csproj b/DesertPaintLab.csproj
--- a/DesertPaintLab.csproj
+++ b/DesertPaintLab.csproj
@@ -72,7 +72,9 @@
     <Compile Include="ScreenCheckDialog.cs" />
     <Compile Include="gtk-gui\DesertPaintLab.ScreenCheckDialog.cs" />
     <Compile Include="FileUtils.cs" />
-    <Compile Include="PaintRecipe.cs" />
+    <Compile Include="PaintRecipe.cs">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Compile>
     <Compile Include="ReactionRecorder.cs" />
     <Compile Include="ReactionStatusWindow.cs" />
     <Compile Include="gtk-gui\DesertPaintLab.ReactionStatusWindow.cs" />
@@ -95,4 +97,16 @@
       </Properties>
     </MonoDevelop>
   </ProjectExtensions>
+  <ItemGroup>
+    <None Include="data\colors.txt">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="data\ingredients.txt">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="data\template\dp_reactions.txt">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="data\template\ingredients.txt" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/PaintRecipe.cs b/PaintRecipe.cs
--- a/PaintRecipe.cs
+++ b/PaintRecipe.cs
@@ -44,6 +44,17 @@ namespace DesertPaintLab
                 this.name = name;
                 this.quantity = quantity;
             }
+
+            public RecipeIngredient(RecipeIngredient other)
+            {
+                this.name = other.name;
+                this.quantity = other.quantity;
+            }
+
+            public override string ToString()
+            {
+                return String.Format("{0} {1}", name, quantity);
+            }
         };
 
         private List<RecipeIngredient> recipe = new List<RecipeIngredient>();
@@ -68,7 +79,24 @@ namespace DesertPaintLab
             }
             foreach (RecipeIngredient copyIngredient in other.recipe)
             {
-                RecipeIngredient ingredient = new RecipeIngredient(copyIngredient.name, copyIngredient.quantity);
+                RecipeIngredient ingredient = new RecipeIngredient(copyIngredient);
+                this.recipe.Add(ingredient);
+            }
+        }
+
+        public void CopyFrom(PaintRecipe other)
+        {
+            this.dirty = true;
+            this.reactions = other.reactions;
+            this.reagents.Clear();
+            foreach (string reagentName in other.reagents)
+            {
+                this.reagents.Add(reagentName);
+            }
+            this.recipe.Clear();
+            foreach (RecipeIngredient otherIngredient in other.recipe)
+            {
+                RecipeIngredient ingredient = new RecipeIngredient(otherIngredient);
                 this.recipe.Add(ingredient);
             }
         }
diff --git a/PlayerProfile.cs b/PlayerProfile.cs
--- a/PlayerProfile.cs
+++ b/PlayerProfile.cs
@@ -59,6 +59,11 @@ namespace DesertPaintLab
 			this.directory = directory;
 			this.reactFile = System.IO.Path.Combine(directory, "dp_reactions.txt");
             this.reagentFile = System.IO.Path.Combine(directory, "ingredients.txt");
+            this.recipes = new SortedDictionary<string, PaintRecipe>();
+            foreach (PaintColor color in Palette.Colors)
+            {
+                this.recipes.Add(color.Name, new PaintRecipe());
+            }
 		}
 
         public string Directory
@@ -88,6 +93,21 @@ namespace DesertPaintLab
                 return this.recipes;
             }
         }
+
+        public int RecipeCount
+        {
+            get {
+                int count = 0;
+                foreach (PaintRecipe recipe in this.recipes.Values)
+                {
+                    if (recipe.IsValid)
+                    {
+                        ++count;
+                    }
+                }
+                return count;
+            }
+        }
 		
 		public void Initialize()
 		{
@@ -318,12 +338,16 @@ namespace DesertPaintLab
 
         public void LoadRecipes()
         {
-            this.recipes = new SortedDictionary<string, PaintRecipe>();
+            foreach (PaintRecipe recipe in this.recipes.Values)
+            {
+                recipe.Clear();
+            }
             string recipeFile = System.IO.Path.Combine(directory, "dp_recipes.txt");
             string line;
             Match match;
             bool inRecipe = false;
-            PaintRecipe recipe = null;
+            PaintRecipe testRecipe = new PaintRecipe();
+            testRecipe.Reactions = reactions;
             string currentRecipeColor = null;
             if (File.Exists(recipeFile))
             {
@@ -334,12 +358,11 @@ namespace DesertPaintLab
                         match = recipeHeaderRegex.Match(line); 
                         if (match.Success)
                         {
-                            if (recipe != null && currentRecipeColor != null)
+                            if (testRecipe != null && currentRecipeColor != null)
                             {
-                                recipes.Add(currentRecipeColor, recipe);
+                                recipes[currentRecipeColor].CopyFrom(testRecipe);
                             }
-                            recipe = new PaintRecipe();
-                            recipe.Reactions = reactions;
+                            testRecipe.Clear();
                             currentRecipeColor = match.Groups["colorname"].Value;
                             inRecipe = true;
                         }
@@ -350,13 +373,13 @@ namespace DesertPaintLab
                             {
                                 string ingredient = match.Groups["ingredient"].Value;
                                 uint quantity = uint.Parse(match.Groups["quantity"].Value);
-                                recipe.AddReagent(ingredient, quantity);
+                                testRecipe.AddReagent(ingredient, quantity);
                             }
                         }
                     }
                     if (inRecipe)
                     {
-                        recipes.Add(currentRecipeColor, recipe);
+                        recipes[currentRecipeColor].CopyFrom(testRecipe);
                     }
                 }
             }
@@ -403,7 +426,7 @@ namespace DesertPaintLab
                     {
                         foreach (PaintRecipe.RecipeIngredient ingredient in recipe.Ingredients)
                         {
-                            colorLine += " " + ingredient.name + " " + ingredient.quantity.ToString();
+                            colorLine += " " + ingredient.ToString();
                         }
                     } 
                     else
@@ -430,7 +453,7 @@ namespace DesertPaintLab
         public void SetRecipe(PaintRecipe recipe)
         {
             string colorName = Palette.FindNearest(recipe.ReactedColor);
-            recipes[colorName] = recipe;
+            recipes[colorName].CopyFrom(recipe);
         }
 	}
 }
diff --git a/RecipeGenerator.cs b/RecipeGenerator.cs
--- a/RecipeGenerator.cs
+++ b/RecipeGenerator.cs
@@ -60,16 +60,25 @@ namespace DesertPaintLab
         protected class SearchNode
         {
             //int initialReagentCount;
-            List<uint> reagents;
-            public List<uint> Reagents
+            uint[] reagents;
+            public uint[] Reagents
             {
                 get
                 {
                     return reagents;
                 }
             }
+            uint INVALID_REAGENT;
+            int nextReagentPos;
+            public int ReagentCount
+            {
+                get
+                {
+                    return nextReagentPos;
+                }
+            }
 
-            HashSet<uint> reagentInUse = new HashSet<uint>();
+            bool[] reagentInUse;
             List<Reagent> costSortedReagents;
             PaintRecipe testRecipe = null;
             public PaintRecipe TestRecipe
@@ -113,16 +122,38 @@ namespace DesertPaintLab
                 }
             }
 
-            public SearchNode(List<Reagent> costSortedReagents, List<uint> reagents)
+            public SearchNode(List<Reagent> costSortedReagents, uint[] reagents)
             {
                 this.costSortedReagents = new List<Reagent>(costSortedReagents);
-                this.reagents = new List<uint>(reagents);
-                foreach (uint reagentIdx in reagents)
+                this.reagents = new uint[costSortedReagents.Count];
+                INVALID_REAGENT = (uint)costSortedReagents.Count;
+                nextReagentPos = reagents.Length;
+                for (int i = this.reagents.Length-1; i >= this.reagents.Length; --i)
+                {
+                    reagents[i] = INVALID_REAGENT;
+                }
+                for (int i = reagents.Length-1; i >= 0; --i)
                 {
-                    reagentInUse.Add(reagentIdx);
+                    this.reagents[i] = reagents[i];
+                    if (reagents[i] == INVALID_REAGENT)
+                    {
+                        nextReagentPos = i;
+                    }
                 }
-                InitialCount = this.reagents.Count;
-                MaxReagents = (uint)this.reagents.Count; // better set this later!
+                reagentInUse = new bool[costSortedReagents.Count];
+                for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
+                {
+                    reagentInUse[reagentIdx] = false;
+                }
+                foreach (uint reagentIdx in this.reagents)
+                {
+                    if (reagentIdx != INVALID_REAGENT)
+                    {
+                        reagentInUse[reagentIdx] = true;
+                    }
+                }
+                InitialCount = nextReagentPos;
+                MaxReagents = (uint)nextReagentPos; // better set this later!
                 UsedQuantity = 0;
             }
 
@@ -130,8 +161,19 @@ namespace DesertPaintLab
             public SearchNode(List<Reagent> costSortedReagents, uint startReagent)
             {
                 this.costSortedReagents = new List<Reagent>(costSortedReagents);
-                this.reagents = new List<uint>();
-                this.reagents.Add(NextFreeReagent(startReagent));
+                this.reagents = new uint[costSortedReagents.Count];
+                INVALID_REAGENT = (uint)costSortedReagents.Count;
+                nextReagentPos = 0;
+                for (int i = 0; i < reagents.Length; ++i)
+                {
+                    this.reagents[i] = INVALID_REAGENT;
+                }
+                reagentInUse = new bool[costSortedReagents.Count];
+                for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
+                {
+                    reagentInUse[reagentIdx] = false;
+                }
+                this.reagents[nextReagentPos++] = NextFreeReagent(startReagent);
                 InitialCount = 1; // don't iterate up beyond the start reagent
                 MaxReagents = 1;
                 UsedQuantity = 0;
@@ -140,8 +182,19 @@ namespace DesertPaintLab
             public SearchNode(List<Reagent> costSortedReagents)
             {
                 this.costSortedReagents = costSortedReagents;
-                this.reagents = new List<uint>();
-                this.reagents.Add(NextFreeReagent(0));
+                this.reagents = new uint[costSortedReagents.Count];
+                INVALID_REAGENT = (uint)costSortedReagents.Count;
+                nextReagentPos = 0;
+                for (int i = 0; i < reagents.Length; ++i)
+                {
+                    this.reagents[i] = INVALID_REAGENT;
+                }
+                reagentInUse = new bool[costSortedReagents.Count];
+                for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
+                {
+                    reagentInUse[reagentIdx] = false;
+                }
+                this.reagents[nextReagentPos++] = NextFreeReagent(0);
                 InitialCount = 0;
                 MaxReagents = 1;
                 UsedQuantity = 0;
@@ -156,26 +209,27 @@ namespace DesertPaintLab
             {
                 get
                 {
-                    return reagents[reagents.Count - 1];
+                    return reagents[nextReagentPos - 1];
                 }
             }
 
             public void RemoveLastReagent()
             {
-                uint reagentIdx = reagents[reagents.Count-1];
+                uint reagentIdx = reagents[nextReagentPos-1];
                 ReleaseReagent(reagentIdx);
                 if (costSortedReagents[(int)reagentIdx].IsCatalyst)
                 {
                     --CatalystCount;
                 }
-                reagents.RemoveAt(reagents.Count-1);
+                reagents[nextReagentPos-1] = INVALID_REAGENT;
+                --nextReagentPos;
             }
 
             public void ReplaceLastReagent(uint reagentIdx)
             {
-                uint oldReagentIdx = reagents[reagents.Count-1];
+                uint oldReagentIdx = reagents[nextReagentPos-1];
                 ReleaseReagent(oldReagentIdx);
-                reagents[reagents.Count-1] = reagentIdx;
+                reagents[nextReagentPos-1] = reagentIdx;
                 if (costSortedReagents[(int)oldReagentIdx].IsCatalyst)
                 {
                     --CatalystCount;
@@ -191,11 +245,11 @@ namespace DesertPaintLab
                 uint idx = startIdx;
                 for (; idx < costSortedReagents.Count; ++idx)
                 {
-                    bool inUse = reagentInUse.Contains(idx);
+                    bool inUse = reagentInUse[idx];
                     if (inUse == false)
                     {
                         //Console.WriteLine("Found free reagent idx {0}", idx);
-                        reagentInUse.Add(idx);
+                        reagentInUse[idx] = true;
                         return idx;
                     }
                 }
@@ -205,16 +259,16 @@ namespace DesertPaintLab
     
             private void ReleaseReagent(uint reagentIdx)
             {
-                reagentInUse.Remove(reagentIdx);
+                reagentInUse[reagentIdx] = false;
             }
     
             public bool AddNextReagent()
             {
-                bool ok = (reagents.Count < MaxReagents);
+                bool ok = (nextReagentPos < MaxReagents);
                 if (ok)
                 {
                     uint nextReagent = NextFreeReagent(0);
-                    reagents.Add(nextReagent);
+                    reagents[nextReagentPos++] = nextReagent;
                     if (costSortedReagents[(int)nextReagent].IsCatalyst)
                     {
                         ++CatalystCount;
@@ -233,9 +287,9 @@ namespace DesertPaintLab
                     return;
                 }
                 UsedQuantity = 0;
-                uint remainingReagents = ((uint)reagents.Count - CatalystCount);
+                uint remainingReagents = ((uint)nextReagentPos - CatalystCount);
                 uint remainingWeight = CurrentTargetQuantity - CatalystCount;
-                for (int i = 0; i < reagents.Count; ++i)
+                for (int i = 0; i < nextReagentPos; ++i)
                 {
                     Reagent reagent = Reagent(i);
     
@@ -266,12 +320,12 @@ namespace DesertPaintLab
             {
                 writer.WriteLine("---SearchNode---");
                 writer.WriteLine("MaxReagents: {0}", MaxReagents);
-                writer.WriteLine("Reagents: {0}", reagents.Count);
-                for (int i = 0; i < reagents.Count; ++i)
+                writer.WriteLine("Reagents: {0}", nextReagentPos);
+                for (int i = 0; i < nextReagentPos; ++i)
                 {
                     uint idx = reagents[i];
                     uint weight = currentWeights[i];
-                    writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse.Contains(idx) ? 1 : 0, weight);
+                    writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse[idx] ? 1 : 0, weight);
                 }
                 // pulled from parent: List<Reagent> costSortedReagents;
                 // new on construct: PaintRecipe testRecipe = null;
@@ -296,7 +350,6 @@ namespace DesertPaintLab
 
                 bool success = true;
                 Match match;
-                int reagentIdx = 0;
                 while ((line = reader.ReadLine()) != null)
                 {
                     if (line.Equals("---EndNode---"))
@@ -310,10 +363,13 @@ namespace DesertPaintLab
                         {
                             case "Reagents":
                                 {
-                                    int reagentCount = int.Parse(match.Groups[2].Value);
-                                    reagents = new List<uint>(reagentCount);
-                                    reagentInUse.Clear();
-                                    reagentIdx = 0;
+                                    //int reagentCount = int.Parse(match.Groups[2].Value);
+                                    for (int i = 0; i < reagents.Length; ++i)
+                                    {
+                                        reagents[i] = INVALID_REAGENT;
+                                        reagentInUse[i] = false;
+                                    }
+                                    nextReagentPos = 0;
                                 }
                                 break;
                             case "Reagent":
@@ -324,12 +380,13 @@ namespace DesertPaintLab
                                         uint reagentId = uint.Parse(reagentInfo.Groups["id"].Value);
                                         int isInUse = int.Parse(reagentInfo.Groups["inUse"].Value);
                                         uint weight = uint.Parse(reagentInfo.Groups["weight"].Value);
-                                        reagents.Add(reagentId);
-                                        currentWeights[reagentIdx] = weight;
+                                        reagents[nextReagentPos] = reagentId;
+                                        currentWeights[nextReagentPos] = weight;
                                         if (isInUse != 0)
                                         {
-                                            reagentInUse.Add(reagentId);
+                                            reagentInUse[reagentId] = true;
                                         }
+                                        ++nextReagentPos;
                                     }
                                     else
                                     {
@@ -425,6 +482,11 @@ namespace DesertPaintLab
         public RecipeGenerator(ReactionSet reactions)
         {
             this.reactions = reactions;
+            foreach (PaintColor color in Palette.Colors)
+            {
+                recipes.Add(color.Name, new PaintRecipe());
+                recipeCosts.Add(color.Name, uint.MaxValue);
+            }
         }
 
         public SortedDictionary<string, PaintRecipe> Recipes
@@ -459,16 +521,16 @@ namespace DesertPaintLab
             }
         }
 
-        public void InitRecipes(SortedDictionary<string, PaintRecipe> recipes)
+        public void InitRecipes(SortedDictionary<string, PaintRecipe> initialRecipes)
         {
             if (running)
             {
                 return;
             }
-            foreach (PaintRecipe recipe in recipes.Values)
+            foreach (PaintRecipe recipe in initialRecipes.Values)
             {
-                PaintRecipe recipeCopy = new PaintRecipe(recipe);
-                AddCheapestRecipe(recipeCopy);
+                //PaintRecipe recipeCopy = new PaintRecipe(recipe);
+                AddCheapestRecipe(recipe);
             }
         }
 
@@ -508,12 +570,13 @@ namespace DesertPaintLab
             // Pre-populate recipes list with:
             // 1) 1-ingredient recipes @ 10db for all enabled ingredients with a count >= 10
             // 2) any previously-generated recipes
+            PaintRecipe recipe = new PaintRecipe();
+            recipe.Reactions = reactions;
             foreach (Reagent reagent in costSortedReagents)
             {
                 if (!reagent.IsCatalyst && reagent.RecipeMax >= 10)
                 {
-                    PaintRecipe recipe = new PaintRecipe();
-                    recipe.Reactions = reactions;
+                    recipe.Clear();
                     recipe.AddReagent(reagent.Name, 10);
                     AddCheapestRecipe(recipe);
                 }
@@ -762,9 +825,8 @@ namespace DesertPaintLab
 
         // Add the cheapest recipe to the recipe list
         // returns the discarded recipe from the pair (or null if no original recipe to replace)
-        private PaintRecipe AddCheapestRecipe(PaintRecipe recipe)
+        private void AddCheapestRecipe(PaintRecipe recipe)
         {
-            PaintRecipe discarded = recipe;
             if (recipe.IsValid)
             {
                 recipe.Reactions = reactions;
@@ -782,9 +844,8 @@ namespace DesertPaintLab
                     {
                         if (cost > recipe.Cost)
                         {
-                            discarded = recipes[colorName];
+                            recipes[colorName].CopyFrom(recipe);
                             recipeCosts[colorName] = recipe.Cost;
-                            recipes[colorName] = recipe;
                             if (NewRecipe != null)
                             {
                                 NewRecipeEventArgs args = new NewRecipeEventArgs(colorName, recipe);
@@ -794,9 +855,9 @@ namespace DesertPaintLab
                     }
                     else
                     {
-                        discarded = null;
+                        // This would be an error!
                         recipeCosts.Add(colorName, recipe.Cost);
-                        recipes.Add(colorName, recipe);
+                        recipes.Add(colorName, new PaintRecipe(recipe));
                         if (NewRecipe != null)
                         {
                             NewRecipeEventArgs args = new NewRecipeEventArgs(colorName, recipe);
@@ -816,8 +877,6 @@ namespace DesertPaintLab
             //        Console.WriteLine(msg);
             //    }
             //}
-            
-            return discarded;
         }
 
         private bool Iterate(SearchNode node)
@@ -845,26 +904,26 @@ namespace DesertPaintLab
             {
                 if (!node.AddNextReagent())
                 {
-                    while ((node.Reagents.Count > node.InitialCount) && (node.LastReagent == (totalReagents-1)))
+                    while ((node.ReagentCount > node.InitialCount) && (node.LastReagent == (totalReagents-1)))
                     {
                         node.RemoveLastReagent();
                     }
-                    if (node.Reagents.Count == node.InitialCount)
+                    if (node.ReagentCount == node.InitialCount)
                     {
                         // done
                         return false;
                     }
                     uint nextReagent = node.NextFreeReagent(node.LastReagent);
-                    while ((node.Reagents.Count > node.InitialCount) && (nextReagent >= totalReagents))
+                    while ((node.ReagentCount > node.InitialCount) && (nextReagent >= totalReagents))
                     {
                         // No more reagents to try at this level
                         node.RemoveLastReagent();
-                        if (node.Reagents.Count > node.InitialCount)
+                        if (node.ReagentCount > node.InitialCount)
                         {
                             nextReagent = node.NextFreeReagent(node.LastReagent);
                         }
                     }
-                    if (node.Reagents.Count == node.InitialCount)
+                    if (node.ReagentCount == node.InitialCount)
                     {
                         // done
                         return false;
@@ -897,20 +956,11 @@ namespace DesertPaintLab
                 node.TestRecipe.Reactions = reactions;
             }
             node.TestRecipe.Clear();
-            for (int i = 0; i < node.Reagents.Count; ++i)
+            for (int i = 0; i < node.ReagentCount; ++i)
             {
                 node.TestRecipe.AddReagent(node.Reagent(i).Name, node.CurrentWeights[i]);
             }
-            PaintRecipe replacement = AddCheapestRecipe(node.TestRecipe);
-            if (replacement == null)
-            {
-                node.TestRecipe = new PaintRecipe();
-                node.TestRecipe.Reactions = reactions;
-            }
-            else
-            {
-                node.TestRecipe = replacement;
-            }
+            AddCheapestRecipe(node.TestRecipe);
             
             // check for the next recipe
             uint remainingWeight = node.CurrentTargetQuantity - node.CatalystCount;
@@ -921,7 +971,7 @@ namespace DesertPaintLab
             }
             //uint remainingReagents = (uint)node.Reagents.Count - node.CatalystCount;
 
-            uint depth = (uint)node.Reagents.Count;
+            uint depth = (uint)node.ReagentCount;
             uint weightToConsume = 0;
             uint spaceBelow = 0;
             int reagentsBelow = 0;
@@ -1010,8 +1060,14 @@ namespace DesertPaintLab
 
         public void Reset()
         {
-            recipes.Clear();
-            recipeCosts.Clear();
+            foreach (PaintRecipe recipe in recipes.Values)
+            {
+                recipe.Clear();
+            }
+            foreach (string key in recipeCosts.Keys)
+            {
+                recipeCosts[key] = uint.MaxValue;
+            }
         }
     }
 }
diff --git a/RecipeGeneratorWindow.cs b/RecipeGeneratorWindow.cs
--- a/RecipeGeneratorWindow.cs
+++ b/RecipeGeneratorWindow.cs
@@ -22,6 +22,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Collections.Concurrent;
 
 namespace DesertPaintLab
 {
@@ -54,6 +55,12 @@ namespace DesertPaintLab
             }
         }
 
+        Gtk.ThreadNotify notifyFinished;
+        Gtk.ThreadNotify notifyProgress;
+        Gtk.ThreadNotify notifyNewRecipe;
+
+        ConcurrentQueue<PaintRecipe> pendingNewRecipes = new ConcurrentQueue<PaintRecipe>();
+
         public RecipeGeneratorWindow(PlayerProfile profile) : base(Gtk.WindowType.Toplevel)
         {
             this.profile = profile;
@@ -84,9 +91,13 @@ namespace DesertPaintLab
             profile.LoadRecipes();
 
             // init UI
-            foreach (string key in profile.Recipes.Keys)
+            foreach (KeyValuePair<string, PaintRecipe> pair in profile.Recipes)
             {
-                colorStore.AppendValues(key);
+                if (pair.Value.IsValid)
+                {
+                    string colorName = pair.Key;
+                    colorStore.AppendValues(colorName);
+                }
             }
 
             canceling = false;
@@ -111,9 +122,13 @@ namespace DesertPaintLab
                     stopResumeButton.Sensitive = true;
                 }
             }
-            countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
+            countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount, Palette.Count);
 
             Destroyed += OnDestroyed;
+
+            notifyFinished = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleFinished));
+            notifyProgress = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleProgress));
+            notifyNewRecipe = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleNewRecipe));
         }
 
         protected void OnMaxIngredientsChanged(object sender, EventArgs e)
@@ -151,7 +166,7 @@ namespace DesertPaintLab
             fullQuantitySpinButton.Sensitive = false;
             fullQuantityDepthSpinButton.Sensitive = false;
 
-            countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
+            countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount, Palette.Count);
 
             // TODO: hook up event notifications
             // - progress
@@ -212,50 +227,58 @@ namespace DesertPaintLab
             }
         }
 
-        protected void OnFinished(object sender, EventArgs args)
+        private void HandleFinished()
         {
-            Gtk.Application.Invoke(delegate {
-                generator.Wait();
-                if (pauseForCheckpoint)
+            generator.Wait();
+            if (pauseForCheckpoint)
+            {
+                pauseForCheckpoint = false;
+                generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
+                generator.ResumeRecipeGeneration();
+            }
+            else
+            {
+                running = false;
+                beginButton.Sensitive = true;
+                ExportToWikiAction.Sensitive = true;
+                IngredientsAction.Sensitive = true;
+                stopResumeButton.Sensitive = false;
+                maxIngredientsSpinButton.Sensitive = true;
+                maxRecipeSpinButton.Sensitive = true;
+                fullQuantitySpinButton.Sensitive = true;
+                fullQuantityDepthSpinButton.Sensitive = true;
+                //generator = null; // don't. Hang on to generator for resume.
+                profile.SaveRecipes();
+                if (canceling)
                 {
-                    pauseForCheckpoint = false;
                     generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
-                    generator.ResumeRecipeGeneration();
+                    stopResumeButton.Label = "Resume";
+                    stopResumeButton.Sensitive = true;
+                    beginButton.Label = "Restart";
                 }
                 else
                 {
-                    running = false;
-                    beginButton.Sensitive = true;
-                    ExportToWikiAction.Sensitive = true;
-                    IngredientsAction.Sensitive = true;
-                    stopResumeButton.Sensitive = false;
-                    maxIngredientsSpinButton.Sensitive = true;
-                    maxRecipeSpinButton.Sensitive = true;
-                    fullQuantitySpinButton.Sensitive = true;
-                    fullQuantityDepthSpinButton.Sensitive = true;
-                    //generator = null; // don't. Hang on to generator for resume.
-                    profile.SaveRecipes();
-                    if (canceling)
-                    {
-                        generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
-                        stopResumeButton.Label = "Resume";
-                        stopResumeButton.Sensitive = true;
-                        beginButton.Label = "Restart";
-                    }
-                    else
-                    {
-                        System.IO.File.Delete(System.IO.Path.Combine(profile.Directory, STATE_FILE));
-                    }
+                    System.IO.File.Delete(System.IO.Path.Combine(profile.Directory, STATE_FILE));
                 }
-            });
+            }
         }
 
-        protected void OnNewRecipe(object sender, NewRecipeEventArgs args)
+        protected void OnFinished(object sender, EventArgs args)
         {
-            PaintRecipe recipe = new PaintRecipe(args.Recipe); // copy it
-            Gtk.Application.Invoke(delegate
+            notifyFinished.WakeupMain();
+            //Gtk.Application.Invoke(delegate {
+            //    HandleFinished();
+            //});
+        }
+
+        private void HandleNewRecipe()
+        {
+            progressBar.Pulse();
+            
+            PaintRecipe recipe = null;
+            if (pendingNewRecipes.TryDequeue(out recipe))
             {
-                progressBar.Pulse();
+                string recipeColor = Palette.FindNearest(recipe.ReactedColor);
                 // TODO: Add item to recipe list only if not already listed
                 bool exists = false;
                 Gtk.TreeIter iter;
@@ -264,7 +287,7 @@ namespace DesertPaintLab
                     do
                     {
                         string color = (string)colorStore.GetValue(iter, 0);
-                        if (color.Equals(args.Color))
+                        if (color.Equals(recipeColor))
                         {
                             exists = true;
                             break;
@@ -276,11 +299,11 @@ namespace DesertPaintLab
                     //Console.WriteLine("Add new recipe for {0}", args.Color);
                     //    bool isMissingReactions = args.Recipe.CheckMissingReactions(ref missingReactions);
                     //    string missingReactionLabel = isMissingReactions ? "X" : "";
-                    colorStore.AppendValues(args.Color); // , missingReactionLabel);
-                    countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
+                    colorStore.AppendValues(recipeColor); // , missingReactionLabel);
+                    countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount+1, Palette.Count);
                 }
                 profile.SetRecipe(recipe);
-
+    
                 long progressTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
                 long delta = progressTime - lastProfileSave;
                 if (delta >= RECIPE_SAVE_INTERVAL)
@@ -288,38 +311,48 @@ namespace DesertPaintLab
                     profile.SaveRecipes();
                     lastProfileSave = progressTime;
                 }
-            });
+            }
+        }
+
+        protected void OnNewRecipe(object sender, NewRecipeEventArgs args)
+        {
+            PaintRecipe recipe = new PaintRecipe(args.Recipe); // copy it, so the worker thread can release
+            lock(this) {
+                pendingNewRecipes.Enqueue(recipe);
+            }
+            notifyNewRecipe.WakeupMain();
+            //Gtk.Application.Invoke(delegate {
+            //    HandleNewRecipe();
+            //});
+        }
+
+        private void HandleProgress()
+        {
+            long progressTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
+            long delta = progressTime - lastProgressUpdate;
+            if (delta > 30)
+            {
+                lastProgressUpdate = progressTime;
+                progressBar.Pulse();
+            }
+            delta = progressTime - lastStatusUpdate;
+            if (delta > 500)
+            {
+                lastStatusUpdate = progressTime;
+                statusLabel.Text = String.Format("Recipes searched: {0:N00}", generator.RecipeCount);
+            }
+            delta = progressTime - lastCheckpoint;
+            if (delta > CHECKPOINT_INTERVAL)
+            {
+                lastCheckpoint = progressTime;
+                pauseForCheckpoint = true;
+                generator.Stop();
+            }
         }
 
         protected void OnProgress(object sender, EventArgs args)
         {
-            Gtk.Application.Invoke(delegate
-            {
-                // TODO: based on time rather than count
-                long progressTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
-                long delta = progressTime - lastProgressUpdate;
-                if (delta > 30)
-                {
-                    progressBar.Pulse();
-                    lastProgressUpdate = progressTime;
-                }
-                delta = progressTime - lastStatusUpdate;
-                if (delta > 500)
-                {
-                    // Update recipe count label as well
-                    statusLabel.Text = String.Format("Recipes searched: {0:N00}", generator.RecipeCount);
-                    lastStatusUpdate = progressTime;
-                }
-                //progressBar.Fraction = (double)((generator.RecipeCount / 10000) % 100) / 100.0;
-
-                delta = progressTime - lastCheckpoint;
-                if (delta > CHECKPOINT_INTERVAL)
-                {
-                    pauseForCheckpoint = true;
-                    lastCheckpoint = progressTime;
-                    generator.Stop();
-                }
-            });
+            notifyProgress.WakeupMain();
         }
 
         protected void OnColorSelected(object o, EventArgs args)
diff --git a/bin/Debug/colors.txt b/bin/Debug/colors.txt
deleted file mode 100644
--- a/bin/Debug/colors.txt
+++ /dev/null
@@ -1,182 +0,0 @@
-#F0F8FF	AliceBlue
-#9966CC	Amethyst
-#FAEBD7	AntiqueWhite
-#00FFFF	Aqua
-#7FFFD4	Aquamarine
-#F0FFFF	Azure
-#FF91AF	BakerMillerPink
-#E3CF57	Banana
-#7C0A02	BarnRed
-#8E388E	Beet
-#F5F5DC	Beige
-#FFE4C4	Bisque
-#010101	Black
-#FFEBCD	BlanchedAlmond
-#FF6700	BlazeOrange
-#0000FF	Blue
-#8A2BE2	BlueViolet
-#873260	Boysenberry
-#FF007F	BrightPink
-#A52A2A	Brown
-#800020	BurgundyRed
-#DEB887	BurlyWood
-#8A360F	BurntSienna
-#8A3324	BurntUmber
-#5F9EA0	CadetBlue
-#FF6103	CadmiumOrange
-#FF9912	CadmiumYellow
-#E07020	Carrot
-#7FFF00	Chartreuse
-#D2691E	Chocolate
-#3D59AB	CobaltBlue
-#3D9140	CobaltGreen
-#FF7F50	Coral
-#6495ED	CornflowerBlue
-#FFF8DC	Cornsilk
-#DC143C	Crimson
-#00008B	DarkBlue
-#008B8B	DarkCyan
-#B8860B	DarkGoldenRod
-#006400	DarkGreen
-#A9A9A9	DarkGrey
-#1A2421	DarkJungleGreen
-#BDB76B	DarkKhaki
-#8B008B	DarkMagenta
-#556B2F	DarkOliveGreen
-#FF8C00	DarkOrange
-#9932CC	DarkOrchid
-#8B0000	DarkRed
-#E9967A	DarkSalmon
-#560319	DarkScarlet
-#8FBC8F	DarkSeaGreen
-#3C1414	DarkSienna
-#483D8B	DarkSlateBlue
-#2F4F4F	DarkSlateGrey
-#00CED1	DarkTurquoise
-#9400D3	DarkViolet
-#FF1493	DeepPink
-#00BFFF	DeepSkyBlue
-#696969	DimGrey
-#1E90FF	DodgerBlue
-#00009C	DukeBlue
-#FCE6C9	EggshellWhite
-#00C957	EmeraldGreen
-#D19275	Feldspar
-#B22222	FireBrick
-#FFFAF0	FloralWhite
-#228B22	ForestGreen
-#FF00FF	Fuchsia
-#DCDCDC	Gainsboro
-#F8F8FF	GhostWhite
-#FFD700	Gold
-#DAA520	GoldenRod
-#008000	Green
-#ADFF2F	GreenYellow
-#808080	Grey
-#F0FFF0	HoneyDew
-#FF69B4	HotPink
-#002395	ImperialBlue
-#CD5C5C	IndianRed
-#4B0082	Indigo
-#FFFFF0	Ivory
-#F0E68C	Khaki
-#E6E6FA	Lavender
-#FFF0F5	LavenderBlush
-#7CFC00	LawnGreen
-#FFFACD	LemonChiffon
-#1A1110	Licorice
-#ADD8E6	LightBlue
-#F08080	LightCoral
-#E0FFFF	LightCyan
-#FAFAD2	LightGoldenRodYellow
-#90EE90	LightGreen
-#D3D3D3	LightGrey
-#FFB6C1	LightPink
-#FFA07A	LightSalmon
-#20B2AA	LightSeaGreen
-#87CEFA	LightSkyBlue
-#8470FF	LightSlateBlue
-#778899	LightSlateGrey
-#B0C4DE	LightSteelBlue
-#FFFFE0	LightYellow
-#00FF00	Lime
-#32CD32	LimeGreen
-#FAF0E6	Linen
-#800000	Maroon
-#66CDAA	MediumAquaMarine
-#0000CD	MediumBlue
-#BA55D3	MediumOrchid
-#9370DB	MediumPurple
-#3CB371	MediumSeaGreen
-#7B68EE	MediumSlateBlue
-#00FA9A	MediumSpringGreen
-#48D1CC	MediumTurquoise
-#C71585	MediumVioletRed
-#E3A869	Melon
-#191970	MidnightBlue
-#F5FFFA	MintCream
-#FFE4E1	MistyRose
-#FFE4B5	Moccasin
-#FFDEAD	NavajoWhite
-#000080	Navy
-#FDF5E6	OldLace
-#808000	Olive
-#6B8E23	OliveDrab
-#FFA500	Orange
-#FF4500	OrangeRed
-#DA70D6	Orchid
-#002147	OxfordBlue
-#EEE8AA	PaleGoldenRod
-#98FB98	PaleGreen
-#AFEEEE	PaleTurquoise
-#DB7093	PaleVioletRed
-#FFEFD5	PapayaWhip
-#FFDAB9	PeachPuff
-#33A1C9	Peacock
-#32127A	PersianIndigo
-#F77FBE	PersianPink
-#CD853F	Peru
-#FFC0CB	Pink
-#DDA0DD	Plum
-#B0E0E6	PowderBlue
-#003153	PrussianBlue
-#800080	Purple
-#C76114	RawSienna
-#FF0000	Red
-#860111	RedDevil
-#004040	RichBlack
-#BC8F8F	RosyBrown
-#4169E1	RoyalBlue
-#9B111E	RubyRed
-#8B4513	SaddleBrown
-#FA8072	Salmon
-#F4A460	SandyBrown
-#92000A	Sangria
-#308014	SapGreen
-#2E8B57	SeaGreen
-#321414	SealBrown
-#FFF5EE	SeaShell
-#A0522D	Sienna
-#C0C0C0	Silver
-#87CEEB	SkyBlue
-#6A5ACD	SlateBlue
-#708090	SlateGrey
-#100C08	SmokeyBlack
-#FFFAFA	Snow
-#00FF7F	SpringGreen
-#4682B4	SteelBlue
-#CC3366	SteelPink
-#D2B48C	Tan
-#008080	Teal
-#D8BFD8	Thistle
-#FF6347	Tomato
-#40E0D0	Turquoise
-#66023C	TyrianPurple
-#EE82EE	Violet
-#D02090	VioletRed
-#F5DEB3	Wheat
-#FFFFFF	White
-#F5F5F5	WhiteSmoke
-#FFFF00	Yellow
-#9ACD32	YellowGreen
-#0014A8	Zaffre
diff --git a/bin/Debug/ingredients.txt b/bin/Debug/ingredients.txt
deleted file mode 100644
--- a/bin/Debug/ingredients.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-// Desert Paint Lab Ingredients
-// Name | Practical Paint Name | RGB values
-// These should be kept in the order they show up on the paint bench
-
-Cabbage Juice	| Cabbage	| 128, 64, 144
-Carrot		| Carrot	| 224, 112, 32
-Clay		| Clay		| 128, 96, 32
-Dead Tongue	| DeadTongue	| 112, 64, 64
-Toad Skin	| ToadSkin	| 48, 96, 48
-Earth Light	| EarthLight	| 128, 240, 224
-Red Sand	| RedSand	| 144, 16, 24
-Lead		| Lead		| 80, 80, 96
-Silver Powder	| Silver	| 16, 16, 32
-Iron		| Iron		| 96, 48, 32
-Copper		| Copper	| 64, 192, 192
-Sulfur		| Sulfur	| catalyst
-Potash		| Potash	| catalyst
-Lime		| Lime		| catalyst
-Saltpeter	| Saltpeter	| catalyst
diff --git a/bin/Debug/template/dp_reactions.txt b/bin/Debug/template/dp_reactions.txt
deleted file mode 100644
--- a/bin/Debug/template/dp_reactions.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-
\ No newline at end of file
diff --git a/bin/Debug/template/ingredients.txt b/bin/Debug/template/ingredients.txt
deleted file mode 100644
--- a/bin/Debug/template/ingredients.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Ingredients are in the form:
-// Name | RGB values | cost | enabled (Y/N) | bulk/normal | max items per paint (1-20)
-//
-// It is recommended to only change the cost value
-// It is not recommended to set many of the ingredients above 10 per paint
-
-Cabbage		| 128, 64, 144   | 8      | Y | bulk    | 10
-Carrot		| 224, 112, 32   | 8      | Y | bulk    | 10
-Clay		| 128, 96, 32    | 10     | Y | bulk    | 20
-DeadTongue	| 112, 64, 64    | 500    | Y | normal  | 4
-ToadSkin	| 48, 96, 48     | 500    | Y | normal  | 4
-EarthLight	| 128, 240, 224  | 10000  | Y | normal  | 4
-RedSand		| 144, 16, 24    | 4      | Y | bulk    | 20
-Lead		| 80, 80, 96     | 50     | Y | normal  | 6
-Silver		| 16, 16, 32     | 50     | Y | normal  | 6
-Iron		| 96, 48, 32     | 30     | Y | normal  | 8
-Copper		| 64, 192, 192   | 30     | Y | normal  | 8
-Sulfur      | catalyst       | 15     | Y | normal  | 1
-Potash      | catalyst       | 50     | Y | normal  | 1
-Lime        | catalyst       | 20     | Y | normal  | 1
-Saltpeter   | catalyst       | 10     | Y | normal  | 1
diff --git a/bin/Release/colors.txt b/bin/Release/colors.txt
deleted file mode 100644
--- a/bin/Release/colors.txt
+++ /dev/null
@@ -1,182 +0,0 @@
-#F0F8FF	AliceBlue
-#9966CC	Amethyst
-#FAEBD7	AntiqueWhite
-#00FFFF	Aqua
-#7FFFD4	Aquamarine
-#F0FFFF	Azure
-#FF91AF	BakerMillerPink
-#E3CF57	Banana
-#7C0A02	BarnRed
-#8E388E	Beet
-#F5F5DC	Beige
-#FFE4C4	Bisque
-#010101	Black
-#FFEBCD	BlanchedAlmond
-#FF6700	BlazeOrange
-#0000FF	Blue
-#8A2BE2	BlueViolet
-#873260	Boysenberry
-#FF007F	BrightPink
-#A52A2A	Brown
-#800020	BurgundyRed
-#DEB887	BurlyWood
-#8A360F	BurntSienna
-#8A3324	BurntUmber
-#5F9EA0	CadetBlue
-#FF6103	CadmiumOrange
-#FF9912	CadmiumYellow
-#E07020	Carrot
-#7FFF00	Chartreuse
-#D2691E	Chocolate
-#3D59AB	CobaltBlue
-#3D9140	CobaltGreen
-#FF7F50	Coral
-#6495ED	CornflowerBlue
-#FFF8DC	Cornsilk
-#DC143C	Crimson
-#00008B	DarkBlue
-#008B8B	DarkCyan
-#B8860B	DarkGoldenRod
-#006400	DarkGreen
-#A9A9A9	DarkGrey
-#1A2421	DarkJungleGreen
-#BDB76B	DarkKhaki
-#8B008B	DarkMagenta
-#556B2F	DarkOliveGreen
-#FF8C00	DarkOrange
-#9932CC	DarkOrchid
-#8B0000	DarkRed
-#E9967A	DarkSalmon
-#560319	DarkScarlet
-#8FBC8F	DarkSeaGreen
-#3C1414	DarkSienna
-#483D8B	DarkSlateBlue
-#2F4F4F	DarkSlateGrey
-#00CED1	DarkTurquoise
-#9400D3	DarkViolet
-#FF1493	DeepPink
-#00BFFF	DeepSkyBlue
-#696969	DimGrey
-#1E90FF	DodgerBlue
-#00009C	DukeBlue
-#FCE6C9	EggshellWhite
-#00C957	EmeraldGreen
-#D19275	Feldspar
-#B22222	FireBrick
-#FFFAF0	FloralWhite
-#228B22	ForestGreen
-#FF00FF	Fuchsia
-#DCDCDC	Gainsboro
-#F8F8FF	GhostWhite
-#FFD700	Gold
-#DAA520	GoldenRod
-#008000	Green
-#ADFF2F	GreenYellow
-#808080	Grey
-#F0FFF0	HoneyDew
-#FF69B4	HotPink
-#002395	ImperialBlue
-#CD5C5C	IndianRed
-#4B0082	Indigo
-#FFFFF0	Ivory
-#F0E68C	Khaki
-#E6E6FA	Lavender
-#FFF0F5	LavenderBlush
-#7CFC00	LawnGreen
-#FFFACD	LemonChiffon
-#1A1110	Licorice
-#ADD8E6	LightBlue
-#F08080	LightCoral
-#E0FFFF	LightCyan
-#FAFAD2	LightGoldenRodYellow
-#90EE90	LightGreen
-#D3D3D3	LightGrey
-#FFB6C1	LightPink
-#FFA07A	LightSalmon
-#20B2AA	LightSeaGreen
-#87CEFA	LightSkyBlue
-#8470FF	LightSlateBlue
-#778899	LightSlateGrey
-#B0C4DE	LightSteelBlue
-#FFFFE0	LightYellow
-#00FF00	Lime
-#32CD32	LimeGreen
-#FAF0E6	Linen
-#800000	Maroon
-#66CDAA	MediumAquaMarine
-#0000CD	MediumBlue
-#BA55D3	MediumOrchid
-#9370DB	MediumPurple
-#3CB371	MediumSeaGreen
-#7B68EE	MediumSlateBlue
-#00FA9A	MediumSpringGreen
-#48D1CC	MediumTurquoise
-#C71585	MediumVioletRed
-#E3A869	Melon
-#191970	MidnightBlue
-#F5FFFA	MintCream
-#FFE4E1	MistyRose
-#FFE4B5	Moccasin
-#FFDEAD	NavajoWhite
-#000080	Navy
-#FDF5E6	OldLace
-#808000	Olive
-#6B8E23	OliveDrab
-#FFA500	Orange
-#FF4500	OrangeRed
-#DA70D6	Orchid
-#002147	OxfordBlue
-#EEE8AA	PaleGoldenRod
-#98FB98	PaleGreen
-#AFEEEE	PaleTurquoise
-#DB7093	PaleVioletRed
-#FFEFD5	PapayaWhip
-#FFDAB9	PeachPuff
-#33A1C9	Peacock
-#32127A	PersianIndigo
-#F77FBE	PersianPink
-#CD853F	Peru
-#FFC0CB	Pink
-#DDA0DD	Plum
-#B0E0E6	PowderBlue
-#003153	PrussianBlue
-#800080	Purple
-#C76114	RawSienna
-#FF0000	Red
-#860111	RedDevil
-#004040	RichBlack
-#BC8F8F	RosyBrown
-#4169E1	RoyalBlue
-#9B111E	RubyRed
-#8B4513	SaddleBrown
-#FA8072	Salmon
-#F4A460	SandyBrown
-#92000A	Sangria
-#308014	SapGreen
-#2E8B57	SeaGreen
-#321414	SealBrown
-#FFF5EE	SeaShell
-#A0522D	Sienna
-#C0C0C0	Silver
-#87CEEB	SkyBlue
-#6A5ACD	SlateBlue
-#708090	SlateGrey
-#100C08	SmokeyBlack
-#FFFAFA	Snow
-#00FF7F	SpringGreen
-#4682B4	SteelBlue
-#CC3366	SteelPink
-#D2B48C	Tan
-#008080	Teal
-#D8BFD8	Thistle
-#FF6347	Tomato
-#40E0D0	Turquoise
-#66023C	TyrianPurple
-#EE82EE	Violet
-#D02090	VioletRed
-#F5DEB3	Wheat
-#FFFFFF	White
-#F5F5F5	WhiteSmoke
-#FFFF00	Yellow
-#9ACD32	YellowGreen
-#0014A8	Zaffre
diff --git a/bin/Release/ingredients.txt b/bin/Release/ingredients.txt
deleted file mode 100644
--- a/bin/Release/ingredients.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-// Desert Paint Lab Ingredients
-// Name | Practical Paint Name | RGB values
-// These should be kept in the order they show up on the paint bench
-
-Cabbage Juice	| Cabbage	| 128, 64, 144
-Carrot		| Carrot	| 224, 112, 32
-Clay		| Clay		| 128, 96, 32
-Dead Tongue	| DeadTongue	| 112, 64, 64
-Toad Skin	| ToadSkin	| 48, 96, 48
-Earth Light	| EarthLight	| 128, 240, 224
-Red Sand	| RedSand	| 144, 16, 24
-Lead		| Lead		| 80, 80, 96
-Silver Powder	| Silver	| 16, 16, 32
-Iron		| Iron		| 96, 48, 32
-Copper		| Copper	| 64, 192, 192
-Sulfur		| Sulfur	| catalyst
-Potash		| Potash	| catalyst
-Lime		| Lime		| catalyst
-Saltpeter	| Saltpeter	| catalyst
diff --git a/bin/Release/template/dp_reactions.txt b/bin/Release/template/dp_reactions.txt
deleted file mode 100644
--- a/bin/Release/template/dp_reactions.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-
\ No newline at end of file
diff --git a/bin/Release/template/ingredients.txt b/bin/Release/template/ingredients.txt
deleted file mode 100644
--- a/bin/Release/template/ingredients.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Ingredients are in the form:
-// Name | RGB values | cost | enabled (Y/N) | bulk/normal | max items per paint (1-20)
-//
-// It is recommended to only change the cost value
-// It is not recommended to set many of the ingredients above 10 per paint
-
-Cabbage		| 128, 64, 144   | 8      | Y | bulk    | 10
-Carrot		| 224, 112, 32   | 8      | Y | bulk    | 10
-Clay		| 128, 96, 32    | 10     | Y | bulk    | 20
-DeadTongue	| 112, 64, 64    | 500    | Y | normal  | 4
-ToadSkin	| 48, 96, 48     | 500    | Y | normal  | 4
-EarthLight	| 128, 240, 224  | 10000  | Y | normal  | 4
-RedSand		| 144, 16, 24    | 4      | Y | bulk    | 20
-Lead		| 80, 80, 96     | 50     | Y | normal  | 6
-Silver		| 16, 16, 32     | 50     | Y | normal  | 6
-Iron		| 96, 48, 32     | 30     | Y | normal  | 8
-Copper		| 64, 192, 192   | 30     | Y | normal  | 8
-Sulfur      | catalyst       | 15     | Y | normal  | 1
-Potash      | catalyst       | 50     | Y | normal  | 1
-Lime        | catalyst       | 20     | Y | normal  | 1
-Saltpeter   | catalyst       | 10     | Y | normal  | 1
diff --git a/gtk-gui/gui.stetic b/gtk-gui/gui.stetic
--- a/gtk-gui/gui.stetic
+++ b/gtk-gui/gui.stetic
@@ -6,7 +6,7 @@
   </configuration>
   <import>
     <widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
-    <widget-library name="../bin/Release/DesertPaintLab.exe" internal="true" />
+    <widget-library name="../bin/Debug/DesertPaintLab.exe" internal="true" />
   </import>
   <widget class="Gtk.Window" id="MainWindow" design-size="629 265">
     <action-group name="Default">
@@ -1190,7 +1190,7 @@ You can either import an existing Practi
         <child>
           <widget class="Gtk.MenuBar" id="menubar1">
             <property name="MemberName" />
-            <node name="menubar1" type="Menubar">
+            <node name="__gtksharp_64_Stetic_Editor_ActionMenuBar" type="Menubar">
               <node type="Menu" action="ExportAction">
                 <node type="Menuitem" action="ExportToWikiAction" />
               </node>
diff --git a/mac/build-mac-bundle.sh b/mac/build-mac-bundle.sh
--- a/mac/build-mac-bundle.sh
+++ b/mac/build-mac-bundle.sh
@@ -15,9 +15,7 @@ fi
 /bin/chmod 755 bin/DesertPaintLab.app/Contents/MacOS/launcher.sh
 /bin/cp ../bin/Release/DesertPaintLab.exe bin/DesertPaintLab.app/Contents/MacOS/
 /bin/mkdir -p bin/DesertPaintLab.app/Contents/Resources
-/bin/cp ../bin/Release/colors.txt bin/DesertPaintLab.app/Contents/Resources/
-/bin/cp ../bin/Release/ingredients.txt bin/DesertPaintLab.app/Contents/Resources/
-/bin/cp -r ../bin/Release/template bin/DesertPaintLab.app/Contents/Resources/template
+/bin/cp -r ../data bin/DesertPaintLab.app/Contents/Resources/data
 
 /usr/bin/defaults write `pwd`/bin/DesertPaintLab.app/Contents/Info.plist CFBundleShortVersionString ${VERSION}
 /usr/bin/defaults write `pwd`/bin/DesertPaintLab.app/Contents/Info.plist CFBundleVersion ${VERSION}