Quantcast

Moved the files up one directory so that the Curse client can have a properly packaged unit.

pschifferer [01-23-09 - 04:45]
Moved the files up one directory so that the Curse client can have a properly packaged unit.
Filename
.pkgmeta
Artwork/Cauldron-Main-BottomLeft.tga
Artwork/Cauldron-Main-BottomMiddle.tga
Artwork/Cauldron-Main-BottomRight.tga
Artwork/Cauldron-Main-TopLeft.tga
Artwork/Cauldron-Main-TopMiddle.tga
Artwork/Cauldron-Main-TopRight.tga
Artwork/resize.tga
Bindings.xml
Cauldron.toc
Cauldron/Artwork/Cauldron-Main-BottomLeft.tga
Cauldron/Artwork/Cauldron-Main-BottomMiddle.tga
Cauldron/Artwork/Cauldron-Main-BottomRight.tga
Cauldron/Artwork/Cauldron-Main-TopLeft.tga
Cauldron/Artwork/Cauldron-Main-TopMiddle.tga
Cauldron/Artwork/Cauldron-Main-TopRight.tga
Cauldron/Artwork/resize.tga
Cauldron/Bindings.xml
Cauldron/Cauldron.toc
Cauldron/CauldronMain.lua
Cauldron/CauldronMain.xml
Cauldron/CauldronMainUI.lua
Cauldron/CauldronQueue.lua
Cauldron/CauldronShoppingList.lua
Cauldron/CauldronShoppingList.xml
Cauldron/CauldronShoppingListUI.lua
Cauldron/CauldronTradeskill.lua
Cauldron/CauldronUtil.lua
Cauldron/Locale/Cauldron-enUS.lua
Cauldron/embeds.xml
CauldronMain.lua
CauldronMain.xml
CauldronMainUI.lua
CauldronQueue.lua
CauldronShoppingList.lua
CauldronShoppingList.xml
CauldronShoppingListUI.lua
CauldronTradeskill.lua
CauldronUtil.lua
Locale/Cauldron-enUS.lua
embeds.xml
diff --git a/.pkgmeta b/.pkgmeta
index 18e1aa9..6b702e5 100644
--- a/.pkgmeta
+++ b/.pkgmeta
@@ -1,41 +1,41 @@
 package-as: Cauldron
 externals:
-    Cauldron/Libs/LibStub:
+    Libs/LibStub:
         url: svn://svn.wowace.com/wow/libstub/mainline/trunk
         tag: latest
-    Cauldron/Libs/AceAddon-3.0:
+    Libs/AceAddon-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceAddon-3.0
         tag: latest
-    Cauldron/Libs/AceConfig-3.0:
+    Libs/AceConfig-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceConfig-3.0
         tag: latest
-    Cauldron/Libs/AceConsole-3.0:
+    Libs/AceConsole-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceConsole-3.0
         tag: latest
-    Cauldron/Libs/AceDB-3.0:
+    Libs/AceDB-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceDB-3.0
         tag: latest
-    Cauldron/Libs/AceEvent-3.0:
+    Libs/AceEvent-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceEvent-3.0
         tag: latest
-    Cauldron/Libs/AceGUI-3.0:
+    Libs/AceGUI-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceGUI-3.0
         tag: latest
-    Cauldron/Libs/AceHook-3.0:
+    Libs/AceHook-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceHook-3.0
         tag: latest
-    Cauldron/Libs/AceLocale-3.0:
+    Libs/AceLocale-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceLocale-3.0
         tag: latest
-    Cauldron/Libs/AceTimer-3.0:
+    Libs/AceTimer-3.0:
         url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceTimer-3.0
         tag: latest
-    Cauldron/Libs/CallbackHandler-1.0:
+    Libs/CallbackHandler-1.0:
         url: svn://svn.wowace.com/wow/callbackhandler/mainline/trunk/CallbackHandler-1.0
         tag: latest
-    Cauldron/Libs/LibDataBroker-1.1:
+    Libs/LibDataBroker-1.1:
         url: git://github.com/tekkub/libdatabroker-1-1.git
         tag: latest
-    Cauldron/Libs/LibLogger-1.0:
+    Libs/LibLogger-1.0:
         url: svn://svn.wowace.com/wow/liblogger-1-0/mainline/trunk/LibLogger-1.0
         tag: latest
diff --git a/Artwork/Cauldron-Main-BottomLeft.tga b/Artwork/Cauldron-Main-BottomLeft.tga
new file mode 100644
index 0000000..e186b35
Binary files /dev/null and b/Artwork/Cauldron-Main-BottomLeft.tga differ
diff --git a/Artwork/Cauldron-Main-BottomMiddle.tga b/Artwork/Cauldron-Main-BottomMiddle.tga
new file mode 100644
index 0000000..47d3d6e
Binary files /dev/null and b/Artwork/Cauldron-Main-BottomMiddle.tga differ
diff --git a/Artwork/Cauldron-Main-BottomRight.tga b/Artwork/Cauldron-Main-BottomRight.tga
new file mode 100644
index 0000000..ee8538d
Binary files /dev/null and b/Artwork/Cauldron-Main-BottomRight.tga differ
diff --git a/Artwork/Cauldron-Main-TopLeft.tga b/Artwork/Cauldron-Main-TopLeft.tga
new file mode 100644
index 0000000..dbfdc5e
Binary files /dev/null and b/Artwork/Cauldron-Main-TopLeft.tga differ
diff --git a/Artwork/Cauldron-Main-TopMiddle.tga b/Artwork/Cauldron-Main-TopMiddle.tga
new file mode 100644
index 0000000..a3d03f6
Binary files /dev/null and b/Artwork/Cauldron-Main-TopMiddle.tga differ
diff --git a/Artwork/Cauldron-Main-TopRight.tga b/Artwork/Cauldron-Main-TopRight.tga
new file mode 100644
index 0000000..9a56932
Binary files /dev/null and b/Artwork/Cauldron-Main-TopRight.tga differ
diff --git a/Artwork/resize.tga b/Artwork/resize.tga
new file mode 100644
index 0000000..414c368
Binary files /dev/null and b/Artwork/resize.tga differ
diff --git a/Bindings.xml b/Bindings.xml
new file mode 100644
index 0000000..6ba0f4c
--- /dev/null
+++ b/Bindings.xml
@@ -0,0 +1,14 @@
+<!-- $Revision$ -->
+<Bindings>
+	<Binding name="TOGGLE_CAULDRONSHOPPINGLIST" header="CAULDRON">
+       	Cauldron:ShoppingList_Toggle();
+	</Binding>
+	<Binding name="CAULDRONRESET">
+       	Cauldron:Reset();
+	</Binding>
+	<!--
+	<Binding name="TOGGLE_CAULDRONCONFIG">
+       	Cauldron:Config_Toggle();
+	</Binding>
+	-->
+</Bindings>
diff --git a/Cauldron.toc b/Cauldron.toc
new file mode 100755
index 0000000..2e67c8d
--- /dev/null
+++ b/Cauldron.toc
@@ -0,0 +1,35 @@
+## Interface: 30000
+## Title: Cauldron |cff7fff7f -Ace3-|r
+## Version: 0.9.6.$Revision$
+## Author: Caendra of Silver Hand
+## Notes: An improved interface for your trade skills
+## RequiredDeps:
+## OptionalDeps: Ace3, LibStub, LibDataBroker-1.1
+## SavedVariables: CauldronDB
+## SavedVariablesPerCharacter:
+## DefaultState: enabled
+## X-Name: Cauldron
+## X-Category: Tradeskill
+## X-eMail: dm AT critical DASH failure DOT org
+## X-Curse-Packaged-Version: r220
+## X-Curse-Packaged-Version: r27
+## X-Curse-Project-Name: Cauldron
+## X-Curse-Project-ID: cauldron
+## X-Curse-Repository-ID: wow/cauldron/mainline
+
+embeds.xml
+
+Locale\Cauldron-enUS.lua
+
+CauldronMain.lua
+CauldronShoppingList.lua
+CauldronQueue.lua
+CauldronTradeskill.lua
+CauldronUtil.lua
+
+CauldronMainUI.lua
+CauldronShoppingListUI.lua
+
+CauldronMain.xml
+CauldronShoppingList.xml
+
diff --git a/Cauldron/Artwork/Cauldron-Main-BottomLeft.tga b/Cauldron/Artwork/Cauldron-Main-BottomLeft.tga
deleted file mode 100644
index e186b35..0000000
Binary files a/Cauldron/Artwork/Cauldron-Main-BottomLeft.tga and /dev/null differ
diff --git a/Cauldron/Artwork/Cauldron-Main-BottomMiddle.tga b/Cauldron/Artwork/Cauldron-Main-BottomMiddle.tga
deleted file mode 100644
index 47d3d6e..0000000
Binary files a/Cauldron/Artwork/Cauldron-Main-BottomMiddle.tga and /dev/null differ
diff --git a/Cauldron/Artwork/Cauldron-Main-BottomRight.tga b/Cauldron/Artwork/Cauldron-Main-BottomRight.tga
deleted file mode 100644
index ee8538d..0000000
Binary files a/Cauldron/Artwork/Cauldron-Main-BottomRight.tga and /dev/null differ
diff --git a/Cauldron/Artwork/Cauldron-Main-TopLeft.tga b/Cauldron/Artwork/Cauldron-Main-TopLeft.tga
deleted file mode 100644
index dbfdc5e..0000000
Binary files a/Cauldron/Artwork/Cauldron-Main-TopLeft.tga and /dev/null differ
diff --git a/Cauldron/Artwork/Cauldron-Main-TopMiddle.tga b/Cauldron/Artwork/Cauldron-Main-TopMiddle.tga
deleted file mode 100644
index a3d03f6..0000000
Binary files a/Cauldron/Artwork/Cauldron-Main-TopMiddle.tga and /dev/null differ
diff --git a/Cauldron/Artwork/Cauldron-Main-TopRight.tga b/Cauldron/Artwork/Cauldron-Main-TopRight.tga
deleted file mode 100644
index 9a56932..0000000
Binary files a/Cauldron/Artwork/Cauldron-Main-TopRight.tga and /dev/null differ
diff --git a/Cauldron/Artwork/resize.tga b/Cauldron/Artwork/resize.tga
deleted file mode 100644
index 414c368..0000000
Binary files a/Cauldron/Artwork/resize.tga and /dev/null differ
diff --git a/Cauldron/Bindings.xml b/Cauldron/Bindings.xml
deleted file mode 100644
index 6ba0f4c..0000000
--- a/Cauldron/Bindings.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<!-- $Revision$ -->
-<Bindings>
-	<Binding name="TOGGLE_CAULDRONSHOPPINGLIST" header="CAULDRON">
-       	Cauldron:ShoppingList_Toggle();
-	</Binding>
-	<Binding name="CAULDRONRESET">
-       	Cauldron:Reset();
-	</Binding>
-	<!--
-	<Binding name="TOGGLE_CAULDRONCONFIG">
-       	Cauldron:Config_Toggle();
-	</Binding>
-	-->
-</Bindings>
diff --git a/Cauldron/Cauldron.toc b/Cauldron/Cauldron.toc
deleted file mode 100755
index 2e67c8d..0000000
--- a/Cauldron/Cauldron.toc
+++ /dev/null
@@ -1,35 +0,0 @@
-## Interface: 30000
-## Title: Cauldron |cff7fff7f -Ace3-|r
-## Version: 0.9.6.$Revision$
-## Author: Caendra of Silver Hand
-## Notes: An improved interface for your trade skills
-## RequiredDeps:
-## OptionalDeps: Ace3, LibStub, LibDataBroker-1.1
-## SavedVariables: CauldronDB
-## SavedVariablesPerCharacter:
-## DefaultState: enabled
-## X-Name: Cauldron
-## X-Category: Tradeskill
-## X-eMail: dm AT critical DASH failure DOT org
-## X-Curse-Packaged-Version: r220
-## X-Curse-Packaged-Version: r27
-## X-Curse-Project-Name: Cauldron
-## X-Curse-Project-ID: cauldron
-## X-Curse-Repository-ID: wow/cauldron/mainline
-
-embeds.xml
-
-Locale\Cauldron-enUS.lua
-
-CauldronMain.lua
-CauldronShoppingList.lua
-CauldronQueue.lua
-CauldronTradeskill.lua
-CauldronUtil.lua
-
-CauldronMainUI.lua
-CauldronShoppingListUI.lua
-
-CauldronMain.xml
-CauldronShoppingList.xml
-
diff --git a/Cauldron/CauldronMain.lua b/Cauldron/CauldronMain.lua
deleted file mode 100644
index b61feff..0000000
--- a/Cauldron/CauldronMain.lua
+++ /dev/null
@@ -1,714 +0,0 @@
--- $Revision$
--- Cauldron main file
-
-Cauldron = LibStub("AceAddon-3.0"):NewAddon("Cauldron", "AceEvent-3.0", "AceTimer-3.0", "AceConsole-3.0", "AceHook-3.0", "LibLogger-1.0")
-local L = LibStub("AceLocale-3.0"):GetLocale("Cauldron")
-
-Cauldron.version = "0.9.7." .. string.sub("$Revision$", 12, -3);
-Cauldron.date = string.sub("$Date$", 8, 17);
-
--- key binding names
-BINDING_HEADER_CAULDRON = "Cauldron";
-BINDING_NAME_TOGGLE_CAULDRONSHOPPINGLIST = "Toggle Shopping List Window";
-BINDING_NAME_CAULDRONRESET = "Reset Cauldron";
--- BINDING_NAME_TOGGLE_CAULDRONCONFIG = "Toggle Config Window";
-
-Cauldron.options = {};
-Cauldron.options.buttons = {};
-
-Cauldron.vars = {};
-
-Cauldron.libs = {};
--- Cauldron.libs.Abacus = LibStub("LibAbacus-3.0");
--- Cauldron.libs.PT = LibStub("LibPeriodicTable-3.1");
-
--- Cauldron:ToggleDebugLog(false);
-Cauldron:SetLogLevel(Cauldron.logLevels.INFO);
-
-CURRENT_TRADESKILL = "";
-
-function Cauldron:OnInitialize()
-	local dbDefaults = {
-		profile = {
-		},
-		realm = {
-			userdata = {}, -- Stores all known characters
-		},
-		global = {
-			difficulty = {}, -- Stores at what level difficulty is changed for all recipes.
-		}
-	}
-
-	self.db = LibStub("AceDB-3.0"):New("CauldronDB", dbDefaults)
-
-	-- set up slash command options
-	local options = {
-		desc = L["Cauldron"],
-		handler = Cauldron,
-		type = 'group',
-		args = {
-			shoppinglist = {
-				name = L["Shopping list"],
-				desc = L["Open shopping list window"],
-				type = 'toggle',
-			},
-			version = {
-				name = L["Version"],
-				desc = L["Shows the version number of the addon"],
-				type = 'execute',
-				func = function() self:DisplayVersion() end,
-			},
-			reset = {
-				name = L["Reset"],
-				desc = L["Resets Cauldron to a fresh state"],
-				type = 'execute',
-				func = function() self:Reset() end,
-			},
---			debug = LibStub('LibLogDebug-1.0'):GetAce3OptionTable(self, 110),
-		},
-	}
-
-	-- register slash command with options
-	LibStub("AceConfig-3.0"):RegisterOptionsTable("Cauldron", options, {"cauldron"})
-
-	-- let the user know the addon is loaded
-	self:Print(L["Cauldron loaded; version "],Cauldron.version);
-end
-
-function Cauldron:InitPlayer()
-	self:debug("InitPlayer enter");
-
-	if not self.vars.playername then
-		self.vars.playername = UnitName("player");
-		if not self.db.realm.userdata[self.vars.playername] then
-			self.db.realm.userdata[self.vars.playername] = {};
-		end
---		if not self.db.realm.userdata[self.vars.playername].knownRecipes then
---			self.db.realm.userdata[self.vars.playername].knownRecipes = {};
---		end
-		if not self.db.realm.userdata[self.vars.playername].skills then
-			self.db.realm.userdata[self.vars.playername].skills = {};
-		end
-		if not self.db.realm.userdata[self.vars.playername].queue then
-			self.db.realm.userdata[self.vars.playername].queue = CauldronQueue:NewQueue();
-		end
-		if not self.db.realm.shopping then
-			self.db.realm.shopping = CauldronShopping:NewList();
-		end
-	end
-
-	self:debug("InitPlayer exit");
-end
-
-function Cauldron:OnEnable()
-	self:debug("OnEnable enter");
-
-	self:InitPlayer();
-	self:RegisterEvent("TRADE_SKILL_SHOW", "OnTradeShow");
-	self:RegisterEvent("TRADE_SKILL_UPDATE", "OnSkillUpdate");
-	self:RegisterEvent("TRADE_SKILL_CLOSE", "OnTradeClose");
-	self:RegisterEvent("SKILL_LINES_CHANGED", "OnSkillUpdate");
-	self:RegisterEvent("ADDON_LOADED", "OnAddonLoaded");
-	self:RegisterEvent("UNIT_PORTRAIT_UPDATE", "OnEvent");
-	self:RegisterEvent("UPDATE_TRADESKILL_RECAST", "OnTradeSkillRecast");
---	self:RegisterEvent("BANKFRAME_OPENED");
---	self:RegisterEvent("BANKFRAME_CLOSED");
---	self:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
---	self:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED");
---	self:RegisterEvent("MERCHANT_SHOW");
---	self:RegisterEvent("MERCHANT_UPDATE");
---	self:RegisterEvent("MERCHANT_CLOSED");
-	self:RegisterEvent("BAG_UPDATE", "OnBagUpdate");
---	self:RegisterEvent("TRAINER_CLOSED");
---	self:RegisterEvent("PLAYER_REGEN_DISABLED");
---	self:RegisterEvent("PLAYER_REGEN_ENABLED");
---	self:RegisterEvent("AUCTION_HOUSE_CLOSED");
---	self:RegisterEvent("AUCTION_HOUSE_SHOW");
-	self:RegisterEvent("CRAFT_SHOW", "OnCraftShow");
-	self:RegisterEvent("CRAFT_CLOSE", "OnCraftClose");
---	self:RegisterEvent("PLAYER_LOGOUT");
-	self:RegisterEvent("UI_ERROR_MESSAGE", "OnError");
-	self:HookTooltips();
-
-	self:debug("OnEnable exit");
-end
-
-function Cauldron:OnDisable()
-	self:debug("OnDisable enter");
-
-	self:debug("OnDisable exit");
-end
-
-function Cauldron:OnAddonLoaded(event, addon)
-	self:debug("OnAddonLoaded enter");
-
-	-- show the shopping list?
-	if self.db.profile.showShoppingList then
-		Cauldron:ShowShoppingList();
-	else
-		if CauldronShopping:ContainsItems(self.db.realm.shopping) then
-			Cauldron:ShowShoppingList();
-		end
-	end
-
-	self:debug("OnAddonLoaded exit");
-end
-
-function Cauldron:OnEvent(event, ...)
-	self:debug("OnEvent enter");
-
-	if ( event == "UNIT_PORTRAIT_UPDATE" ) then
-		local arg1 = ...;
-		if ( arg1 == "player" ) then
-			SetPortraitTexture(CauldronFramePortrait, "player");
-		end
-	end
-
-	self:debug("OnEvent exit");
-end
-
-function Cauldron:OnTradeShow()
-	self:debug("OnTradeShow enter");
-
-	-- update our known skills
-	self:debug("OnTradeShow: update known skills");
-	self:UpdateSkills();
-
-	-- show the UI frame
-	self:debug("OnTradeShow: show the UI");
-	self:Frame_Show();
-
-	self:debug("OnTradeShow exit");
-end
-
-function Cauldron:OnTradeUpdate()
-	self:debug("OnTradeUpdate enter");
-
---	TODO
-
-	self:debug("OnTradeUpdate exit");
-end
-
-function Cauldron:OnTradeClose()
-	self:debug("OnTradeClose enter");
-
-	self:Frame_Hide();
-
-	self:debug("OnTradeClose exit");
-end
-
-function Cauldron:OnSkillUpdate()
-	self:debug("OnSkillUpdate enter");
-
---	self:UpdateSkills();
---	self:UpdateSpecializations();
-
---	if not IsTradeSkillLinked() then
---		if (GetTradeSkillLine() ~= "UNKNOWN") then
---			self:ScheduleTimer(self.UpdateKnownRecipes, 1, self);
---		end
---	end
-
-	if CURRENT_TRADESKILL ~= "" then
-		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL] then
-			return;
-		end
-
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.selected = 0;
-
-		Cauldron:UpdateSkills();
-		CauldronQueue:CalculateAllRequiredItems();
-	end
-
-	self:Frame_Update();
-
-	self:debug("OnSkillUpdate exit");
-end
-
-function Cauldron:OnTradeSkillRecast()
-	self:debug("OnTradeSkillRecast enter");
-
-	self:UpdateSkills();
-
-	CauldronAmountInputBox:SetNumber(GetTradeskillRepeatCount());
-
-	self:Frame_Update();
-
-	self:debug("OnTradeSkillRecast exit");
-end
-
-function Cauldron:OnBagUpdate()
-	self:debug("OnBagUpdate enter");
-
-	if (not CauldronFrame) or (not CauldronFrame:IsShown()) then
-		return;
-	end
-
-	if self.makingItem then
-		self:debug("OnBagUpdate: self.makingItem="..self.makingItem);
-		local count = GetItemCount(self.makingItem);
-		self:debug("OnBagUpdate: count="..count);
-		self:debug("OnBagUpdate: self.itemCurrentCount="..self.itemCurrentCount);
-		if count ~= self.itemCurrentCount then
-			local delta = self.itemCurrentCount - count; -- TODO: is this necessary?
-			self:debug("OnBagUpdate: delta="..delta);
-			CauldronQueue:AdjustItemCount(Cauldron:GetQueue(), self.queueInfo.name, -1);
-			self.itemCurrentCount = count;
-		end
-	else
-		--
-	end
-
-	-- Cauldron:UpdateSkills();
-
-	self:Frame_Update();
-
-	self:debug("OnBagUpdate exit");
-end
-
-function Cauldron:OnCraftShow()
-	self:debug("OnCraftShow enter");
-
---	TODO
-
-	self:debug("OnCraftShow exit");
-end
-
-function Cauldron:OnCraftClose()
-	self:debug("OnCraftClose enter");
-
---	TODO
-
-	self:debug("OnCraftClose exit");
-end
-
-function Cauldron:OnError()
-	self:debug("OnError enter");
-
---	TODO
-
-	self:debug("OnError exit");
-end
-
-function Cauldron:TradeSkillFrame_SetSelection(id)
-	self:debug("TradeSkillFrame_SetSelection enter");
-
-	-- TODO
-
-	self:debug("TradeSkillFrame_SetSelection exit");
-end
-
-function Cauldron:GetSelectedSkill()
-	self:debug("GetSelectedSkill enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local selected = self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected;
-
-	for name, info in pairs(self.db.realm.userdata[self.vars.playername].skills[skillName].recipes) do
-		if selected == info.index then
-			return info;
-		end
-	end
-
-	self:debug("GetSelectedSkill exit");
-
-	return nil;
-end
-
-function Cauldron:QueueAllTradeSkillItem()
-	self:debug("QueueAllTradeSkillItem enter");
-
-	local skillInfo = Cauldron:GetSelectedSkill();
-
-	if skillInfo then
-		local amount = skillInfo.available;
-		if amount > 0 then
-			CauldronQueue:AddItem(self.db.realm.userdata[self.vars.playername].queue, skillInfo, amount);
-
-			Cauldron:UpdateQueue();
-		else
-			-- TODO: notify player?
-		end
-	end
-
-	self:debug("QueueAllTradeSkillItem exit");
-end
-
-function Cauldron:QueueTradeSkillItem()
-	self:debug("QueueTradeSkillItem enter");
-
-	local skillInfo = Cauldron:GetSelectedSkill();
-
-	if skillInfo then
-		local amount = CauldronAmountInputBox:GetNumber();
-		if not amount or amount < 1 then
-			amount = 1;
-		end
-		CauldronQueue:AddItem(self.db.realm.userdata[self.vars.playername].queue, skillInfo, amount);
-	end
-
-	self:debug("QueueTradeSkillItem exit");
-end
-
-function Cauldron:CreateAllTradeSkillItem()
-	self:debug("CreateAllTradeSkillItem enter");
-
-	if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
-		CauldronAmountInputBox:ClearFocus();
-
-		local skillInfo = Cauldron:GetSelectedSkill();
-
-		CauldronAmountInputBox:SetNumber(skillInfo.available);
-
-		DoTradeSkill(skillInfo.index, skillInfo.available);
-	end
-
-	self:debug("CreateAllTradeSkillItem exit");
-end
-
-function Cauldron:CreateTradeSkillItem()
-	self:debug("CreateTradeSkillItem enter");
-
-	if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
-		CauldronAmountInputBox:ClearFocus();
-
-		local skillInfo = Cauldron:GetSelectedSkill();
-		local amount = CauldronAmountInputBox:GetNumber();
-
-		DoTradeSkill(skillInfo.index, amount);
-	end
-
-	self:debug("CreateTradeSkillItem exit");
-end
-
-function Cauldron:ProcessQueue()
-	self:debug("ProcessQueue enter");
-
-	if IsTradeSkillLinked() then
-		-- TODO: display error/warning
-		return;
-	end
-
-	-- find intermediate items that need to be crafted
-	local intQueue = CauldronQueue:GetIntermediates(self.db.realm.userdata[self.vars.playername].queue);
-	self:debug("ProcessQueue: intQueue="..#intQueue);
-
-	local queueInfo = nil;
-	local skillInfo = nil;
-
-	if #intQueue > 0 then
-		self:debug("ProcessQueue: processing intermediate queue items");
-
-	 	queueInfo = intQueue[1];
-		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
-		skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-		self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));
-	else
-		local queue = CauldronQueue:GetItems(self.db.realm.userdata[self.vars.playername].queue);
-		self:debug("ProcessQueue: queue="..#queue);
-
-		if #queue > 0 then
-			self:debug("ProcessQueue: processing main queue items");
-
-			queueInfo = queue[1];
-			self:debug("ProcessQueue: queueInfo="..queueInfo.name);
-			skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-			self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));
-		end
-	end
-
-	if queueInfo and skillInfo then
-		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
-
-		if queueInfo.tradeskill ~= CURRENT_TRADESKILL then
-			local msg = string.format(L["Crafting %1$s requires the %2$s skill."], queueInfo.name, queueInfo.tradeskill);
-			UIErrorsFrame:AddMessage(msg, 1.0, 0.0, 0.0);
-			return;
-		end
-
-		self:debug("ProcessQueue: process item: "..queueInfo.name);
-		Cauldron:ProcessItem(skillInfo, queueInfo, queueInfo.amount);
-	else
-		if not queueInfo then
-			self:Print("Missing queue info!");
-		end
-		if not skillInfo then
-			self:Print("Missing skill info!");
-		end
-	end
-
-	self:debug("ProcessQueue exit");
-end
-
-
-function Cauldron:ProcessItem(skillInfo, queueInfo, amount)
-	self:debug("ProcessItem enter");
-
-	if (not skillInfo) or (amount < 1) then
-		self:warn("Cauldron:ProcessItem: Missing skill info!");
-		return;
-	end
-
-	if ((not PartialPlayTime()) and (not NoPlayTime())) then
-		-- record the item we're making
-		self.makingItem, _ = GetItemInfo(skillInfo.link);
-		self:debug("ProcessItem: self.makingItem="..self.makingItem);
-		self.itemCurrentCount = GetItemCount(skillInfo.link);
-		self:debug("ProcessItem: self.itemCurrentCount="..self.itemCurrentCount);
-		self.queueInfo = queueInfo;
-
-		-- tell the user what we're doing
-		self:Print(string.format(L["Crafting %1$d of %2$s..."], amount, self.makingItem));
-
-		-- do it
-		DoTradeSkill(skillInfo.index, amount);
-	else
-		-- TODO: notify player?
-	end
-
-	self:debug("ProcessItem exit");
-end
-
-function Cauldron:RemoveQueueItem(name)
-	CauldronQueue:RemoveItem(Cauldron:GetQueue(), name);
-end
-
-function Cauldron:IncreaseItemPriority(name, top)
-	CauldronQueue:IncreasePriority(Cauldron:GetQueue(), name, top);
-end
-
-function Cauldron:DecreaseItemPriority(name, bottom)
-	CauldronQueue:DecreasePriority(Cauldron:GetQueue(), name, bottom);
-end
-
-function Cauldron:DecreaseItemCount(name)
-	CauldronQueue:AdjustItemCount(Cauldron:GetQueue(), name, -1);
-end
-
-function Cauldron:GetQueue(player)
-	self:debug("GetQueue enter");
-
-	if not player then
-		player = self.vars.playername;
-	end
-
-	local queue = self.db.realm.userdata[player].queue;
-	if not queue then
-		queue = CauldronQueue:NewQueue();
-		self.db.realm.userdata[player].queue = queue;
-	end
-
-	self:debug("GetQueue enter");
-
-	return queue;
-end
-
-function Cauldron:AddItemToShoppingList(itemName, amount)
-	CauldronShopping:AddToList(self.db.realm.shopping, self.vars.playername, itemName, amount);
-	Cauldron:ShowShoppingList();
-end
-
-function Cauldron:RemoveShoppingListItem(requestor, itemName)
-	CauldronShopping:RemoveFromList(self.db.realm.shopping, requestor, itemName, nil);
-
---	if not CauldronShopping:ContainsItems(self.db.realm.shopping) then
---		Cauldron:HideShoppingList();
---	end
-end
-
-function Cauldron:LocaleString(str)
-	return L[str];
-end
-
-function Cauldron:DisplayVersion()
-	self:Print(L["Version "],Cauldron.version);
-end
-
-----------------------------------------------------------------
---  Tooltip Functions
-----------------------------------------------------------------
-
-function Cauldron:HookTooltips()
-	self:debug("HookTooltips enter");
-
---	self:SecureHook(GameTooltip, "SetBagItem");
---	self:SecureHook(GameTooltip, "SetInventoryItem");
---	self:SecureHook(GameTooltip, "SetLootItem");
---	self:SecureHook(GameTooltip, "SetHyperlink");
---	self:SecureHook(GameTooltip, "SetTradeSkillItem");
---	self:SecureHook(GameTooltip, "SetMerchantItem");
---	self:SecureHook(GameTooltip, "SetAuctionItem");
---	self:SecureHook(GameTooltip, "SetTrainerService");
---	self:SecureHook(GameTooltip, "SetGuildBankItem");
---	self:SecureHook("SetItemRef");
-
-	self:debug("HookTooltips exit");
-end
-
-----------------------------------------------------------------------
--- Property functions
-----------------------------------------------------------------------
-
---[[ Databroker Stuff --]]
-
-local ldb = LibStub:GetLibrary("LibDataBroker-1.1", true)
-if ldb then
-	ldb:NewDataObject("Cauldron", {
-		type = "launcher",
-		text = "Cauldron shopping list",
-		icon = "Interface\\Icons\\INV_Elemental_Mote_Nether",
-		OnClick = function(frame, button)
-			if button == "LeftButton" then
-				Cauldron:ShowShoppingList();
-			elseif button == "RightButton" then
-				Cauldron:ShoppingList_Toggle();
-			end
-		end,
-		OnTooltipShow = function(tooltip)
-			tooltip:AddLine("Cauldron " .. Cauldron.version)
-		end,
-	})
-end
-
---[[
-	Database table structure:
-
-	["userdata"] = {
-		["<character-name>"] = {
-			["queue"] = {
-				["intermediate"] = {
-					["<skill>"] = {
-						["tradeskill"] = "<tradeskill>", -- human-readable name of the tradeskill that contains this skill
-						["name"] = "<skill>", -- human-readable name of the skill
-						["amount"] = <amount>, -- amount of this skill that must be executed
-						["priority"] = <priority>, -- priority of the skill, for ordering in the queue
-						["icon"] = "<icon>", -- the icon path of the skill, for display
-						["link"] = "<link>",
-					},
-				},
-				["main"] = {
-					["<skill>"] = {
-						["tradeskill"] = "<tradeskill>",
-						["name"] = "<skill>",
-						["amount"] = <amount>,
-						["priority"] = <priority>,
-						["icon"] = "<icon>",
-						["link"] = "<link>",
-					},
-				},
-				["reagents"] = {
-					["<reagent>"] = {
-						["tradeskill"] = "<tradeskill>",
-						["name"] = "<reagent>",
-						["amount"] = <amount>,
-						["icon"] = "<icon>",
-						["link"] = "<link>",
-					},
-				},
-			},
-			["skills"] = {
-				["<tradeskill>"] = {
-					["window"] = { -- window metadata
-						["categories"] = { -- category cache of the tradeskill
-							["<category>"] = { -- name of the category
-								["shown"] = true, -- whether the category is being shown in the skill list
-							},
-							...
-						},
-						["search"] = "", -- search text the user typed in the search box
-						["filter"] = { -- flags for the filter dropdown
-							["sortAlpha"] = false, -- should the list be sorted alphabetically (mutually-exclusive to "sortDifficulty" and "sortBenefit")
-							["sortDifficulty"] = true, -- should the list be sorted by difficulty  (mutually-exclusive to "sortAlpha" and "sortBenefit")
-							["sortBenefit"] = false, -- should the list be sorted by potentcy of the benefit the crafted item/enchantment grants  (mutually-exclusive to "sortDifficulty" and "sortAlpha") UNUSED
-							["haveAllReagents"] = false, -- should only items with all required reagents be shown in the list?
-							["haveKeyReagents"] = false, -- should only items with all key reagents be shown in the list?
-							["haveAnyReagents"] = false, -- should only items with any reagents be shown in the list?
-							["optimal"] = true, -- should optimal skills be shown?
-							["medium"] = true, -- should medium skills be shown?
-							["easy"] = true, -- should easy skills be shown?
-							["trivial"] = false, -- should trivial skills be shown?
-							["favorites"] = false, -- should only favorite skills be shown?
-						},
-						["skills"] = {
-							["<skill>"] = {
-								["expanded"] = false, -- should the skill's reagents be displayed?
-								["favorite"] = false, -- is the skill a favorite?
-							},
-							...
-						},
-						["selected"] = 1, -- skill index of the selected skill (gets reset on skill update events, like skill level increases and training)
-						["slots"] = { -- slot cache
-							["INVTYPE_FEET"] = true,
-							["INVTYPE_BAG"] = true,
-							["INVTYPE_CLOAK"] = true,
-							["(none)"] = true, -- special slot for items that don't have an assigned slot
-							["INVTYPE_WRIST"] = true,
-							["INVTYPE_WAIST"] = true,
-							["INVTYPE_CHEST"] = true,
-							["INVTYPE_LEGS"] = true,
-							["INVTYPE_HAND"] = true,
-						},
-					},
-					["recipes"] = {
-						["<skill>"] = {
-							["index"] = <skill index>,
-							["name"] = "<skill>",
-							["link"] = "<link>",
-							["icon"] = "<icon>",
-							["verb"] = "<verb>", -- this is present for skills that cast, like enchantments
-							["tradeskill"] = "<tradeskill>",
-							["difficulty"] = "<difficulty>",
-							["available"] = <available>,
-							["minMade"] = <min>,
-							["maxMade"] = <max>,
-							["slot"] = "INVTYPE_LEGS",
-							["defaultCategory"] = "<category>",
-							["reagents"] = {
-								{
-									["toonHas"] = <has>, -- how many of this reagent the character has
-									["name"] = "<reagent name>",
-									["numRequired"] = <required>, -- the number required of this reagent to complete one execution of the skill
-									["index"] = <reagent index>, -- the index of the reagent, for API call usage
-									["skillIndex"] = <skill index>, -- the index of the skill, for API call usage
-									["icon"] = "<icon>",
-								}, -- [1]
-								...
-							},
-							["keywords"] = "<skill>,<reagent>,...",
-						},
-					},
-				},
-			},
-		},
-	},
-	["shopping"] = {
-		["<character-name>"] = {
-			["<reagent name>"] = <amount>,
-		},
-	},
-
---]]
-
-function Cauldron:Reset()
-	self:Print("Resetting data structures...");
-
-	-- close the window
-	Cauldron:Frame_Hide();
-	HideUIPanel(TradeSkillFrame);
-
-	-- reset the shopping list
-	self.db.realm.shopping = CauldronShopping:NewList();
-
-	-- reset the skills for each character
-	for toon, info in pairs(self.db.realm.userdata) do
-		self.db.realm.userdata[toon] = {};
-		self.db.realm.userdata[toon].skills = {};
-		self.db.realm.userdata[toon].queue = CauldronQueue:NewQueue();
-	end
-
-	self:Print("Reset complete.");
-end
diff --git a/Cauldron/CauldronMain.xml b/Cauldron/CauldronMain.xml
deleted file mode 100644
index 310ee6b..0000000
--- a/Cauldron/CauldronMain.xml
+++ /dev/null
@@ -1,1399 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\..\FrameXML\UI.xsd">
-
-    <!-- Templates -->
-    <Button name="CauldronButtonTemplate" inherits="UIPanelButtonTemplate" virtual="true">
-        <Size x="80" y="20" />
-        <NormalText inherits="GameFontHighlightSmall" />
-        <DisabledText inherits="GameFontDisableSmall" />
-        <HighlightText inherits="GameFontHighlightSmall" />
-        <Scripts>
-            <OnClick>
-                PlaySound("igMainMenuOptionCheckBoxOn");
-			</OnClick>
-            <OnEnter>
-                if ( self.tooltipText ) then
-                    GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-                    GameTooltip:SetText(self.tooltipText, nil, nil, nil, nil, 1);
-                end
-			</OnEnter>
-            <OnLeave>
-                GameTooltip:Hide();
-			</OnLeave>
-        </Scripts>
-    </Button>
-
-	<Button name="CauldronReagentDetailTemplate" inherits="QuestItemTemplate" virtual="true">
-		<Scripts>
-			<OnEnter>
-				GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT");
-				GameTooltip:SetTradeSkillItem(self.skillIndex, self.reagentIndex);
-				CursorUpdate(self);
-			</OnEnter>
-			<OnLeave>
-				GameTooltip:Hide();
-				ResetCursor();
-			</OnLeave>
-			<OnUpdate>
-				CursorOnUpdate(self);
-			</OnUpdate>
-			<OnClick>
-				HandleModifiedItemClick(GetTradeSkillReagentItemLink(TradeSkillFrame.selectedSkill, self:GetID()));
-			</OnClick>
-		</Scripts>
-	</Button>
-
-    <Button name="CauldronSkillItemFrameTemplate" virtual="true">
-    	<Size x="300" y="50" />
-    	<Layers>
-			<Layer level="OVERLAY">
-				<FontString name="$parentSkillName" inherits="GameFontNormal"
-							text="(name)" justifyH="LEFT" justifyV="CENTER">
-					<Size x="250" y="12"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="62" y="-4"/>
-						</Anchor>
-					</Anchors>
-				</FontString>
-				<FontString name="$parentSkillCategory" inherits="GameFontNormalSmall"
-							text="(category)" justifyH="LEFT" justifyV="CENTER">
-					<Size x="250" y="12"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="62" y="-20"/>
-						</Anchor>
-					</Anchors>
-				</FontString>
-				<FontString name="$parentSkillCooldown" inherits="GameFontRedSmall"
-							text="(cooldown)" justifyH="RIGHT" nonSpaceWrap="true" maxLines="3"
-							hidden="true">
-					<Size x="75" y="50"/>
-					<Anchors>
-						<Anchor point="TOPRIGHT">
-							<Offset x="0" y="0"/>
-						</Anchor>
-					</Anchors>
-				</FontString>
-			</Layer>
-			<Layer level="HIGHLIGHT" setAllPoints="true">
-				<Texture file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
-					<Color r="0.7" g="0.7" b="0.7" a="0.5" />
-				</Texture>
-			</Layer>
-    	</Layers>
-    	<Frames>
-			<Button name="$parentSkillIcon">
-				<Size x="37" y="37"/>
-				<Anchors>
-					<Anchor point="TOPLEFT">
-						<Offset x="24" y="-3"/>
-					</Anchor>
-				</Anchors>
-				<Layers>
-					<Layer level="ARTWORK">
-						<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT" hidden="false">
-							<Anchors>
-								<Anchor point="BOTTOMRIGHT">
-									<Offset x="-2" y="2"/>
-								</Anchor>
-							</Anchors>
-						</FontString>
-					</Layer>
-				</Layers>
-				<Scripts>
-					<OnLoad>
-						-- self.hasItem = 1;
-					</OnLoad>
-					<OnClick>
-						-- HandleModifiedItemClick(GetTradeSkillItemLink(self.skillIndex));
-						Cauldron:SkillItem_OnClick(self, button, down);
-					</OnClick>
-					<OnEnter>
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:SetTradeSkillItem(self.skillIndex);
-						CursorUpdate(self);
-					</OnEnter>
-					<OnLeave>
-						GameTooltip:Hide();
-						ResetCursor();
-					</OnLeave>
-					<OnUpdate>
-						if GameTooltip:IsOwned(self) then
-							GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-							GameTooltip:SetTradeSkillItem(self.skillIndex);
-							CursorUpdate(self);
-						end
-						CursorOnUpdate(self);
-					</OnUpdate>
-				</Scripts>
-			</Button>
-			<Button name="$parentDiscloseButton" hidden="false" inherits="ClassTrainerSkillButtonTemplate">
-				<Size x="20" y="22"/>
-				<Anchors>
-					<Anchor point="RIGHT" relativeTo="$parentSkillIcon" relativePoint="LEFT">
-						<Offset x="0" y="0"/>
-					</Anchor>
-				</Anchors>
-				<Scripts>
-					<OnLoad>
-						getglobal(self:GetName()):SetText("");
-					</OnLoad>
-					<OnClick>
-						Cauldron:CollapseItemButton_OnClick(self);
-					</OnClick>
-				</Scripts>
-			</Button>
-			<CheckButton name="$parentFavoriteButton" hidden="false" inherits="UICheckButtonTemplate">
-				<Size x="20" y="22"/>
-				<Anchors>
-					<Anchor point="TOPRIGHT">
-						<Offset x="0" y="0"/>
-					</Anchor>
-				</Anchors>
-				<Scripts>
-					<OnLoad>
-						self:SetScale(0.625);
-						getglobal(self:GetName()):SetText("");
-					</OnLoad>
-                	<OnEnter>
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Mark this skill as a favorite"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-                	</OnEnter>
-                	<OnLeave>
-                		GameTooltip:Hide();
-                		ResetCursor();
-                	</OnLeave>
-					<OnClick>
-						PlaySound("igMainMenuOptionCheckBoxOn");
-						Cauldron:FavoriteItemButton_OnClick(self);
-						Cauldron:UpdateSkillList();
-					</OnClick>
-				</Scripts>
-			</CheckButton>
-    		<Frame name="$parentReagents">
-    			<Size x="40" y="100" />
-				<Anchors>
-					<Anchor point="TOPLEFT" relativeTo="$parentSkillIcon" relativePoint="BOTTOMLEFT">
-						<Offset x="10" y="-3"/>
-					</Anchor>
-				</Anchors>
-    			<Layers>
-    				<Layer level="OVERLAY">
-    					<FontString name="$parentToolsInfo" inherits="GameFontNormal"
-    								text="(tools info)" justifyH="LEFT">
-    						<Size x="250" y="12" />
-							<Anchors>
-								<Anchor point="TOPLEFT">
-									<Offset x="0" y="0"/>
-								</Anchor>
-							</Anchors>
-							<Color r="1.0" g="1.0" b="1.0" />
-    					</FontString>
-    				</Layer>
-    			</Layers>
-    			<Frames>
-					<Button name="$parentItemDetail1" inherits="CauldronReagentDetailTemplate" id="1">
-						<Anchors>
-							<Anchor point="TOPLEFT" relativeTo="$parentToolsInfo" relativePoint="BOTTOMLEFT">
-								<Offset x="0" y="-2"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail2" inherits="CauldronReagentDetailTemplate" id="2">
-						<Anchors>
-							<Anchor point="LEFT" relativeTo="$parentItemDetail1" relativePoint="RIGHT">
-								<Offset x="5" y="0"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail3" inherits="CauldronReagentDetailTemplate" id="3">
-						<Anchors>
-							<Anchor point="TOP" relativeTo="$parentItemDetail1" relativePoint="BOTTOM">
-								<Offset x="0" y="-3"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail4" inherits="CauldronReagentDetailTemplate" id="4">
-						<Anchors>
-							<Anchor point="LEFT" relativeTo="$parentItemDetail3" relativePoint="RIGHT">
-								<Offset x="5" y="0"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail5" inherits="CauldronReagentDetailTemplate" id="5">
-						<Anchors>
-							<Anchor point="TOP" relativeTo="$parentItemDetail3" relativePoint="BOTTOM">
-								<Offset x="0" y="-3"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail6" inherits="CauldronReagentDetailTemplate" id="6">
-						<Anchors>
-							<Anchor point="LEFT" relativeTo="$parentItemDetail5" relativePoint="RIGHT">
-								<Offset x="5" y="0"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail7" inherits="CauldronReagentDetailTemplate" id="7">
-						<Anchors>
-							<Anchor point="TOP" relativeTo="$parentItemDetail7" relativePoint="BOTTOM">
-								<Offset x="0" y="-3"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-					<Button name="$parentItemDetail8" inherits="CauldronReagentDetailTemplate" id="8">
-						<Anchors>
-							<Anchor point="LEFT" relativeTo="$parentItemDetail7" relativePoint="RIGHT">
-								<Offset x="5" y="0"/>
-							</Anchor>
-						</Anchors>
-					</Button>
-    			</Frames>
-    		</Frame>
-    		<Frame name="$parentSelection" setAllPoints="true" enableMouse="true" hidden="true" frameStrata="LOW" frameLevel="1">
-    			<Layers>
-					<Layer level="OVERLAY">
-						<Texture name="$parentSelection" file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
-							<Color r="0.5" g="0.5" b="0.5" a="0.5" />
-						</Texture>
-					</Layer>
-				</Layers>
-			</Frame>
-    	</Frames>
-    	<Scripts>
-    		<OnEnter>
-    			Cauldron:SkillItem_OnEnter(self);
-    		</OnEnter>
-    		<OnLeave>
-    			Cauldron:SkillItem_OnLeave(self);
-    		</OnLeave>
-    		<OnClick>
-                PlaySound("igMainMenuOptionCheckBoxOn");
-    			Cauldron:SkillItem_OnClick(self, button, down);
-    		</OnClick>
-    	</Scripts>
-    </Button>
-
-    <Button name="CauldronQueueItemFrameTemplate" virtual="true" enableMouse="true">
-    	<Size x="300" y="39" />
-    	<Layers>
-			<Layer level="OVERLAY">
-	    		<!-- item name -->
-				<FontString name="$parentItemName" inherits="GameFontNormal"
-							text="(name)" justifyH="LEFT" justifyV="CENTER">
-					<Size x="250" y="12"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="40" y="-4"/>
-						</Anchor>
-					</Anchors>
-					<Color r="0.2" g="0.2" b="0.2" />
-				</FontString>
-				<!-- quantity info -->
-				<FontString name="$parentInfo" inherits="GameFontNormal"
-							text="(info)" justifyH="LEFT" justifyV="CENTER">
-					<Size x="250" y="12"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="40" y="-18"/>
-						</Anchor>
-					</Anchors>
-					<!-- Color r="1.0" g="1.0" b="1.0" / -->
-				</FontString>
-			</Layer>
-			<Layer level="HIGHLIGHT" setAllPoints="true">
-				<Texture file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
-					<Color r="0.8" g="0.8" b="0.8" a="0.5" />
-				</Texture>
-			</Layer>
-    	</Layers>
-    	<Frames>
-    		<!-- icon -->
-			<Button name="$parentIcon">
-				<Size x="37" y="37"/>
-				<Anchors>
-					<Anchor point="TOPLEFT">
-						<Offset x="2" y="-3"/>
-					</Anchor>
-				</Anchors>
-				<Layers>
-					<Layer level="ARTWORK">
-						<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT" hidden="false">
-							<Anchors>
-								<Anchor point="BOTTOMRIGHT">
-									<Offset x="-2" y="2"/>
-								</Anchor>
-							</Anchors>
-						</FontString>
-					</Layer>
-				</Layers>
-				<Scripts>
-					<OnLoad>
-						-- self.hasItem = 1;
-					</OnLoad>
-					<OnClick>
-						-- HandleModifiedItemClick(GetTradeSkillItemLink(TradeSkillFrame.selectedSkill));
-					</OnClick>
-					<OnEnter>
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						if self.link then
-							GameTooltip:SetHyperlink(self.link);
-						end
-						CursorUpdate(self);
-					</OnEnter>
-					<OnLeave>
-						GameTooltip:Hide();
-						ResetCursor();
-					</OnLeave>
-					<OnUpdate>
-						if GameTooltip:IsOwned(self) then
-							GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-							if self.link then
-								GameTooltip:SetHyperlink(self.link);
-							end
-							CursorUpdate(self);
-						end
-						CursorOnUpdate(self);
-					</OnUpdate>
-				</Scripts>
-			</Button>
-			<Button name="$parentRemoveItem" inherits="UIPanelCloseButton" hidden="true">
-                <Anchors>
-                    <Anchor point="TOPRIGHT">
-                        <Offset x="0" y="0"/>
-                    </Anchor>
-                </Anchors>
-                <Scripts>
-                	<OnEnter>
-                		self:GetParent().inHoverButtons = true;
-
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Remove this item from the queue"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-                	</OnEnter>
-                	<OnLeave>
-                		self:GetParent().inHoverButtons = false;
-
-                		GameTooltip:Hide();
-                		ResetCursor();
-                	</OnLeave>
-                    <OnClick>
-                    	Cauldron:RemoveQueueItem(self:GetParent().itemName);
-                    	Cauldron:UpdateQueue();
-                    	Cauldron:UpdateButtons();
-                    </OnClick>
-                </Scripts>
-            </Button>
-			<Button name="$parentAddToShoppingList" inherits="UIPanelCloseButton" hidden="true">
-                <Anchors>
-                    <Anchor point="TOPRIGHT">
-                        <Offset x="0" y="0"/>
-                    </Anchor>
-                </Anchors>
-                <Scripts>
-                	<OnEnter>
-                		self:GetParent().inHoverButtons = true;
-
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Add this item to the shopping list"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-                	</OnEnter>
-                	<OnLeave>
-                		self:GetParent().inHoverButtons = false;
-
-                		GameTooltip:Hide();
-                		ResetCursor();
-                	</OnLeave>
-                    <OnClick>
-                    	Cauldron:AddItemToShoppingList(self:GetParent().itemName, self:GetParent().needAmount);
-                    	Cauldron:UpdateShoppingList();
-                    </OnClick>
-                </Scripts>
-				<NormalTexture file="Interface\Buttons\UI-PlusButton-Up" />
-				<PushedTexture file="Interface\Buttons\UI-PlusButton-Down" />
-				<DisabledTexture file="Interface\Buttons\UI-PlusButton-Disabled" />
-				<HighlightTexture file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD" />
-            </Button>
-			<Button name="$parentDecrementCount" hidden="true" inherits="ClassTrainerSkillButtonTemplate">
-				<Size x="23" y="22" />
-                <Anchors>
-                    <Anchor point="TOPRIGHT">
-                        <Offset x="-16" y="-2"/>
-                    </Anchor>
-                </Anchors>
-				<Scripts>
-					<OnLoad>
-						self:RegisterForClicks("AnyUp");
-					</OnLoad>
-                	<OnEnter>
-                		self:GetParent().inHoverButtons = true;
-
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Decrease the amount of this item"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-                	</OnEnter>
-                	<OnLeave>
-                		self:GetParent().inHoverButtons = false;
-
-                		GameTooltip:Hide();
-                		ResetCursor();
-                	</OnLeave>
-					<OnClick>
-						Cauldron:DecreaseItemCount(self:GetParent().itemName);
-						Cauldron:UpdateQueue();
-                    	Cauldron:UpdateButtons();
-					</OnClick>
-				</Scripts>
-				<!--
-				<NormalTexture file="Interface\Buttons\UI-MinusButton-Up" />
-				<PushedTexture file="Interface\Buttons\UI-MinusButton-Down" />
-				<DisabledTexture file="Interface\Buttons\UI-MinusButton-Disabled" />
-				<HighlightTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Highlight" alphaMode="ADD" />
-				-->
-			</Button>
-			<Button name="$parentIncreasePriority" hidden="true">
-				<Size x="23" y="22" />
-                <Anchors>
-                    <Anchor point="TOPRIGHT">
-                        <Offset x="-16" y="-20"/>
-                    </Anchor>
-                </Anchors>
-				<Scripts>
-					<OnLoad>
-						self:RegisterForClicks("AnyUp");
-					</OnLoad>
-                	<OnEnter>
-                		self:GetParent().inHoverButtons = true;
-
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Increase the priority of this item"));
-						GameTooltip:AddLine(Cauldron:LocaleString("Shift-click to move to the top of the queue"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-                	</OnEnter>
-                	<OnLeave>
-                		self:GetParent().inHoverButtons = false;
-
-                		GameTooltip:Hide();
-                		ResetCursor();
-                	</OnLeave>
-					<OnClick>
-						Cauldron:IncreaseItemPriority(self:GetParent().itemName, IsShiftKeyDown());
-						Cauldron:UpdateQueue();
-					</OnClick>
-				</Scripts>
-				<NormalTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Up" />
-				<PushedTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Down" />
-				<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Disabled" />
-				<HighlightTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Highlight" alphaMode="ADD" />
-			</Button>
-			<Button name="$parentDecreasePriority" hidden="true">
-				<Size x="23" y="22" />
-                <Anchors>
-                    <Anchor point="TOPRIGHT">
-                        <Offset x="0" y="-20"/>
-                    </Anchor>
-                </Anchors>
-				<Scripts>
-					<OnLoad>
-						self:RegisterForClicks("AnyUp");
-					</OnLoad>
-                	<OnEnter>
-                		self:GetParent().inHoverButtons = true;
-
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Decrease the priority of this item"));
-						GameTooltip:AddLine(Cauldron:LocaleString("Shift-click to move to the bottom of the queue"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-                	</OnEnter>
-                	<OnLeave>
-                		self:GetParent().inHoverButtons = false;
-
-                		GameTooltip:Hide();
-                		ResetCursor();
-                	</OnLeave>
-					<OnClick>
-						Cauldron:DecreaseItemPriority(self:GetParent().itemName, IsShiftKeyDown());
-						Cauldron:UpdateQueue();
-					</OnClick>
-				</Scripts>
-				<NormalTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Up" />
-				<PushedTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Down" />
-				<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Disabled" />
-				<HighlightTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Highlight" alphaMode="ADD" />
-			</Button>
-    	</Frames>
-    	<Scripts>
-    		<OnEnter>
-    			if self.removeable then
-    				_G[self:GetName().."RemoveItem"]:Show();
-    				_G[self:GetName().."DecreasePriority"]:Show();
-    				_G[self:GetName().."IncreasePriority"]:Show();
-    				_G[self:GetName().."DecrementCount"]:Show();
-    			end
-    			if self.shoppable then
-    				_G[self:GetName().."AddToShoppingList"]:Show();
-    			end
-    		</OnEnter>
-    		<OnLeave>
-    			if not self.inHoverButtons then
-					_G[self:GetName().."RemoveItem"]:Hide();
-    				_G[self:GetName().."DecreasePriority"]:Hide();
-    				_G[self:GetName().."IncreasePriority"]:Hide();
-    				_G[self:GetName().."DecrementCount"]:Hide();
-    				_G[self:GetName().."AddToShoppingList"]:Hide();
-				end
-    		</OnLeave>
-    	</Scripts>
-    </Button>
-
-    <!-- Main frame -->
-    <Frame name="CauldronFrame" toplevel="true" frameStrata="MEDIUM"
-           movable="true" resizable="false" parent="UIParent" enableMouse="true"
-           hidden="true">
-        <Size x="692" y="465" />
-        <Anchors>
-            <Anchor point="CENTER" />
-        </Anchors>
-
-        <!-- Window border and background -->
-        <Layers>
-			<Layer level="BACKGROUND">
-				<Texture name="CauldronFramePortrait">
-					<Size x="60" y="60"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="7" y="-6"/>
-						</Anchor>
-					</Anchors>
-				</Texture>
-				<FontString name="$parentDummyString" inherits="GameFontNormal" hidden="true">
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="0" y="0"/>
-						</Anchor>
-					</Anchors>
-					<Size x="0" y="0"/>
-				</FontString>
-			  </Layer>
-
-            <Layer level="BORDER">
-                <Texture name="CauldronFrameBorderTopLeft"
-                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-TopLeft">
-                    <Anchors>
-                        <Anchor point="TOPLEFT">
-                            <Offset x="0" y="0" />
-                        </Anchor>
-                    </Anchors>
-                </Texture>
-                <Texture name="CauldronFrameBorderTopMiddle"
-                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-TopMiddle">
-                    <Anchors>
-                        <Anchor point="TOPLEFT">
-                            <Offset x="256" y="0" />
-                        </Anchor>
-                    </Anchors>
-                </Texture>
-                <Texture name="CauldronFrameBorderTopRight"
-                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-TopRight">
-                    <Anchors>
-                        <Anchor point="TOPLEFT">
-                            <Offset x="512" y="0" />
-                        </Anchor>
-                    </Anchors>
-                </Texture>
-                <Texture name="CauldronFrameBorderBottomLeft"
-                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-BottomLeft">
-                    <Anchors>
-                        <Anchor point="TOPLEFT">
-                            <Offset x="0" y="-256" />
-                        </Anchor>
-                    </Anchors>
-                </Texture>
-                <Texture name="CauldronFrameBorderBottomMiddle"
-                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-BottomMiddle">
-                    <Anchors>
-                        <Anchor point="TOPLEFT">
-                            <Offset x="256" y="-256" />
-                        </Anchor>
-                    </Anchors>
-                </Texture>
-                <Texture name="CauldronFrameBorderBottomRight"
-                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-BottomRight">
-                    <Anchors>
-                        <Anchor point="TOPLEFT">
-                            <Offset x="512" y="-256" />
-                        </Anchor>
-                    </Anchors>
-                </Texture>
-            </Layer>
-
-            <Layer level="ARTWORK">
-                <FontString name="CauldronFrameTitleText" inherits="GameFontNormal" text="Cauldron">
-                    <Anchors>
-                        <Anchor point="TOP" relativeTo="CauldronFrame" relativePoint="TOP">
-                            <Offset x="0" y="-18" />
-                        </Anchor>
-                    </Anchors>
-                </FontString>
-            </Layer>
-        </Layers>
-
-        <Frames>
-            <!-- Link button -->
-            <Button name="CauldronTradeSkillLinkButton" frameStrata="HIGH">
-                <Size x="32" y="16" />
-                <Anchors>
-                    <Anchor point="LEFT" relativeTo="CauldronFrameTitleText" relativePoint="RIGHT">
-                        <Offset x="5" y="0" />
-                    </Anchor>
-                </Anchors>
-                <Scripts>
-                    <OnClick>
-                        local link=GetTradeSkillListLink();
-                        if (not ChatEdit_InsertLink(link) ) then
-                            ChatFrameEditBox:Show();
-                            ChatEdit_InsertLink(link);
-                        end
-                    </OnClick>
-                    <OnEnter>
-                        GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT");
-                        GameTooltip:SetText(LINK_TRADESKILL_TOOLTIP, nil, nil, nil, nil, 1);
-                        GameTooltip:Show();
-                    </OnEnter>
-                    <OnLeave>
-                        GameTooltip:Hide();
-                    </OnLeave>
-                </Scripts>
-                <NormalTexture file="Interface\TradeSkillFrame\UI-TradeSkill-LinkButton">
-                    <TexCoords left="0" right="1.0" top="0" bottom="0.5" />
-                </NormalTexture>
-                <HighlightTexture file="Interface\TradeSkillFrame\UI-TradeSkill-LinkButton" alphaMode="ADD">
-                    <TexCoords left="0" right="1.0" top="0.5" bottom="1.0" />
-                </HighlightTexture>
-            </Button>
-
-            <!-- Filters frame -->
-            <Frame name="CauldronFiltersFrame">
-                <Size x="300" y="60" />
-                <Anchors>
-                    <Anchor point="TOPLEFT" relativeTo="CauldronFrame" relativePoint="TOPLEFT">
-                        <Offset x="54" y="-35" />
-                    </Anchor>
-                </Anchors>
-
-                <Frames>
-                    <!-- filter dropdown -->
-                    <Frame name="CauldronFiltersFilterDropDown" inherits="UIDropDownMenuTemplate" id="1">
-                        <Size x="140" y="20" />
-                        <Anchors>
-                            <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
-                                <Offset x="0" y="0"/>
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                Cauldron:FilterDropDown_OnLoad(self);
-                            </OnLoad>
-                        </Scripts>
-                    </Frame>
-
-                    <!-- search text box -->
-			        <EditBox name="CauldronFiltersSearchEditBox" autoFocus="false">
-				        <Size x="130" y="20"/>
-				        <Anchors>
-					       <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
-						      <Offset x="155" y="-2" />
-					       </Anchor>
-				        </Anchors>
-
-				        <Layers>
-					       <Layer level="BACKGROUND">
-						      <Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
-							     <Size x="8" y="20"/>
-							     <Anchors>
-								    <Anchor point="TOPLEFT">
-									   <Offset x="-5" y="0"/>
-								    </Anchor>
-							     </Anchors>
-							     <TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
-						      </Texture>
-						      <Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
-							     <Size x="8" y="20"/>
-							     <Anchors>
-								    <Anchor point="RIGHT">
-									   <Offset x="0" y="0"/>
-								    </Anchor>
-							     </Anchors>
-							     <TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
-						      </Texture>
-						      <Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
-							     <Size x="0" y="20"/>
-							     <Anchors>
-								    <Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/>
-								    <Anchor point="RIGHT" relativeTo="$parentRight" relativePoint="LEFT"/>
-							     </Anchors>
-							     <TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
-						      </Texture>
-					       </Layer>
-				        </Layers>
-				        <Scripts>
-					       	<OnLoad>
-						      	self:SetText(SEARCH);
-							</OnLoad>
-							<OnEnterPressed>
-								self:ClearFocus();
-							</OnEnterPressed>
-							<OnEscapePressed>
-								self:ClearFocus();
-							</OnEscapePressed>
-							<OnTextChanged>
-								Cauldron:TradeSkillFilter_OnTextChanged(self);
-							</OnTextChanged>
-							<OnEditFocusLost>
-								self:HighlightText(0, 0);
-								if self:GetText() == "" then
-									self:SetText(SEARCH);
-								end
-							</OnEditFocusLost>
-							<OnEditFocusGained>
-								self:HighlightText();
-								if self:GetText() == SEARCH then
-									self:SetText("");
-								end
-							</OnEditFocusGained>
-						</Scripts>
-						<FontString inherits="ChatFontSmall"/>
-					</EditBox>
-
-                    <!-- category dropdown -->
-                    <Frame name="CauldronFiltersCategoryDropDown" inherits="UIDropDownMenuTemplate" id="4">
-                        <Size x="140" y="20" />
-                        <Anchors>
-                            <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
-                                <Offset x="0" y="-25"/>
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                Cauldron:CategoryDropDown_OnLoad(self);
-                            </OnLoad>
-                        </Scripts>
-                    </Frame>
-
-                    <!-- slot dropdown -->
-                    <Frame name="CauldronFiltersInvSlotDropDown" inherits="UIDropDownMenuTemplate" id="3">
-                        <Size x="140" y="20" />
-                        <Anchors>
-                            <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
-                                <Offset x="137" y="-25"/>
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                Cauldron:InvSlotDropDown_OnLoad(self);
-                            </OnLoad>
-                        </Scripts>
-                    </Frame>
-
-                </Frames>
-            </Frame>
-
-            <!-- List frame -->
-            <Frame name="CauldronSkillListFrame">
-                <Size x="342" y="100" />
-                <Anchors>
-                    <Anchor point="TOPLEFT" relativeTo="CauldronFrame" relativePoint="TOPLEFT">
-                        <Offset x="14" y="-90" />
-                    </Anchor>
-                </Anchors>
-
-                <Frames>
-					<Frame name="$parentExpandButtonFrame">
-						<Size x="54" y="33"/>
-						<Anchors>
-							<Anchor point="TOPLEFT">
-								<Offset x="-3" y="20"/>
-							</Anchor>
-						</Anchors>
-						<Layers>
-							<Layer level="BACKGROUND">
-								<Texture name="$parentExpandTabLeft" file="Interface\ClassTrainerFrame\UI-ClassTrainer-ExpandTab-Left">
-									<Size x="8" y="32"/>
-									<Anchors>
-										<Anchor point="TOPLEFT"/>
-									</Anchors>
-								</Texture>
-								<Texture name="$parentExpandTabMiddle" file="Interface\QuestFrame\UI-QuestLogSortTab-Middle">
-									<Size x="38" y="32"/>
-									<Anchors>
-										<Anchor point="LEFT" relativeTo="$parentExpandTabLeft" relativePoint="RIGHT">
-											<Offset x="0" y="6"/>
-										</Anchor>
-									</Anchors>
-								</Texture>
-								<Texture name="$parentExpandTabRight" file="Interface\QuestFrame\UI-QuestLogSortTab-Right">
-									<Size x="8" y="32"/>
-									<Anchors>
-										<Anchor point="LEFT" relativeTo="$parentExpandTabMiddle" relativePoint="RIGHT"/>
-									</Anchors>
-								</Texture>
-							</Layer>
-						</Layers>
-						<Frames>
-							<Button name="$parentCollapseAllButton" hidden="false" inherits="ClassTrainerSkillButtonTemplate">
-								<Size x="40" y="22"/>
-								<Anchors>
-									<Anchor point="LEFT" relativeTo="$parentExpandTabLeft" relativePoint="RIGHT">
-										<Offset x="0" y="3"/>
-									</Anchor>
-								</Anchors>
-								<Scripts>
-									<OnLoad>
-										getglobal(self:GetName()):SetText(ALL);
-									</OnLoad>
-									<OnClick>
-										Cauldron:CollapseAllButton_OnClick(self);
-									</OnClick>
-								</Scripts>
-							</Button>
-						</Frames>
-					</Frame>
-					<ScrollFrame name="$parentScrollFrame" inherits="ClassTrainerDetailScrollFrameTemplate">
-						<Size x="300" y="338" />
-						<Anchors>
-							<Anchor point="TOPLEFT" relativeTo="CauldronSkillListFrame" relativePoint="TOPLEFT">
-								<Offset x="0" y="-8"/>
-							</Anchor>
-						</Anchors>
-						<ScrollChild>
-							<Frame name="$parentScrollChild">
-								<Size x="300" y="338" />
-								<Anchors>
-									<Anchor point="TOPLEFT">
-										<Offset x="0" y="0"/>
-									</Anchor>
-								</Anchors>
-								<Frames>
-								</Frames>
-							</Frame>
-						</ScrollChild>
-					</ScrollFrame>
-                </Frames>
-            </Frame>
-
-            <!-- Skill Info frame -->
-            <Frame name="CauldronSkillInfoFrame">
-                <Size x="330" y="100" />
-                <Anchors>
-                    <Anchor point="TOPRIGHT" relativeTo="CauldronFrame" relativePoint="TOPRIGHT">
-                        <Offset x="-10" y="-36" />
-                    </Anchor>
-                </Anchors>
-
-                <Layers>
-                    <Layer level="OVERLAY">
-                        <FontString inherits="GameFontNormal" text="Queue">
-                            <Anchors>
-                                <Anchor point="TOP" relativeTo="CauldronSkillInfoFrame" relativePoint="TOP">
-                                    <Offset x="0" y="-18" />
-                                </Anchor>
-                            </Anchors>
-                        </FontString>
-                    </Layer>
-                </Layers>
-
-                <Frames>
-        			<StatusBar name="CauldronRankFrame" drawLayer="ARTWORK"
-        					   minValue="0" maxValue="1" defaultValue="0"
-        					   enableMouse="false">
-        				<Size x="325" y="14"/>
-        				<Anchors>
-        					<Anchor point="TOPLEFT">
-        						<Offset x="0" y="-2"/>
-        					</Anchor>
-        				</Anchors>
-        				<Layers>
-        					<Layer level="OVERLAY">
-                                <FontString name="$parentSkillName" inherits="GameFontHighlightSmall" justifyH="LEFT">
-                                    <Size x="320" y="9"/>
-                                    <Anchors>
-                                        <Anchor point="TOP" relativeTo="CauldronRankFrame">
-                                            <Offset x="0" y="-2"/>
-                                        </Anchor>
-                                    </Anchors>
-                                    <Color r="1.0" g="1.0" b="0.0" a="1.0" />
-                                </FontString>
-        						<FontString name="$parentSkillRank" inherits="GameFontHighlightSmall" justifyH="RIGHT">
-        							<Size x="320" y="9"/>
-        							<Anchors>
-        								<Anchor point="TOP" relativeTo="CauldronRankFrame">
-        									<Offset x="0" y="-2"/>
-        								</Anchor>
-        							</Anchors>
-        						</FontString>
-        					</Layer>
-        					<Layer level="BORDER">
-        						<Texture name="$parentBorder" file="Interface\PaperDollInfoFrame\UI-Character-Skills-BarBorder">
-        							<Size x="334" y="27"/>
-        							<Anchors>
-        								<Anchor point="LEFT">
-        									<Offset x="-5" y="0"/>
-        								</Anchor>
-        							</Anchors>
-        						</Texture>
-        					</Layer>
-        					<Layer level="BACKGROUND">
-        						<Texture name="$parentBackground">
-        							<Color r="1.0" g="1.0" b="1.0" a="0.2"/>
-        						</Texture>
-        					</Layer>
-        				</Layers>
-        				<Scripts>
-        					<!--
-        					<OnLoad>
-        						self:RegisterEvent("SKILL_LINES_CHANGED");
-        					</OnLoad>
-        					<OnEvent>
-        						if event == "SKILL_LINES_CHANGED" then
-        							Cauldron:Frame_Update();
-        						end
-        					</OnEvent>
-        					-->
-        				</Scripts>
-        				<BarTexture name="$parentBar" file="Interface\PaperDollInfoFrame\UI-Character-Skills-Bar" drawLayer="ARTWORK" />
-        				<BarColor r="0.25" g="0.25" b="0.75" />
-        			</StatusBar>
-                </Frames>
-            </Frame>
-
-            <!-- Queue frame -->
-            <Frame name="CauldronQueueFrame">
-                <Size x="320" y="400" />
-                <Anchors>
-                    <Anchor point="TOPRIGHT" relativeTo="CauldronFrame" relativePoint="TOPRIGHT">
-                        <Offset x="-20" y="-76" />
-                    </Anchor>
-                </Anchors>
-
-                <Frames>
-                	<Frame name="$parentQueueEmpty">
-						<Size x="302" y="360" />
-                		<Anchors>
-                			<Anchor point="TOPLEFT">
-								<Offset x="0" y="0" />
-                			</Anchor>
-                		</Anchors>
-						<Layers>
-							<Layer level="OVERLAY">
-								<FontString name="$parentText" inherits="QuestTitleFont"
-											text="The queue is empty!"
-											justifyH="CENTER" justifyV="CENTER">
-									<Size x="302" y="360" />
-									<Anchors>
-										<Anchor point="TOPLEFT">
-											<Offset x="0" y="0" />
-										</Anchor>
-									</Anchors>
-									<Color r="0.2" g="0.2" b="0.2" />
-								</FontString>
-							</Layer>
-						</Layers>
-                	</Frame>
-
-					<ScrollFrame name="$parentScrollFrame" inherits="ClassTrainerDetailScrollFrameTemplate" hidden="true">
-						<Size x="302" y="360" />
-						<Anchors>
-							<Anchor point="TOPLEFT">
-								<Offset x="0" y="0"/>
-							</Anchor>
-						</Anchors>
-						<ScrollChild>
-							<Frame name="$parentQueueSections">
-								<Size x="302" y="360" />
-								<Anchors>
-									<Anchor point="TOPLEFT">
-										<Offset x="0" y="0"/>
-									</Anchor>
-								</Anchors>
-								<Frames>
-									<Frame name="$parentMainItemsHeader">
-										<Size x="300" y="12" />
-										<Anchors>
-											<Anchor point="TOPLEFT">
-												<Offset x="0" y="0" />
-											</Anchor>
-										</Anchors>
-										<Layers>
-											<Layer level="OVERLAY">
-												<FontString name="$parentText" inherits="QuestFont" text="">
-													<Anchors>
-														<Anchor point="TOPLEFT">
-															<Offset x="0" y="0" />
-														</Anchor>
-													</Anchors>
-													<Color r="0.2" g="0.2" b="0.2" />
-												</FontString>
-											</Layer>
-										</Layers>
-									</Frame>
-									<Frame name="$parentMainItems">
-										<Size x="300" y="1" />
-										<Anchors>
-											<Anchor point="TOPLEFT" relativeTo="$parentMainItemsHeader" relativePoint="BOTTOMLEFT">
-												<Offset x="0" y="-2" />
-											</Anchor>
-										</Anchors>
-									</Frame>
-									<Frame name="$parentSecondaryItemsHeader">
-										<Size x="300" y="12" />
-										<Anchors>
-											<Anchor point="TOPLEFT" relativeTo="$parentMainItems" relativePoint="BOTTOMLEFT">
-												<Offset x="0" y="-2" />
-											</Anchor>
-										</Anchors>
-										<Layers>
-											<Layer level="OVERLAY">
-												<FontString name="$parentText" inherits="QuestFont" text="">
-													<Anchors>
-														<Anchor point="TOPLEFT">
-															<Offset x="0" y="0" />
-														</Anchor>
-													</Anchors>
-													<Color r="0.2" g="0.2" b="0.2" />
-												</FontString>
-											</Layer>
-										</Layers>
-									</Frame>
-									<Frame name="$parentSecondaryItems">
-										<Size x="300" y="1" />
-										<Anchors>
-											<Anchor point="TOPLEFT" relativeTo="$parentSecondaryItemsHeader" relativePoint="BOTTOMLEFT">
-												<Offset x="0" y="-2" />
-											</Anchor>
-										</Anchors>
-									</Frame>
-									<Frame name="$parentReagentsHeader">
-										<Size x="300" y="12" />
-										<Anchors>
-											<Anchor point="TOPLEFT" relativeTo="$parentSecondaryItems" relativePoint="BOTTOMLEFT">
-												<Offset x="0" y="-2" />
-											</Anchor>
-										</Anchors>
-										<Layers>
-											<Layer level="OVERLAY">
-												<FontString name="$parentText" inherits="QuestFont" text="">
-													<Anchors>
-														<Anchor point="TOPLEFT">
-															<Offset x="0" y="0" />
-														</Anchor>
-													</Anchors>
-													<Color r="0.2" g="0.2" b="0.2" />
-												</FontString>
-											</Layer>
-										</Layers>
-									</Frame>
-									<Frame name="$parentReagents">
-										<Size x="300" y="1" />
-										<Anchors>
-											<Anchor point="TOPLEFT" relativeTo="$parentReagentsHeader" relativePoint="BOTTOMLEFT">
-												<Offset x="0" y="-2" />
-											</Anchor>
-										</Anchors>
-									</Frame>
-								</Frames>
-							</Frame>
-						</ScrollChild>
-					</ScrollFrame>
-                </Frames>
-            </Frame>
-
-            <!-- Close button -->
-            <Button name="CauldronFrameCloseButton" inherits="UIPanelCloseButton">
-                <Anchors>
-                    <Anchor point="TOPRIGHT" relativeTo="CauldronFrame" relativePoint="TOPRIGHT">
-                        <Offset x="-2" y="-8"/>
-                    </Anchor>
-                </Anchors>
-                <Scripts>
-                    <OnClick>
-                        HideUIPanel(TradeSkillFrame);
-						PlaySound("igCharacterInfoClose");
-                    </OnClick>
-                </Scripts>
-            </Button>
-
-            <!-- Buttons frame -->
-            <Frame name="CauldronButtonsFrame">
-                <Size x="684" y="25" />
-                <Anchors>
-                    <Anchor point="BOTTOMLEFT" relativeTo="CauldronFrame" relativePoint="BOTTOMLEFT">
-                        <Offset x="13" y="0" />
-                    </Anchor>
-                </Anchors>
-
-                <Frames>
-
-                    <!-- Queue All button -->
-                    <Button name="CauldronQueueAllButton" inherits="CauldronButtonTemplate" text="Queue All">
-                        <Anchors>
-                            <Anchor point="TOPLEFT">
-                                <Offset x="0" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                getglobal(self:GetName()):Disable();
-                            </OnLoad>
-                            <OnClick>
-                            	Cauldron:QueueAllTradeSkillItem();
-								Cauldron:UpdateQueue();
-                            	Cauldron:UpdateButtons();
-                            </OnClick>
-                        </Scripts>
-                    </Button>
-
-                    <!-- Create All button (disabled) -->
-                    <Button name="CauldronCreateAllButton" inherits="CauldronButtonTemplate" text="CREATE_ALL">
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronQueueAllButton" relativePoint="RIGHT">
-                                <Offset x="0" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                getglobal(self:GetName()):Disable();
-                            </OnLoad>
-							<OnClick>
-								Cauldron:CreateAllTradeSkillItem();
-							</OnClick>
-                        </Scripts>
-                    </Button>
-
-                    <!-- Number input -->
-                    <Button name="CauldronAmountDecrementButton">
-                        <Size x="23" y="22" />
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronCreateAllButton" relativePoint="RIGHT">
-                                <Offset x="0" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnClick>
-                                Cauldron:AmountDecrement_OnClick();
-                                CauldronAmountInputBox:ClearFocus();
-							</OnClick>
-                        </Scripts>
-                        <NormalTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Up" />
-                        <PushedTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Down" />
-                        <DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Disabled" />
-                        <HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" />
-                    </Button>
-                    <EditBox name="CauldronAmountInputBox" letters="3" numeric="true" autoFocus="false">
-                        <Size x="30" y="20" />
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronAmountDecrementButton" relativePoint="RIGHT">
-                                <Offset x="4" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Layers>
-                            <Layer level="BACKGROUND">
-                                <Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
-                                    <Size x="8" y="20" />
-                                    <Anchors>
-                                        <Anchor point="TOPLEFT">
-                                            <Offset x="-5" y="0" />
-                                        </Anchor>
-                                    </Anchors>
-                                    <TexCoords left="0" right="0.0625" top="0" bottom="0.625" />
-                                </Texture>
-                                <Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
-                                    <Size x="8" y="20" />
-                                    <Anchors>
-                                        <Anchor point="RIGHT">
-                                            <Offset x="0" y="0" />
-                                        </Anchor>
-                                    </Anchors>
-                                    <TexCoords left="0.9375" right="1.0" top="0" bottom="0.625" />
-                                </Texture>
-                                <Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
-                                    <Size x="10" y="20" />
-                                    <Anchors>
-                                        <Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT" />
-                                        <Anchor point="RIGHT" relativeTo="$parentRight" relativePoint="LEFT" />
-                                    </Anchors>
-                                    <TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625" />
-                                </Texture>
-                            </Layer>
-                        </Layers>
-                        <Scripts>
-                        	<OnLoad>
-                        		self:SetText("1");
-                        	</OnLoad>
-                            <OnEnterPressed>
-                                self:ClearFocus();
-							</OnEnterPressed>
-                            <OnEscapePressed>
-                                self:ClearFocus();
-							</OnEscapePressed>
-                            <OnTextChanged>
-                                if ( self:GetText() == "0" ) then
-									self:SetText("1");
-                                end
-							</OnTextChanged>
-                            <OnEditFocusLost>
-                                self:HighlightText(0, 0);
-							</OnEditFocusLost>
-                            <OnEditFocusGained>
-                                self:HighlightText();
-							</OnEditFocusGained>
-                        </Scripts>
-                        <FontString inherits="ChatFontNormal" />
-                    </EditBox>
-                    <Button name="CauldronAmountIncrementButton">
-                        <Size x="23" y="22" />
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronAmountInputBox" relativePoint="RIGHT">
-                                <Offset x="-3" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnClick>
-                                Cauldron:AmountIncrement_OnClick();
-                                CauldronAmountInputBox:ClearFocus();
-                            </OnClick>
-                        </Scripts>
-                        <NormalTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Up" />
-                        <PushedTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Down" />
-                        <DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Disabled" />
-                        <HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" />
-                    </Button>
-
-                    <!-- Create button (disabled) -->
-                    <Button name="CauldronCreateButton" inherits="CauldronButtonTemplate" text="CREATE">
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronAmountIncrementButton" relativePoint="RIGHT">
-                                <Offset x="0" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                getglobal(self:GetName()):Disable();
-                            </OnLoad>
-							<OnClick>
-								Cauldron:CreateTradeSkillItem();
-							</OnClick>
-                        </Scripts>
-                    </Button>
-
-                    <!-- Queue button -->
-                    <Button name="CauldronQueueButton" inherits="CauldronButtonTemplate" text="Queue">
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronCreateButton" relativePoint="RIGHT">
-                                <Offset x="0" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                getglobal(self:GetName()):Disable();
-                            </OnLoad>
-							<OnClick>
-								Cauldron:QueueTradeSkillItem();
-								Cauldron:UpdateQueue();
-                            	Cauldron:UpdateButtons();
-							</OnClick>
-                        </Scripts>
-                    </Button>
-
-                    <!-- spacer -->
-
-                    <!-- Process button (disabled) -->
-                    <Button name="CauldronProcessButton" inherits="CauldronButtonTemplate" text="Process">
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronQueueButton" relativePoint="RIGHT">
-                                <Offset x="10" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                getglobal(self:GetName()):Disable();
-                            </OnLoad>
-							<OnClick>
-								Cauldron:ProcessQueue();
-							</OnClick>
-                        </Scripts>
-                    </Button>
-
-                    <!-- Clear Queue button (disabled) -->
-                    <Button name="CauldronClearQueueButton" inherits="CauldronButtonTemplate" text="Clear Queue">
-                        <Size x="90" y="20" />
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronProcessButton" relativePoint="RIGHT">
-                                <Offset x="0" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnLoad>
-                                getglobal(self:GetName()):Disable();
-                            </OnLoad>
-							<OnClick>
-								CauldronQueue:ClearQueue(Cauldron:GetQueue());
-								Cauldron:UpdateQueue();
-							</OnClick>
-                        </Scripts>
-                    </Button>
-
-                    <!-- spacer -->
-
-                    <!-- Close button -->
-                    <Button name="CauldronCloseButton" inherits="CauldronButtonTemplate" text="CLOSE">
-                        <Anchors>
-                            <Anchor point="LEFT" relativeTo="CauldronClearQueueButton" relativePoint="RIGHT">
-                                <Offset x="12" y="0" />
-                            </Anchor>
-                        </Anchors>
-                        <Scripts>
-                            <OnClick>
-								HideUIPanel(TradeSkillFrame);
-								PlaySound("igCharacterInfoClose");
-                            </OnClick>
-                        </Scripts>
-                    </Button>
-                </Frames>
-            </Frame>
-        </Frames>
-
-        <Scripts>
-            <OnLoad>
-                self:SetBackdropColor(.05,.05,.05,.8);
-                self:SetBackdropBorderColor(.4,.4,.4,1);
-                tinsert(UISpecialFrames, self:GetName());
-            </OnLoad>
-            <OnShow>
-                PlaySound("igCharacterInfoOpen");
-            </OnShow>
-            <OnHide>
-                --HideUIPanel(CauldronFrame);
-                PlaySound("igCharacterInfoClose");
-            </OnHide>
-            <OnMouseWheel>
-                return;
-            </OnMouseWheel>
-        </Scripts>
-    </Frame>
-
-</Ui>
diff --git a/Cauldron/CauldronMainUI.lua b/Cauldron/CauldronMainUI.lua
deleted file mode 100644
index 09eb7af..0000000
--- a/Cauldron/CauldronMainUI.lua
+++ /dev/null
@@ -1,1646 +0,0 @@
--- $Revision$
--- Cauldron user interface logic
-
-local L = LibStub("AceLocale-3.0"):GetLocale("Cauldron")
-
--- CauldronUI = LibStub("AceAddon-3.0"):NewAddon("CauldronUI", "AceEvent-3.0", "AceConsole-3.0", "LibDebugLog-1.0")
-
-function Cauldron:Frame_Show()
- 	self:debug("Frame_Show enter");
-
- 	self:debug("Frame_Show: close dropdown menus");
- 	CloseDropDownMenus();
-
---	self:UpdateFramePosition();
---	self:UpdateFrameStrata();
-
- 	self:debug("Frame_Show: show our frame");
- 	ShowUIPanel(CauldronFrame);
-
-	if TradeSkillFrame then
-		self:debug("Frame_Show: hide the original tradeskill frame");
-
-		-- hide the original tradeskill frame
-		TradeSkillFrame:SetAlpha(0);
---		TradeSkillFrame:ClearAllPoints();
---		TradeSkillFrame:SetPoint("TOPLEFT", 0, 900);
-		CauldronFrame:SetPoint("TOPLEFT", TradeSkillFrame, "TOPLEFT", 0, 0);
-	end
-
- 	self:RegisterMessage("Cauldron_Update", "OnCauldronUpdate");
-
- 	self:debug("Frame_Show: call Frame_Update()");
-	self:Frame_Update();
-
- 	self:debug("Frame_Show exit");
-end
-
-function Cauldron:Frame_Hide()
- 	self:debug("Frame_Hide enter");
-
- 	self:UnregisterEvent("Cauldron_Update")
- 	HideUIPanel(CauldronFrame);
-
- 	self:debug("Frame_Hide exit");
-end
-
-function Cauldron:Frame_Toggle()
- 	self:debug("Frame_Toggle enter");
-
- 	if CauldronFrame:IsVisible() then
-		self:debug("Frame_Toggle: call Frame_Hide()");
- 		Cauldron:Frame_Hide();
- 	else
-		self:debug("Frame_Toggle: call Frame_Show()");
- 		Cauldron:Frame_Show();
- 	end
-
- 	self:debug("Frame_Toggle exit");
-end
-
-function Cauldron:Frame_Update()
- 	self:debug("Frame_Update enter");
-
-	local numTradeSkills = GetNumTradeSkills();
-	self:debug("Frame_Update numTradeSkills: ",numTradeSkills);
---	local skillOffset = FauxScrollFrame_GetOffset(TradeSkillListScrollFrame);
-	local name, rank, maxRank = GetTradeSkillLine();
-	self:debug("Frame_Update name: ",name,"; rank: ",rank,"; maxRank: ",maxRank);
-
-	if name == "UNKNOWN" then
-		return;
-	end
-
-	Cauldron:UpdateSkills();
-
-	if CURRENT_TRADESKILL ~= name then
-		self:debug("Frame_Update: current skill changed");
-
-		StopTradeSkillRepeat();
-
-		if ( CURRENT_TRADESKILL ~= "" ) then
-			-- To fix problem with switching between two tradeskills
---			UIDropDownMenu_Initialize(TradeSkillInvSlotDropDown, TradeSkillInvSlotDropDown_Initialize);
---			UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, 1);
-
---			UIDropDownMenu_Initialize(TradeSkillSubClassDropDown, TradeSkillSubClassDropDown_Initialize);
---			UIDropDownMenu_SetSelectedID(TradeSkillSubClassDropDown, 1);
-		end
-		CURRENT_TRADESKILL = name;
-	end
-
-	-- update the frame dimensions
-    -- <Size x="692" y="465" />
-	CauldronFrame:SetHeight(465);
-	CauldronFrame:SetWidth(692);
-
-	-- display skill name, level/progress
-	self:debug("Frame_Update: display skill level/progress");
-	self:UpdateSkillInfo(name, rank, maxRank);
-
-	-- update search text box
-	self:debug("Frame_Update: display search text");
-	self:UpdateSearchText();
-
-	-- TODO: update dropdowns
-	self:debug("Frame_Update: update dropdowns");
-	self:UpdateFilterDropDowns();
-
-	-- display list of matching skills
-	self:debug("Frame_Update: display list of skills");
-	self:UpdateSkillList();
-
-	-- display queue
-	self:debug("Frame_Update: display queue");
-	self:UpdateQueue();
-
-	-- update buttons
-	self:debug("Frame_Update: update buttons");
-	self:UpdateButtons();
-
- 	self:debug("Frame_Update exit");
-end
-
-function Cauldron:UpdateSkillInfo(skillName, rank, maxRank)
-	self:debug("UpdateSkillInfo enter");
-
-	CauldronRankFrameSkillName:SetText(skillName);
-
-	CauldronRankFrame:SetStatusBarColor(0.0, 0.0, 1.0, 0.5);
-	CauldronRankFrameBackground:SetVertexColor(0.0, 0.0, 0.75, 0.5);
-	CauldronRankFrame:SetMinMaxValues(0, maxRank);
-	CauldronRankFrame:SetValue(rank);
-	CauldronRankFrameSkillRank:SetText(rank.."/"..maxRank);
-
-	self:debug("UpdateSkillInfo exit");
-end
-
-function Cauldron:UpdateSearchText()
-	self:debug("UpdateSearchText enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local searchText = self.db.realm.userdata[self.vars.playername].skills[skillName].window.search or "";
-	if searchText == "" then
-		searchText = SEARCH;
-	end
-	CauldronFiltersSearchEditBox:SetText(searchText);
-
-	self:debug("UpdateSearchText exit");
-end
-
-function Cauldron:UpdateFilterDropDowns()
-	self:debug("UpdateFilterDropDowns enter");
-
-	self:debug("UpdateFilterDropDowns exit");
-end
-
-function Cauldron:UpdateSkillList()
-	self:debug("UpdateSkillList enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local skillList = Cauldron:GetSkillList(self.vars.playername, skillName);
-	self:debug("UpdateSkillList: skillList="..#skillList);
-
-	local height = 0;
-
-	-- iterate over the list of skills
-	for i, skillInfo in ipairs(skillList) do
-		self:debug("UpdateSkillList: i="..i);
-
-		local skillFrame = _G["CauldronSkillItem"..i];
-
-		-- check if we have a frame for this position
-		if not skillFrame then
-			-- create a new frame for the skill information
-			skillFrame = CreateFrame("Button",
-									 "CauldronSkillItem"..i,
-									 CauldronSkillListFrameScrollFrameScrollChild,
-									 "CauldronSkillItemFrameTemplate");
-		end
-
-		skillFrame:SetID(i);
-		skillFrame.skillIndex = skillInfo.index;
-
-		-- set selection
-		if self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected == skillInfo.index then
-			_G["CauldronSkillItem"..i.."Selection"]:Show();
-		else
-			_G["CauldronSkillItem"..i.."Selection"]:Hide();
-		end
-
-		-- populate the frame
-		local frame = nil;
-
-		-- set name and difficulty color
-		frame = _G["CauldronSkillItem"..i.."SkillName"];
-		local nameText = skillInfo.name;
-		local potentialCount = Cauldron:GetPotentialCraftCount(skillInfo);
-		if potentialCount > 0 then
-			nameText = nameText.." ["..skillInfo.available.."/"..potentialCount.."]";
-		elseif skillInfo.available > 0 then
-			nameText = nameText.." ["..skillInfo.available.."]";
-		end
-		frame:SetText(nameText);
-		if TradeSkillTypeColor then
-			local color = TradeSkillTypeColor[skillInfo.difficulty];
-			if color then
-				frame:SetFontObject(color.font);
-				frame.r = color.r;
-				frame.g = color.g;
-				frame.b = color.b;
-			end
-		end
-
-		-- set category
-		frame = _G["CauldronSkillItem"..i.."SkillCategory"];
-		frame:SetText(skillInfo.defaultCategory);
-		if TradeSkillTypeColor then
-			frame:SetFontObject(TradeSkillTypeColor.header.font);
-			frame.r = TradeSkillTypeColor.header.r;
-			frame.g = TradeSkillTypeColor.header.g;
-			frame.b = TradeSkillTypeColor.header.b;
-		end
-
-		-- set favorite check button
-		frame = _G["CauldronSkillItem"..i.."FavoriteButton"];
-		frame:SetChecked(self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite);
-		frame.skillInfo = skillInfo;
-
-		-- set cooldown
-		frame = _G["CauldronSkillItem"..i.."SkillCooldown"];
-		local cooldown = GetTradeSkillCooldown(skillInfo.index);
-		if cooldown then
-			if not frame:IsVisible() then
-				frame:Show();
-			end
-			frame:SetText(SecondsToTime(cooldown));
-		else
-			if frame:IsVisible() then
-				frame:Hide();
-			end
-		end
-
-		-- set the icon
-		frame = _G["CauldronSkillItem"..i.."SkillIcon"];
-		frame:SetNormalTexture(skillInfo.icon);
-		frame.skillIndex = skillInfo.index;
-
-		-- set the craft count
-		frame = _G["CauldronSkillItem"..i.."SkillIconCount"];
-		local minMade, maxMade = skillInfo.minMade, skillInfo.maxMade;
-		if maxMade > 1 then
-			if minMade == maxMade then
-				frame:SetText(minMade);
-			else
-				frame:SetText(minMade.."-"..maxMade);
-			end
-			if frame:GetWidth() > 39 then
-				frame:SetText("~"..floor((minMade + maxMade)/2));
-			end
-		else
-			frame:SetText("");
-		end
-
-		-- set the disclosure button texture
-		frame = _G["CauldronSkillItem"..i.."DiscloseButton"];
-		frame.skillInfo = skillInfo;
-		self:debug("UpdateSkillList: skillInfo.name="..skillInfo.name);
-		local reagentsExpanded = self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
-		self:debug("UpdateSkillList: reagentsExpanded="..tostring(reagentsExpanded));
-		if reagentsExpanded then
-			frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
-
-			_G["CauldronSkillItem"..i.."Reagents"]:Show();
-
-			-- fill in the tools info
-			local spellFocus = BuildColoredListString(GetTradeSkillTools(skillInfo.index));
-			local toolsFrame = _G["CauldronSkillItem"..i.."ReagentsToolsInfo"];
-			if spellFocus then
-				self:debug("UpdateSkillList: skill has a spell focus");
-
-				toolsFrame:Show();
-				toolsFrame:SetText(L["Requires"]..": "..spellFocus);
-				toolsFrame:SetHeight(15);
-			else
-				self:debug("UpdateSkillList: skill doesn't have a spell focus");
-
-				toolsFrame:Hide();
-				toolsFrame:SetText("");
-				toolsFrame:SetHeight(0);
-			end
-
-			-- fill in the reagents
-			_G["CauldronSkillItem"..i.."Reagents"]:SetScale(0.86);
-			local reagentCount = #skillInfo.reagents;
-
-			for j=1,8 do
-				local reagentFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j];
-
-				if j > reagentCount then
-					reagentFrame:Hide();
-				else
-					local reagentInfo = skillInfo.reagents[j];
-
-					reagentFrame.skillIndex = skillInfo.index;
-					reagentFrame.reagentIndex = reagentInfo.index;
-
-					local reagentNameFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Name"];
-					local reagentCountFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Count"];
-
-					reagentFrame:Show();
-					SetItemButtonTexture(reagentFrame, reagentInfo.icon);
-					reagentNameFrame:SetText(reagentInfo.name);
-
-					local playerReagentCount = reagentInfo.toonHas;
-
-					if playerReagentCount < reagentInfo.numRequired then
-						-- Grayout items
-						SetItemButtonTextureVertexColor(reagentFrame, 0.5, 0.5, 0.5);
-						reagentNameFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
-					else
-						SetItemButtonTextureVertexColor(reagentFrame, 1.0, 1.0, 1.0);
-						reagentNameFrame:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
-					end
-					if playerReagentCount >= 100 then
-						playerReagentCount = "*";
-					end
-					reagentCountFrame:SetText(playerReagentCount.."/"..reagentInfo.numRequired);
-				end
-			end
-
-			local reagentRows = math.floor((reagentCount - 1) / 2) + 1;
-			_G["CauldronSkillItem"..i.."Reagents"]:SetHeight(toolsFrame:GetHeight() + (reagentRows * _G["CauldronSkillItem"..i.."ReagentsItemDetail1"]:GetHeight()));
-			_G["CauldronSkillItem"..i]:SetHeight(_G["CauldronSkillItem"..i.."SkillIcon"]:GetHeight() + _G["CauldronSkillItem"..i.."Reagents"]:GetHeight());
-		else
-			_G["CauldronSkillItem"..i.."Reagents"]:Hide();
-
-			frame:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
-			_G["CauldronSkillItem"..i]:SetHeight(_G["CauldronSkillItem"..i.."SkillIcon"]:GetHeight());
-		end
-
-		-- place the frame in the scroll view
-		if i > 1 then
-			-- anchor to the frame above
-			self:debug("UpdateSkillList: anchor frame to top left of frame above");
-			skillFrame:SetPoint("TOPLEFT", _G["CauldronSkillItem"..(i-1)], "BOTTOMLEFT", 0, -2);
-		else
-			-- anchor to the parent
-			self:debug("UpdateSkillList: anchor frame to parent");
-			skillFrame:SetPoint("TOPLEFT", 0, 0);
-		end
-
-		-- adjust the scroll child size
-		height = height + skillFrame:GetHeight();
-		self:debug("UpdateSkillList: height="..height);
-		CauldronSkillListFrameScrollFrameScrollChild:SetHeight(height);
-
-		-- show the frame
-		self:debug("UpdateSkillList: show the frame");
-		skillFrame:Show();
-	end
-
-	-- hide any remaining frames
-	local j = #skillList + 1;
-	while true do
-		local frame = _G["CauldronSkillItem"..j];
-		if not frame then
-			break;
-		end
-
-		frame:Hide();
-		frame:SetHeight(0);
-
-		j = j + 1;
-	end
-
-	self:debug("UpdateSkillList exit");
-end
-
-function Cauldron:UpdateButtons()
-	self:debug("UpdateButtons enter");
-
-	if IsTradeSkillLinked() then
-		CauldronQueueAllButton:Hide();
-		CauldronQueueButton:Hide();
-		CauldronAmountDecrementButton:Hide();
-		CauldronAmountInputBox:Hide();
-		CauldronAmountIncrementButton:Hide();
-		CauldronCreateAllButton:Hide();
-		CauldronCreateButton:Hide();
-		CauldronProcessButton:Hide();
-		CauldronClearQueueButton:Hide();
-		return;
-	else
-		CauldronQueueAllButton:Show();
-		CauldronQueueButton:Show();
-		CauldronAmountDecrementButton:Show();
-		CauldronAmountInputBox:Show();
-		CauldronAmountIncrementButton:Show();
-		CauldronCreateAllButton:Show();
-		CauldronCreateButton:Show();
-		CauldronProcessButton:Show();
-		CauldronClearQueueButton:Show();
-	end
-
-	local skillInfo = Cauldron:GetSelectedSkill();
-
-	if skillInfo then
-		if skillInfo.verb then
-			CauldronQueueAllButton:Hide();
-			CauldronQueueButton:Hide();
-			CauldronCreateAllButton:Hide();
-
-			CauldronCreateButton:Enable();
-			CauldronCreateButton:SetText(skillInfo.verb or CREATE);
-		else
-			CauldronQueueAllButton:Enable();
-			CauldronQueueButton:Enable();
-
-			if skillInfo.available then
-				CauldronCreateAllButton:Enable();
-				CauldronCreateButton:Enable();
-				CauldronCreateButton:SetText(CREATE);
-			end
-		end
-	else
-		CauldronQueueAllButton:Disable();
-		CauldronQueueButton:Disable();
-		CauldronCreateAllButton:Disable();
-		CauldronCreateButton:Disable();
-	end
-
-	if #CauldronQueue:GetItems(self.db.realm.userdata[self.vars.playername].queue, CURRENT_TRADESKILL) > 0 then
-		CauldronProcessButton:Enable();
-		CauldronClearQueueButton:Enable();
-	else
-		CauldronProcessButton:Disable();
-		CauldronClearQueueButton:Disable();
-	end
-
-	self:debug("UpdateButtons exit");
-end
-
-function Cauldron:UpdateQueue()
-	self:debug("UpdateQueue enter");
-
-	if not CauldronFrame:IsShown() then
-		return;
-	end
-
-	local queue = self.db.realm.userdata[self.vars.playername].queue;
-	local itemQueue = {};
-
-	local skillName = CURRENT_TRADESKILL;
-	if not IsTradeSkillLinked() then
-		itemQueue = CauldronQueue:GetItems(queue);
-	end
-
-	if #itemQueue == 0 then
-		self:debug("UpdateQueue: display empty queue");
-
-		-- queue is empty, display the empty message
-		CauldronQueueFrameQueueEmpty:Show();
-		CauldronQueueFrameScrollFrame:Hide();
-
-		if IsTradeSkillLinked() then
-			CauldronQueueFrameQueueEmptyText:SetText("No queue for linked tradeskills.");
-		else
-			CauldronQueueFrameQueueEmptyText:SetText("The queue is empty!\nMake something.");
-		end
-
-		return;
-	end
-
-	self:debug("UpdateQueue: display queue");
-
-	-- queue has items, show them
-	CauldronQueueFrameQueueEmpty:Hide();
-	CauldronQueueFrameScrollFrame:Show();
-
-	local itemFrameHeight = 39;
-
-	local height = 0;
-
-	CauldronQueueFrameScrollFrameQueueSectionsMainItemsHeaderText:SetText(L["In order to make:"]);
-	-- adjust the scroll child size
-	CauldronQueueFrameScrollFrameQueueSectionsMainItems:SetHeight(#itemQueue * itemFrameHeight);
-
-	for i, queueInfo in ipairs(itemQueue) do
-		local queueItemFrame = _G["CauldronQueueItem"..i];
-
-		-- check if we have a frame for this position
-		if not queueItemFrame then
-			-- create a new frame for the skill information
-			queueItemFrame = CreateFrame("Button",
-									 	 "CauldronQueueItem"..i,
-									 	 CauldronQueueFrameScrollFrameQueueSectionsMainItems,
-									 	 "CauldronQueueItemFrameTemplate");
-		end
-
-		queueItemFrame:SetID(i);
-		queueItemFrame.itemName = queueInfo.name;
-		queueItemFrame.removeable = true;
-		queueItemFrame.shoppable = false;
-		queueItemFrame.inHoverButtons = false;
-
-		_G["CauldronQueueItem"..i.."RemoveItem"]:Hide();
-		_G["CauldronQueueItem"..i.."RemoveItem"]:SetScale(0.75);
-		_G["CauldronQueueItem"..i.."IncreasePriority"]:Hide();
-		_G["CauldronQueueItem"..i.."DecreasePriority"]:Hide();
-		_G["CauldronQueueItem"..i.."DecrementCount"]:Hide();
-		_G["CauldronQueueItem"..i.."AddToShoppingList"]:Hide();
-
-		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-		if not skillInfo then
-			-- the skill isn't available (character doesn't know it?)
-			-- TODO
-		end
-
-		-- initialize the frame object
-		local frame = nil;
-
-		-- set name and difficulty color
-		frame = _G["CauldronQueueItem"..i.."ItemName"];
-		frame:SetText(queueInfo.name);
-		if skillInfo then
-			local color = TradeSkillTypeColor[skillInfo.difficulty];
-			if color then
-				frame:SetFontObject(color.font);
-				frame:SetTextColor(color.r, color.g, color.b, 1.0);
-				frame.r = color.r;
-				frame.g = color.g;
-				frame.b = color.b;
-			end
-		else
-			-- TODO: default color info
-		end
-
-		-- set quantity info
-		frame = _G["CauldronQueueItem"..i.."Info"];
-		local infoText = queueInfo.tradeskill;
-		-- TODO: alts/bank/etc.
-		frame:SetText(infoText);
---		frame:SetTextColor(1.0, 1.0, 0.2, 1.0);
---		frame:SetShadowOffset(0, 0);
-
-		-- set the icon
-		frame = _G["CauldronQueueItem"..i.."Icon"];
-		frame:SetNormalTexture(queueInfo.icon);
-		frame.link = queueInfo.link;
-
-		-- set the amount
-		frame = _G["CauldronQueueItem"..i.."IconCount"];
-		frame:SetText(queueInfo.amount);
-
-		-- place the frame in the scroll view
-		if i > 1 then
-			-- anchor to the frame above
-			self:debug("UpdateQueue: anchor frame to top left of frame above");
-			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueItem"..(i-1)], "BOTTOMLEFT", 0, 0);
-		else
-			-- anchor to the parent
-			self:debug("UpdateQueue: anchor frame to parent");
-			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsMainItems, "TOPLEFT", 0, 0);
-		end
-
---		height = height + queueItemFrame:GetHeight() + 2;
---		self:debug("UpdateQueue: height="..height);
-
-		-- show the frame
-		self:debug("UpdateQueue: show the frame");
-		queueItemFrame:Show();
-	end
-
-	-- hide any remaining frames
-	local j = #itemQueue + 1;
-	while true do
-		local frame = _G["CauldronQueueItem"..j];
-		if not frame then
-			break;
-		end
-
-		_G["CauldronQueueItem"..j] = nil;
-
-		frame:Hide();
-		frame:SetHeight(0);
-
-		j = j + 1;
-	end
-
-	local intQueue = CauldronQueue:GetIntermediates(queue);
-	local reagentList = CauldronQueue:GetReagents(queue);
-
-	-- store the intermediate queue and the reagent list
---	self.db.realm.userdata[self.vars.playername].intQueue = intQueue;
---	self.db.realm.userdata[self.vars.playername].reagentList = reagentList;
-
-	-- display intermediate queue, maybe
-	if #intQueue == 0 then
-		self:debug("UpdateQueue: intermediate queue is empty, hide header and item frames");
-		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:SetHeight(1);
-		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeaderText:SetText("");
-		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(1);
-	else
-		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:SetHeight(12);
-		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeaderText:SetText(L["You first have to make:"]);
-
-		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(#intQueue * itemFrameHeight);
-
-		local intHeight = 0;
-
-		for i, queueInfo in ipairs(intQueue) do
-			local queueItemFrame = _G["CauldronQueueIntItem"..i];
-
-			-- check if we have a frame for this position
-			if not queueItemFrame then
-				-- create a new frame for the skill information
-				queueItemFrame = CreateFrame("Button",
-											 "CauldronQueueIntItem"..i,
-											 CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems,
-											 "CauldronQueueItemFrameTemplate");
-			end
-
-			queueItemFrame:SetID(i);
-			queueItemFrame.itemName = queueInfo.name;
-			queueItemFrame.removeable = false;
-			queueItemFrame.shoppable = false;
-			queueItemFrame.inHoverButtons = false;
-
-			-- don't show the remove button
-			_G["CauldronQueueIntItem"..i.."RemoveItem"]:Hide();
-			_G["CauldronQueueIntItem"..i.."RemoveItem"]:SetScale(0.75);
-			_G["CauldronQueueIntItem"..i.."IncreasePriority"]:Hide();
-			_G["CauldronQueueIntItem"..i.."DecreasePriority"]:Hide();
-			_G["CauldronQueueIntItem"..i.."DecrementCount"]:Hide();
-			_G["CauldronQueueIntItem"..i.."AddToShoppingList"]:Hide();
-
-			local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-			if not skillInfo then
-				-- the skill isn't available (character doesn't know it?)
-				-- TODO
-			end
-
-			-- populate the frame
-			local frame = nil;
-
-			-- set name and difficulty color
-			frame = _G["CauldronQueueIntItem"..i.."ItemName"];
-			frame:SetText(queueInfo.name);
-			if skillInfo then
-				local color = TradeSkillTypeColor[skillInfo.difficulty];
-				if color then
-					frame:SetFontObject(color.font);
-					frame:SetTextColor(color.r, color.g, color.b, 1.0);
-					frame.r = color.r;
-					frame.g = color.g;
-					frame.b = color.b;
-				end
-			else
-				frame:SetFont("GameFontNormal", 12);
---				frame:SetTextColor(1.0, 1.0, 1.0, 1.0);
-				frame.r = 1.0;
-				frame.g = 1.0;
-				frame.b = 1.0;
-			end
-
-			-- set quantity info
-			frame = _G["CauldronQueueIntItem"..i.."Info"];
-			local countInfo = Cauldron:ReagentCount(queueInfo.name);
-			local infoText = string.format(queueInfo.tradeskill.."; "..L["Have %d"], countInfo.has);
-			local need = math.max(0, queueInfo.amount - countInfo.has);
-			if need > 0 then
-				infoText = infoText..string.format(L[", need %d"], need);
-			end
-			-- alts/bank/etc.
-			frame:SetText(infoText);
-			frame:SetTextColor(0.1, 0.1, 0.1, 1.0);
-			frame:SetShadowOffset(0, 0);
-
-			-- set the icon
-			frame = _G["CauldronQueueIntItem"..i.."Icon"];
-			frame:SetNormalTexture(queueInfo.icon);
-			frame.link = queueInfo.link;
-
-			-- set the amount
-			frame = _G["CauldronQueueIntItem"..i.."IconCount"];
-			frame:SetText(queueInfo.amount);
-
-			-- place the frame in the scroll view
-			if i > 1 then
-				-- anchor to the frame above
-				self:debug("UpdateQueue: anchor frame to top left of frame above");
-				queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueIntItem"..(i-1)], "BOTTOMLEFT", 0, 0);
-			else
-				-- anchor to the parent
-				self:debug("UpdateQueue: anchor frame to parent");
-				queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems, "TOPLEFT", 0, 0);
-			end
-
-			-- adjust the scroll child size
---			intHeight = intHeight + queueItemFrame:GetHeight() + 2;
---			self:debug("UpdateQueue: height="..height);
---			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(intHeight);
-
-			-- show the frame
-			self:debug("UpdateQueue: show the frame");
-			queueItemFrame:Show();
-		end
-	end
-
-	-- hide any remaining frames
-	local j = #intQueue + 1;
-	while true do
-		local frame = _G["CauldronQueueIntItem"..j];
-		if not frame then
-			break;
-		end
-
-		_G["CauldronQueueIntItem"..j] = nil;
-
-		frame:Hide();
-		frame:SetHeight(0);
-
-		j = j + 1;
-	end
-
-	-- display reagent list
-
-	CauldronQueueFrameScrollFrameQueueSectionsReagentsHeaderText:SetText(L["You will need:"]);
-	CauldronQueueFrameScrollFrameQueueSectionsReagents:SetHeight(#reagentList * itemFrameHeight);
-
-	local reagentHeight = 0;
-
-	for i, queueInfo in ipairs(reagentList) do
-		local queueItemFrame = _G["CauldronQueueReagentItem"..i];
-
-		-- check if we have a frame for this position
-		if not queueItemFrame then
-			-- create a new frame for the skill information
-			queueItemFrame = CreateFrame("Button",
-										 "CauldronQueueReagentItem"..i,
-										 CauldronQueueFrameScrollFrameQueueSectionsReagents,
-										 "CauldronQueueItemFrameTemplate");
-		end
-
-		local countInfo = Cauldron:ReagentCount(queueInfo.name);
-		local need = math.max(0, queueInfo.amount - countInfo.has);
-
-		queueItemFrame:SetID(i);
-		queueItemFrame.skillIndex = queueInfo.skillIndex;
-		queueItemFrame.index = queueInfo.index;
-		queueItemFrame.itemName = queueInfo.name;
-		queueItemFrame.removeable = false;
-		queueItemFrame.shoppable = true;
-		queueItemFrame.inHoverButtons = false;
-		queueItemFrame.needAmount = need;
-
-		-- don't show the remove button
-		_G["CauldronQueueReagentItem"..i.."RemoveItem"]:Hide();
-		_G["CauldronQueueReagentItem"..i.."RemoveItem"]:SetScale(0.75);
-		_G["CauldronQueueReagentItem"..i.."IncreasePriority"]:Hide();
-		_G["CauldronQueueReagentItem"..i.."DecreasePriority"]:Hide();
-		_G["CauldronQueueReagentItem"..i.."DecrementCount"]:Hide();
-		_G["CauldronQueueReagentItem"..i.."AddToShoppingList"]:Hide();
-		_G["CauldronQueueReagentItem"..i.."AddToShoppingList"]:SetScale(0.5);
-
-		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-		if not skillInfo then
-			-- TODO
-		end
-
-		-- populate the frame
-		local frame = nil;
-
-		-- set name and difficulty color
-		frame = _G["CauldronQueueReagentItem"..i.."ItemName"];
-		frame:SetText(queueInfo.name);
-		frame:SetShadowOffset(0, 0);
-		frame:SetFont("GameFontNormal", 12);
-		frame:SetTextColor(0.1, 0.1, 0.1, 1.0);
-		frame.r = 1.0;
-		frame.g = 1.0;
-		frame.b = 1.0;
-
-		-- set quantity info
-		frame = _G["CauldronQueueReagentItem"..i.."Info"];
-		local countInfo = Cauldron:ReagentCount(queueInfo.name);
-		local qtyText = string.format(L["Have %d"], countInfo.has);
-		if need > 0 then
-			qtyText = qtyText..string.format(L[", need %d"], need);
-		end
-		-- TODO: alts/bank/etc.
-		frame:SetText(qtyText);
-		frame:SetTextColor(0.4, 0.4, 0.4, 1.0);
-		frame:SetShadowOffset(0, 0);
-
-		-- set the icon
-		frame = _G["CauldronQueueReagentItem"..i.."Icon"];
-		frame:SetNormalTexture(queueInfo.icon);
-		frame.link = queueInfo.link;
---		local playerReagentCount = 0; -- TODO
---		if playerReagentCount < queueInfo.amount then
---			frame:SetVertexColor(0.5, 0.5, 0.5, 1.0);
---			frame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
---		else
---			frame:SetVertexColor(1.0, 1.0, 1.0, 1.0);
---			frame:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
---		end
-
-		-- set the amount
-		frame = _G["CauldronQueueReagentItem"..i.."IconCount"];
-		frame:SetText(queueInfo.amount);
-
-		-- place the frame in the scroll view
-		if i > 1 then
-			-- anchor to the frame above
-			self:debug("UpdateQueue: anchor frame to top left of frame above");
-			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueReagentItem"..(i-1)], "BOTTOMLEFT", 0, 0);
-		else
-			-- anchor to the parent
-			self:debug("UpdateQueue: anchor frame to parent");
-			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsReagents, "TOPLEFT", 0, 0);
-		end
-
-		-- adjust the scroll child size
---		reagentHeight = reagentHeight + queueItemFrame:GetHeight() + 2;
---		self:debug("UpdateQueue: height="..height);
---		CauldronQueueFrameScrollFrameQueueSectionsReagents:SetHeight(reagentHeight);
-
-		-- show the frame
-		self:debug("UpdateQueue: show the frame");
-		queueItemFrame:Show();
-	end
-
-	-- hide any remaining frames
-	local j = #reagentList + 1;
-	while true do
-		local frame = _G["CauldronQueueReagentItem"..j];
-		if not frame then
-			break;
-		end
-
-		_G["CauldronQueueReagentItem"..j] = nil;
-
-		frame:Hide();
-		frame:SetHeight(0);
-
-		j = j + 1;
-	end
---]]
-	-- adjust the height of the scroll frame
-	local h = CauldronQueueFrameScrollFrameQueueSectionsMainItemsHeader:GetHeight() +
-			CauldronQueueFrameScrollFrameQueueSectionsMainItems:GetHeight() +
-			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:GetHeight() +
-			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:GetHeight() +
-			CauldronQueueFrameScrollFrameQueueSectionsReagentsHeader:GetHeight() +
-			CauldronQueueFrameScrollFrameQueueSectionsReagents:GetHeight();
-	CauldronQueueFrameScrollFrameQueueSections:SetHeight(h);
-	CauldronQueueFrameScrollFrame:UpdateScrollChildRect();
-
-	self:debug("UpdateQueue exit");
-end
-
-function Cauldron:SaveFramePosition()
- 	self:debug("SaveFramePosition enter");
-
--- TODO
-
- 	self:debug("SaveFramePosition exit");
-end
-
-function Cauldron:OnCauldronUpdate()
-	self:debug("OnCauldronUpdate enter");
-
---	self:Search();
- 	local selectionIndex
- 	if self.vars.selectionIndex == 0 then
- 		selectionIndex = self:GetFirstTradeSkill();
- 	else
- 		selectionIndex = self.vars.selectionIndex;
- 	end
-
-	self:debug("OnCauldronUpdate exit");
-end
-
-function Cauldron:FilterDropDown_OnLoad(dropdown)
-	self:debug("FilterDropDown_OnLoad enter");
-
---[[
-	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
-		return;
-	end
---]]
-
-	UIDropDownMenu_Initialize(dropdown, Cauldron.FilterDropDown_Initialize);
-	UIDropDownMenu_SetText(CauldronFiltersFilterDropDown, L["Filters"]);
-
-	self:debug("FilterDropDown_OnLoad exit");
-end
-
-function Cauldron:InvSlotDropDown_OnLoad(dropdown)
-	self:debug("InvSlotDropDown_OnLoad enter");
-
---[[
-	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
-		return;
-	end
---]]
-
-	UIDropDownMenu_Initialize(dropdown, Cauldron.InvSlotDropDown_Initialize);
-	UIDropDownMenu_SetText(CauldronFiltersInvSlotDropDown, L["Slots"]);
-
-	self:debug("InvSlotDropDown_OnLoad exit");
-end
-
-function Cauldron:CategoryDropDown_OnLoad(dropdown)
-	self:debug("CategoryDropDown_OnLoad enter");
-
---[[
-	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
-		return;
-	end
---]]
-
-	UIDropDownMenu_Initialize(dropdown, Cauldron.CategoryDropDown_Initialize);
-	UIDropDownMenu_SetText(CauldronFiltersCategoryDropDown, L["Categories"]);
-
-	self:debug("CategoryDropDown_OnLoad exit");
-end
-
-function Cauldron:FilterDropDown_Initialize(level)
-	Cauldron:debug("FilterDropDown_Initialize enter");
-
---[[
-	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
-		return;
-	end
---]]
-
-	if not Cauldron.db then
-		return;
-	end
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	UIDropDownMenu_SetText(CauldronFiltersFilterDropDown, L["Filters"]);
-
-	-- sorting
-
-	local sortingTitle = {
-		text = L["Sort"],
-		isTitle = true,
-		tooltipTitle = "",
-		tooltipText = "",
-	};
-	UIDropDownMenu_AddButton(sortingTitle);
-
-	local sortAlpha = {
-		text = L["Alphabetically"],
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortAlpha,
-		tooltipTitle = L["Alphabetically"],
-		tooltipText = L["Set the sorting method to use on the skills list"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
-		arg1 = "alpha",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(sortAlpha);
-
-	local sortDifficulty = {
-		text = L["By difficulty"],
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDifficulty,
-		tooltipTitle = L["By difficulty"],
-		tooltipText = L["Set the sorting method to use on the skills list"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
-		arg1 = "difficulty",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(sortDifficulty);
-
-	--[[
-	local sortBenefit = {
-		text = L["By benefit"],
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit,
-		tooltipTitle = L["By benefit"],
-		tooltipText = L["Set the sorting method to use on the skills list"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
-		arg1 = "benefit",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(sortBenefit);
-	--]]
-
-	-- spacer
-	UIDropDownMenu_AddButton({
-		text = "",
-		notClickable = true,
-	});
-
-	-- skill difficulty
-
-	local difficultyTitle = {
-		text = L["Difficulty"],
-		isTitle = true,
-		tooltipTitle = "",
-		tooltipText = "",
-	};
-	UIDropDownMenu_AddButton(difficultyTitle);
-
-	local difficultyOptimal = {
-		text = L["Optimal"],
---		textR = 1.0,
---		textG = 1.0,
---		textB = 1.0,
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.optimal,
---		keepShownOnClick = true,
-		tooltipTitle = L["Optimal"],
-		tooltipText = L["Set whether items of this difficulty level should be shown"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
-		arg1 = "optimal",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(difficultyOptimal);
-
-	local difficultyMedium = {
-		text = L["Medium"],
---		textR = 1.0,
---		textG = 1.0,
---		textB = 1.0,
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.medium,
---		keepShownOnClick = true,
-		tooltipTitle = L["Medium"],
-		tooltipText = L["Set whether items of this difficulty level should be shown"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
-		arg1 = "medium",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(difficultyMedium);
-
-	local difficultyEasy = {
-		text = L["Easy"],
---		textR = 1.0,
---		textG = 1.0,
---		textB = 1.0,
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.easy,
---		keepShownOnClick = true,
-		tooltipTitle = L["Easy"],
-		tooltipText = L["Set whether items of this difficulty level should be shown"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
-		arg1 = "easy",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(difficultyEasy);
-
-	local difficultyTrivial = {
-		text = L["Trivial"],
---		textR = 1.0,
---		textG = 1.0,
---		textB = 1.0,
-		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.trivial,
---		keepShownOnClick = true,
-		tooltipTitle = L["Trivial"],
-		tooltipText = L["Set whether items of this difficulty level should be shown"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
-		arg1 = "trivial",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(difficultyTrivial);
-
-	-- spacer
-	UIDropDownMenu_AddButton({
-		text = "",
-		notClickable = true,
-	});
-
-	if not IsTradeSkillLinked() then
-		local miscTitle = {
-			text = L["Miscellaneous"],
-			isTitle = true,
-			tooltipTitle = "",
-			tooltipText = "",
-		};
-		UIDropDownMenu_AddButton(miscTitle);
-
-		-- favorites
-		local faves = {
-			text = L["Favorites"],
-			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites,
-			tooltipTitle = L["Favorites"],
-			tooltipText = L["Display only favorite skills"],
-			func = function(arg1, arg2) Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites; Cauldron:UpdateSkillList(); end,
-			arg1 = "favorite",
-			arg2 = "",
-		};
-		UIDropDownMenu_AddButton(faves);
-
-		-- spacer
-		UIDropDownMenu_AddButton({
-			text = "",
-			notClickable = true,
-		});
-	end
-
-	-- reagents availability
-
-	local reagentsTitle = {
-		text = L["Reagents"],
-		isTitle = true,
-		tooltipTitle = "",
-		tooltipText = "",
-	};
-	UIDropDownMenu_AddButton(reagentsTitle);
-
-	-- force check "normal" if the list is linked
-	if IsTradeSkillLinked() then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
-	end
-
-	local normal = {
-		text = L["Normal"],
-		checked = Cauldron:ReagentsFilterNormalCheck(),
-		tooltipTitle = L["Reagents"],
-		tooltipText = L["Display the normal list of skills"],
-		func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
-		arg1 = "normal",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(normal);
-
-	if not IsTradeSkillLinked() then
-
-		local haveAllReagents = {
-			text = L["Have all"],
-			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents,
-			tooltipTitle = L["Reagents"],
-			tooltipText = L["Set whether skills for which you have all the required reagents are shown in the list"],
-			func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
-			arg1 = "all",
-			arg2 = "",
-		};
-		UIDropDownMenu_AddButton(haveAllReagents);
-
-		--[[
-		local haveKeyReagents = {
-			text = L["Have key"],
-			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents,
-			tooltipTitle = L["Reagents"],
-			tooltipText = L["Set whether skills for which you have all key reagents (non-vendor available) are shown in the list"],
-			func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
-			arg1 = "key",
-			arg2 = "",
-		};
-		UIDropDownMenu_AddButton(haveKeyReagents);
-		--]]
-
-		local haveAnyReagents = {
-			text = L["Have any"],
-			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents,
-			tooltipTitle = L["Reagents"],
-			tooltipText = L["Set whether skills for which you have any reagents are shown in the list"],
-			func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
-			arg1 = "any",
-			arg2 = "",
-		};
-		UIDropDownMenu_AddButton(haveAnyReagents);
-
-	end
-
-	Cauldron:debug("FilterDropDown_Initialize exit");
-end
-
-function Cauldron:FilterDropDown_SetSort(info)
-	self:debug("FilterDropDown_SetSort enter");
-
-	local sort = info.arg1;
-
-	if sort == "alpha" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortAlpha = true;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortDifficulty = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit = false;
-	elseif sort == "difficulty" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortAlpha = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortDifficulty = true;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit = false;
-	elseif sort == "benefit" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortAlpha = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortDifficulty = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit = true;
-	end
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("FilterDropDown_SetSort exit");
-end
-
-function Cauldron:ReagentsFilterNormalCheck()
-	self:debug("ReagentsFilterNormalCheck enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local checked = true;
-
-	if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents or
-	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents or
-	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents then
-	   	checked = false;
-	end
-
-	self:debug("ReagentsFilterNormalCheck exit");
-
-	return checked;
-end
-
-function Cauldron:FilterDropDown_SetReagentFilter(info)
-	self:debug("FilterDropDown_SetReagentFilter enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local reagents = info.arg1;
-
-	if reagents == "normal" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
-	elseif reagents == "all" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = true;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
-	elseif reagents == "key" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = true;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
-	elseif reagents == "any" then
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
-	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = true;
-	end
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("FilterDropDown_SetReagentFilter exit");
-end
-
-function Cauldron:FilterDropDown_ToggleDifficulty(info)
-	self:debug("FilterDropDown_ToggleDifficulty enter");
-
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter[info.arg1] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter[info.arg1];
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("FilterDropDown_ToggleDifficulty exit");
-end
-
-function Cauldron:InvSlotDropDown_Initialize(level)
-	Cauldron:debug("InvSlotDropDown_Initialize enter");
-
---[[
-	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
-		return;
-	end
---]]
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	UIDropDownMenu_SetText(CauldronFiltersInvSlotDropDown, L["Slots"]);
-
-	local all = {
-		text = L["All slots"],
-		checked = false,
-		tooltipTitle = L["All slots"],
-		func = function(arg1, arg2) Cauldron:InvSlotDropDown_SetSlot(arg1) end,
-		arg1 = "all",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(all);
-
-	local none = {
-		text = L["(None)"],
-		checked = true,
-		tooltipTitle = L["(None)"],
-		func = function(arg1, arg2) Cauldron:InvSlotDropDown_SetSlot(arg1) end,
-		arg1 = "none",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(none);
-
-	local slots = Cauldron:GetSlots(Cauldron.vars.playername, skillName);
-
-	for name, _ in pairs(slots) do
-		if slot ~= "" then
-			local slot = {
-				text = _G[name],
-				checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[name],
-				tooltipTitle = _G[name],
-				func = function(arg1, arg2) Cauldron:InvSlotDropDown_SetSlot(arg1) end,
-				arg1 = name,
-				arg2 = "",
-			};
-			UIDropDownMenu_AddButton(slot);
-		end
-	end
-
-	Cauldron:debug("InvSlotDropDown_Initialize exit");
-end
-
-function Cauldron:SlotsFilterAllCheck()
-	self:debug("SlotsFilterAllCheck enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local checked = true;
-
-	if Cauldron.db then
-		for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots) do
-			if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[name] then
-				checked = false;
-				break;
-			end
-		end
-	end
-
-	self:debug("SlotsFilterAllCheck exit");
-
-	return checked;
-end
-
-function Cauldron:InvSlotDropDown_SetSlot(info)
-	self:debug("InvSlotDropDown_SetSlot enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	self:debug("InvSlotDropDown_SetSlot: info.arg1="..info.arg1);
-
-	if info.arg1 == "all" then
-		self:debug("InvSlotDropDown_SetSlot: selecting all slots...");
-		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots["(none)"] = true;
-		for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots) do
-			self:debug("InvSlotDropDown_SetSlot: name="..name);
-			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[name] = true;
-		end
-	elseif info.arg1 == "none" then
-		self:debug("InvSlotDropDown_SetSlot: selecting special 'none' slot...");
-		local slotName = "(none)";
-		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName] then
-			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName] = true;
-		else
-			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName];
-		end
-	else
-		self:debug("InvSlotDropDown_SetSlot: select a specific slot: "..info.arg1);
-		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1] then
-			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1] = true;
-		else
-			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1];
-		end
-	end
-
-	self:debug("InvSlotDropDown_SetSlot exit");
-end
-
-function Cauldron:CategoryDropDown_Initialize(level)
-	Cauldron:debug("CategoryDropDown_Initialize enter");
-
---[[
-	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
-		return;
-	end
---]]
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	UIDropDownMenu_SetText(CauldronFiltersCategoryDropDown, L["Categories"]);
-
-	local all = {
-		text = L["All categories"],
-		checked = false, -- Cauldron:CategoriesFilterAllCheck(),
-		tooltipTitle = L["All categories"],
-		func = function(arg1, arg2) Cauldron:CategoryDropDown_SetCategory(arg1) end,
-		arg1 = "all",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(all);
-
-	local none = {
-		text = L["No categories"],
-		checked = false, -- Cauldron:CategoriesFilterAllCheck(),
-		tooltipTitle = L["No categories"],
-		func = function(arg1, arg2) Cauldron:CategoryDropDown_SetCategory(arg1) end,
-		arg1 = "none",
-		arg2 = "",
-	};
-	UIDropDownMenu_AddButton(none);
-
-	local categories = Cauldron:GetDefaultCategories(Cauldron.vars.playername, skillName);
-
-	-- sort the category list by alpha
-	local c = {};
-	for name, _ in pairs(categories) do
-		table.insert(c, name);
-	end
-
-	table.sort(c);
-
-	for i, name in ipairs(c) do
-		local category = {
-			text = name,
-			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name].shown,
-			tooltipTitle = name,
-			func = function(arg1, arg2) Cauldron:CategoryDropDown_SetCategory(arg1) end,
-			arg1 = name,
-			arg2 = "",
-		};
-		UIDropDownMenu_AddButton(category);
-	end
-
-	Cauldron:debug("CategoryDropDown_Initialize exit");
-end
-
---[[
-function Cauldron:CategoriesFilterAllCheck()
-	self:debug("CategoriesFilterAllCheck enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local checked = true;
-
-	for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories) do
-		if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name] then
-			checked = false;
-			break;
-		end
-	end
-
-	self:debug("CategoriesFilterAllCheck exit");
-
-	return checked;
-end
---]]
-
-function Cauldron:CategoryDropDown_SetCategory(info)
-	self:debug("CategoryDropDown_SetCategory enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	if info.arg1 == "all" or info.arg1 == "none" then
-		for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories) do
-			local checked = (info.arg1 == "all");
-			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name].shown = checked;
-		end
-	else
-		if not IsShiftKeyDown() then
-			-- uncheck everything
-			for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories) do
-				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name].shown = false;
-			end
-
-			-- check the clicked item
-			Cauldron.db.realm.userdata[self.vars.playername].skills[skillName].window.categories[info.arg1].shown = true;
-		else
-			Cauldron.db.realm.userdata[self.vars.playername].skills[skillName].window.categories[info.arg1].shown = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.categories[info.arg1].shown;
-		end
-	end
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("CategoryDropDown_SetCategory exit");
-end
-
-function Cauldron:CollapseAllButton_OnClick(button)
-	self:debug("CollapseAllButton_OnClick enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	-- reset all the expanded fields to false
-	for name, info in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills) do
-		info.expanded = false;
-	end
-
-	-- unselect the selected skill
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = 0;
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("CollapseAllButton_OnClick exit");
-end
-
-function Cauldron:CollapseItemButton_OnClick(button)
-	self:debug("CollapseItemButton_OnClick enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local skillInfo = button.skillInfo;
-
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = skillInfo.index;
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("CollapseItemButton_OnClick exit");
-end
-
-function Cauldron:SkillItem_OnEnter(frame)
-	self:debug("SkillItem_OnEnter enter");
-
-	local id = frame:GetID();
-	self:debug("SkillItem_OnEnter: id="..id);
-
-	local name = _G["CauldronSkillItem"..id.."SkillName"];
-	if name then
---		name:
-	end
-
-	-- TODO
-
-	self:debug("SkillItem_OnEnter exit");
-end
-
-function Cauldron:SkillItem_OnLeave(frame)
-	self:debug("SkillItem_OnLeave enter");
-
-
-
-	self:debug("SkillItem_OnLeave exit");
-end
-
-function Cauldron:SkillItem_OnClick(frame, button, down)
-	self:debug("SkillItem_OnClick enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-	self:debug("SkillItem_OnClick: skillName="..skillName);
-
-	-- select this frame
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = frame.skillIndex;
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-	Cauldron:UpdateButtons();
-
-	self:debug("SkillItem_OnClick exit");
-end
-
-function Cauldron:TradeSkillFilter_OnTextChanged(frame)
-	self:debug("TradeSkillFilter_OnTextChanged enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local text = frame:GetText();
-	if text == SEARCH then
-		text = "";
-	end
-
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.search = text;
-
-	-- update the UI
-	Cauldron:UpdateSkillList();
-
-	self:debug("TradeSkillFilter_OnTextChanged exit");
-end
-
-function Cauldron:AmountDecrement_OnClick()
-	self:debug("AmountDecrement_OnClick enter");
-
-	local num = CauldronAmountInputBox:GetNumber();
-	num = math.max(1, num - 1);
-	CauldronAmountInputBox:SetNumber(num);
-
-	self:debug("AmountDecrement_OnClick exit");
-end
-
-function Cauldron:AmountIncrement_OnClick()
-	self:debug("AmountIncrement_OnClick enter");
-
-	local num = CauldronAmountInputBox:GetNumber();
-	num = math.min(999, num + 1);
-	CauldronAmountInputBox:SetNumber(num);
-
-	self:debug("AmountIncrement_OnClick exit");
-end
-
-function Cauldron:FavoriteItemButton_OnClick(button)
-	self:debug("FavoriteItemButton_OnClick enter");
-
-	local skillName = CURRENT_TRADESKILL;
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	local skillInfo = button.skillInfo;
-
-	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite = button:GetChecked();
-
-	self:debug("FavoriteItemButton_OnClick exit");
-end
diff --git a/Cauldron/CauldronQueue.lua b/Cauldron/CauldronQueue.lua
deleted file mode 100644
index b6b3550..0000000
--- a/Cauldron/CauldronQueue.lua
+++ /dev/null
@@ -1,463 +0,0 @@
--- $Revision$
--- Cauldron queue management functions
-
-CauldronQueue = {};
-
---[[
-	The following table describes a queue item in the "main" and "intermediate"
-	sections of the queue:
-
-	queueItem = {
-		["name"] = "<name of skill>",
-		["icon"] = "<icon path>",
-		["tradeskill"] = "<name of tradeskill>",
-		["amount"] = <amount>,
-		["priority"] = <priority>,
-		["link"] = "<link>",
-	};
-
-	The following table describes a reagent needed by items in the queue.
-
-	reagent = {
-		["name"] = "<name of item>",
-		["icon"] = "<icon path>",
-		["amount"] = <amount>,
-		["tradeskill"] = "<tradeskill that caused this reagent to be listed>",
-		["link"] = "<link>",
-	};
---]]
-
-function CauldronQueue:NewQueue()
-	local queue = {
-		["main"] = {},
-		["intermediate"] = {},
-		["reagents"] = {},
-	};
-
-	return queue;
-end
-
-function CauldronQueue:NewItem(name, icon, amount, priority, tradeskill, link)
-
-	local queueItem = {
-		["name"] = name or "",
-		["icon"] = icon or "",
-		["tradeskill"] = tradeskill or "",
-		["link"] = link,
-		["amount"] = amount or 1,
-		["priority"] = priority or 0,
-	};
-
-	return queueItem;
-end
-
-function CauldronQueue:NewReagent(name, icon, amount, tradeskill, link)
-
-	local reagent = {
-		["name"] = name or "",
-		["icon"] = icon or "",
-		["amount"] = amount or 1,
-		["tradeskill"] = tradeskill,
-		["link"] = link,
-	};
-
-	return reagent;
-end
-
-function CauldronQueue:GetItems(queue)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return nil;
-	end
-
-	local items = {};
-
-	for _, item in pairs(queue.main) do
-		if item.amount > 0 then
-			table.insert(items, item);
-		end
-	end
-
-	-- sort the list
-	table.sort(items, function(r1, r2) return r2.priority < r1.priority; end);
-
-	return items;
-end
-
-function CauldronQueue:GetIntermediates(queue)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return nil;
-	end
-
-	local items = {};
-
-	for _, item in pairs(queue.intermediate) do
---		if tradeskill then
---			if tradeskill == item.tradeskill then
---				table.insert(items, item);
---			end
---		else
-			table.insert(items, item);
---		end
-	end
-
-	-- sort the list
---	table.sort(items, function(r1, r2) return r2.priority < r1.priority; end);
-
-	return items;
-end
-
-function CauldronQueue:GetReagents(queue)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return nil;
-	end
-
-	local items = {};
-
-	for _, item in pairs(queue.reagents) do
---		if tradeskill then
---			if tradeskill == item.tradeskill then
---				table.insert(items, item);
---			end
---		else
-			table.insert(items, item);
---		end
-	end
-
-	return items;
-end
-
-function CauldronQueue:AddItem(queue, skillInfo, amount, suppressCalc)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return;
-	end
-
-	if not queue.main then
-		queue.main = {};
-	end
-
-	-- look for the item in the "main" section
-	local item = queue.main[skillInfo.name];
-	if item then
-		-- it's there, so increase the amount
-		item.amount = item.amount + amount;
-	else
-		-- it's not there, so create a new instance
-		queue.main[skillInfo.name] = CauldronQueue:NewItem(skillInfo.name, skillInfo.icon, amount, nil, skillInfo.tradeskill);
-	end
-
-	if not suppressCalc then
-		CauldronQueue:CalculateAllRequiredItems(queue);
-	end
-end
-
-function CauldronQueue:CalculateAllRequiredItems(queue)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return;
-	end
-
-	-- reset the intermediate and reagent lists
-	queue.intermediate = {};
-	queue.reagents = {};
-
-	-- iterate over the queued items
-	for name, queueInfo in pairs(queue.main) do
-		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-		CauldronQueue:CalculateRequiredItems(queue, skillInfo, queueInfo.amount);
-	end
-
-end
-
-function CauldronQueue:CalculateRequiredItems(queue, skillInfo, amount)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return;
-	end
-
-	-- get the intermediates and reagents for the item
-	local intermediates, reagents = Cauldron:GetRequiredItems(skillInfo, amount);
-
-	-- check the intermediate list; if the item is available somewhere (inventory, bank, alt, etc.)
-	-- then move it to the reagent list; otherwise, update the intermediate list in the queue
-
-	-- update the intermediate and reagent lists
-	for i, reagent in ipairs(intermediates) do
-		local count = Cauldron:ReagentCount(reagent.name);
-
-		if count.has >= reagent.numRequired then
-			-- add the item to the reagent list if the character has all the required amount
-			table.insert(reagents, reagent);
-		else
-			local amount = reagent.numRequired;
-
-			-- if the character has some, add that amount to the reagent list
-			if count.has > 0 then
-				-- create a reagent copy of the item
-				local newItem = CopyTable(reagent);
-				newItem.numRequired = count.has;
-
-				table.insert(reagents, newItem);
-
-				-- adjust item count to how many need to be crafted
-				amount = reagent.numRequired - count.has;
-			end
-
-			-- add the remaining amount to the intermediate list
-			if amount > 0 then
-				-- adjust the amount if the item produces more than one per execution
-				local intSkillInfo = Cauldron:GetSkillInfoForItem(reagent.name);
-				if intSkillInfo then
-					if intSkillInfo.minMade > 1 then
-						-- we ignore maxMade, since if it is greater than minMade, then the amount
-						-- produced is variable, so we err on the side of caution and account for
-						-- only ever making the minimum possible; besides, each execution of the
-						-- skill will cause the reagent list to be reassessed, so producing more
-						-- will be handled appropriately
-						amount = math.ceil(amount / intSkillInfo.minMade);
-					end
-				end
-
-				CauldronQueue:AddIntermediate(queue, reagent, amount);
-
-				-- add the intermediate's reagents also
-				CauldronQueue:CalculateRequiredItems(queue, intSkillInfo, amount);
-			end
-		end
-	end
-
-	for i, reagent in ipairs(reagents) do
-		CauldronQueue:AddReagent(queue, reagent, reagent.numRequired, skillInfo.tradeskill);
-	end
-
-end
-
-function CauldronQueue:AddIntermediate(queue, reagent, amount)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return;
-	end
-
-	amount = math.max(0, tonumber(amount) or 0);
-
-	if not queue.intermediate then
-		queue.intermediate = {};
-	end
-
-	-- look for the item in the "intermediate" section
-	local item = queue.intermediate[reagent.name];
-	if item then
-		-- it's there, so increase the amount
-		item.amount = item.amount + amount;
-	else
-		local skillInfo = Cauldron:GetSkillInfoForItem(reagent.name);
-
-		-- it's not there, so create a new instance
-		queue.intermediate[reagent.name] = CauldronQueue:NewItem(reagent.name, reagent.icon, amount, nil, skillInfo.tradeskill);
-	end
-
-end
-
-function CauldronQueue:AddReagent(queue, reagent, amount, tradeskill)
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return;
-	end
-
-	amount = math.max(1, tonumber(amount) or 1);
-
-	if not queue.reagents then
-		queue.reagents = {};
-	end
-
-	-- look for the item in the "reagents" section
-	local item = queue.reagents[reagent.name];
-	if item then
-		-- it's there, so increase the amount
-		item.amount = (tonumber(item.amount) or 0) + amount;
-	else
-		-- it's not there, so create a new instance
-		queue.reagents[reagent.name] = CauldronQueue:NewReagent(reagent.name, reagent.icon, amount, tradeskill);
-	end
-
-end
-
-function CauldronQueue:AdjustItemCount(queue, name, delta)
-
-	-- sanity checks
-	if not queue then
-		Cauldron:warn("CauldronQueue:AdjustItemCount: queue not found!");
-		return;
-	end
-
-	local item = queue.main[name];
---[[
-	for qName, qInfo in pairs(queue.main) do
-		if name == qInfo.item then
-			item = qInfo;
-			break;
-		end
-	end
---]]
-	Cauldron:debug("AdjustItemCount: item="..tostring(item));
-	if item then
-		Cauldron:debug("AdjustItemCount: item.amount="..item.amount);
-		item.amount = item.amount + delta;
-		Cauldron:debug("AdjustItemCount: item.amount(delta)="..item.amount);
-
-		if item.amount < 1 then
-			Cauldron:debug("AdjustItemCount: remove item: "..name);
-			queue.main[name] = nil;
-		end
-	end
-
-	Cauldron:debug("AdjustItemCount: calculate required items");
-	CauldronQueue:CalculateAllRequiredItems(queue);
-
-end
-
-function CauldronQueue:RemoveItem(queue, itemName)
-	Cauldron:debug("RemoveItem enter");
-
-	-- sanity checks
-	if (not queue) and (not itemName) then
-		-- TODO: display error
-		return;
-	end
-
-	if queue.main[itemName] then
-		queue.main[itemName] = nil;
-
-		CauldronQueue:CalculateAllRequiredItems(queue);
-	end
-
-	Cauldron:debug("RemoveItem exit");
-end
-
-function CauldronQueue:IncreasePriority(queue, itemName, top)
-	Cauldron:debug("IncreasePriority enter");
-
-	-- sanity checks
-	if (not queue) and (not itemName) then
-		-- TODO: display error
-		return;
-	end
-
-	local item = queue.main[itemName];
-	if item then
-		local priority = item.priority + 1;
-		local highest = 0;
-
-		if top then
-			for _, info in pairs(queue.main) do
-				if info.priority > highest then
-					highest = info.priority;
-				end
-			end
-
-			priority = highest + 1;
-		end
-
-		item.priority = priority;
-	end
-
-	Cauldron:debug("IncreasePriority exit");
-end
-
-function CauldronQueue:DecreasePriority(queue, itemName, bottom)
-	Cauldron:debug("DecreasePriority enter");
-
-	-- sanity checks
-	if (not queue) and (not itemName) then
-		-- TODO: display error
-		return;
-	end
-
-	local item = queue.main[itemName];
-	if item then
-		local priority = item.priority - 1;
-		local lowest = 0;
-
-		if top then
-			for _, info in pairs(queue.main) do
-				if info.priority < lowest then
-					lowest = info.priority;
-				end
-			end
-
-			priority = lowest - 1;
-		end
-
-		item.priority = priority;
-	end
-
-	Cauldron:debug("DecreasePriority exit");
-end
-
-function CauldronQueue:ClearQueue(queue)
-	Cauldron:debug("ClearQueue enter");
-
-	-- sanity checks
-	if not queue then
-		-- TODO: display error
-		return;
-	end
-
-	--[[
-	if tradeskill then
-		Cauldron:debug("ClearQueue: clearing tradeskill: "..tradeskill);
-
-		-- set aside the current main queue
-		Cauldron:debug("ClearQueue: set aside main table");
-		local main = queue.main;
-
-		-- clear out the tables
-		Cauldron:debug("ClearQueue: clear out tables");
-		queue.main = {};
-
-		-- iterate over the items and re-add the ones not for the specified tradeskill
-		Cauldron:debug("ClearQueue: iterate over items");
-		for i, item in ipairs(main) do
-			Cauldron:debug("ClearQueue: item: "..i);
-			if item.tradeskill ~= tradeskill then
-				-- get the skill for the item
-				Cauldron:debug("ClearQueue: item.tradeskill: "..item.tradeskill);
-				local skillInfo = Cauldron:GetSkillInfo(item.tradeskill, item.name);
-
-				-- recalculate
-				Cauldron:debug("ClearQueue: recalculate");
-				CauldronQueue:AddItem(queue, skillInfo, item.amount, true);
-			end
-		end
-
-		CauldronQueue:CalculateAllRequiredItems(queue);
-	else
-	--]]
-
-	queue.main = {};
-	queue.intermediate = {};
-	queue.reagents = {};
-
-	Cauldron:debug("ClearQueue exit");
-end
-
-
diff --git a/Cauldron/CauldronShoppingList.lua b/Cauldron/CauldronShoppingList.lua
deleted file mode 100644
index 50299c8..0000000
--- a/Cauldron/CauldronShoppingList.lua
+++ /dev/null
@@ -1,145 +0,0 @@
--- $Revision$
--- Cauldron shopping list functions
-
-CauldronShopping = {};
-
---[[
-	list = {
-		["<requestor>"] = {
-			["<item name>"] = <quantity>,
-			["<item name>"] = <quantity>,
-			...
-		},
-		["<requestor>"] = {
-			...
-		},
-	};
---]]
-
-function CauldronShopping:NewList()
-
-	local list = {};
-
-	return list;
-end
-
-function CauldronShopping:AddToList(list, requestor, itemName, quantity)
-
-	-- sanity checks
-	if (not list) and (not requestor) and (not itemName) then
-		-- TODO: display error
-		return;
-	end
-
-	quantity = math.max(1, tonumber(quantity) or 1);
-
-	if not list[requestor] then
-		-- initialize the list for the requestor
-		list[requestor] = {};
-	end
-
-	if list[requestor][itemName] then
-		list[requestor][itemName] = list[requestor][itemName] + quantity;
-	else
-		list[requestor][itemName] = quantity;
-	end
-
-end
-
-function CauldronShopping:RemoveFromList(list, requestor, itemName, quantity)
-	-- sanity checks
-	if not list then
-		-- TODO: display error
-		return;
-	end
-
-	if not list[requestor] then
-		-- initialize the list for the requestor
-		list[requestor] = {};
-	end
-
-	if list[requestor][itemName] then
-		if quantity then
-			list[requestor][itemName] = list[requestor][itemName] - quantity;
-			if list[requestor][itemName] < 1 then
-				list[requestor][itemName] = nil;
-			end
-		else
-			list[requestor][itemName] = nil;
-		end
-	end
-end
-
-function CauldronShopping:GetRequestors(list)
-
-	if not list then
-		-- TODO: display error
-		return;
-	end
-
-	local requestors = {};
-
-	for name, _ in pairs(list) do
-		table.insert(requestors, name);
-	end
-
-	return requestors;
-end
-
-function CauldronShopping:ContainsItems(list)
-
-	if not list then
-		Cauldron:warn("CauldronShopping:ContainsItems: missing list!");
-		return false;
-	end
-
-	for _, items in pairs(list) do
-		for _, amount in pairs(items) do
-			if amount > 0 then
-				return true;
-			end
-		end
-	end
-
-	return false;
-end
-
-function CauldronShopping:HasItems(list, requestor)
-
-	if not list then
-		Cauldron:warn("CauldronShopping:HasItems: missing list!");
-		return false;
-	end
-
-	if list[requestor] then
-		for _, amount in pairs(list[requestor]) do
-			if amount > 0 then
-				return true;
-			end
-		end
-	end
-
-	return false;
-end
-
-function CauldronShopping:GetRequestedItems(list, requestor)
-end
-
-function CauldronShopping:EmptyShoppingList(list, requestor)
-
-	if not list then
-		Cauldron:warn("CauldronShopping:EmptyShoppingList: missing list!");
-		return;
-	end
-
-	for r, _ in pairs(list) do
-		if requestor then
-			if requestor == r then
-				list[r] = nil;
-			end
-		else
-			list[r] = nil;
-		end
-	end
-
-end
diff --git a/Cauldron/CauldronShoppingList.xml b/Cauldron/CauldronShoppingList.xml
deleted file mode 100644
index e17dc5f..0000000
--- a/Cauldron/CauldronShoppingList.xml
+++ /dev/null
@@ -1,232 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\..\FrameXML\UI.xsd">
-    <!-- $Revision$ -->
-
-    <!-- templates -->
-    <Frame name="CauldronShoppingListRequestorTemplate" virtual="true">
-    	<Size x="240" y="12" />
-    	<Layers>
-			<Layer level="OVERLAY">
-				<FontString name="$parentName" inherits="GameFontNormal"
-							text="(name)" justifyH="LEFT" justifyV="CENTER">
-					<Size x="240" y="12"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="0" y="0"/>
-						</Anchor>
-					</Anchors>
-				</FontString>
-			</Layer>
-    	</Layers>
-    </Frame>
-
-    <Frame name="CauldronShoppingListItemTemplate" virtual="true">
-    	<Size x="240" y="12" />
-    	<Layers>
-			<Layer level="OVERLAY">
-				<FontString name="$parentItem" inherits="GameFontNormal"
-							text="(item)" justifyH="LEFT" justifyV="CENTER">
-					<Size x="225" y="12"/>
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset x="10" y="0"/>
-						</Anchor>
-					</Anchors>
-					<Color r="1.0" g="1.0" b="1.0" />
-				</FontString>
-			</Layer>
-    	</Layers>
-    	<Frames>
-            <Button name="$parentCloseButton" inherits="UIPanelCloseButton">
-                <Anchors>
-                    <Anchor point="RIGHT">
-                        <Offset>
-                            <AbsDimension x="0" y="0"/>
-                        </Offset>
-                    </Anchor>
-                </Anchors>
-                <Scripts>
-                	<OnLoad>
-                		self:SetScale(0.6);
-                	</OnLoad>
-					<OnEnter>
-						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
-						GameTooltip:ClearLines();
-						GameTooltip:AddLine(Cauldron:LocaleString("Remove this item from the shopping list"));
-						GameTooltip:Show();
-						CursorUpdate(self);
-					</OnEnter>
-					<OnLeave>
-						GameTooltip:Hide();
-						ResetCursor();
-					</OnLeave>
-                    <OnClick>
-                        Cauldron:RemoveShoppingListItem(self:GetParent().requestor, self:GetParent().itemName);
-                        Cauldron:UpdateShoppingList();
-                    </OnClick>
-                </Scripts>
-            </Button>
-    	</Frames>
-    </Frame>
-
-	<!-- main window -->
-	<Frame name="CauldronShoppingListFrame" toplevel="true"
-		   frameStrata="LOW" parent="UIParent"
-		   movable="true" resizable="true" enableMouse="true" hidden="true">
-		<Size x="250" y="300" />
-
-		<ResizeBounds>
-			<minResize>
-				<AbsDimension x="75" y="75"/>
-			</minResize>
-			<maxResize>
-				<AbsDimension x="400" y="900"/>
-			</maxResize>
-		</ResizeBounds>
-		<Anchors>
-			<Anchor point="TOPRIGHT" relativeTo="UIParent" relativePoint="TOPRIGHT">
-				<Offset>
-					<AbsDimension x="-50" y="-200" />
-				</Offset>
-			</Anchor>
-		</Anchors>
-		<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background"
-				  edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="false">
-			<BackgroundInsets>
-				<AbsInset left="0" right="0" top="0" bottom="0" />
-			</BackgroundInsets>
-			<EdgeSize>
-				<AbsValue val="2" />
-			</EdgeSize>
-		</Backdrop>
-
-		<!-- Window Title -->
-		<Layers>
-			<Layer level="BORDER">
-				<FontString name="$parentTitleText" inherits="GameFontNormal" text="Shopping List">
-					<Anchors>
-						<Anchor point="TOP" relativeTo="CauldronShoppingListFrame" relativePoint="TOP">
-							<Offset>
-								<AbsDimension x="0" y="-4"/>
-							</Offset>
-						</Anchor>
-					</Anchors>
-				</FontString>
-			</Layer>
-		</Layers>
-
-		<Frames>
-            <!-- Close button -->
-            <Button name="$parentCloseButton" inherits="UIPanelCloseButton">
-                <Anchors>
-                    <Anchor point="TOPRIGHT">
-                        <Offset>
-                            <AbsDimension x="0" y="0"/>
-                        </Offset>
-                    </Anchor>
-                </Anchors>
-                <Scripts>
-                	<OnLoad>
-                		self:SetScale(0.75);
-                	</OnLoad>
-                    <OnClick>
-                        Cauldron:HideShoppingList();
-                    </OnClick>
-                </Scripts>
-            </Button>
-            <ScrollFrame name="$parentItemsScrollFrame">
-            	<Size x="240" y="280" />
-            	<Anchors>
-            		<Anchor point="TOPLEFT">
-            			<Offset>
-            				<AbsDimension x="5" y="-20" />
-            			</Offset>
-            		</Anchor>
-            		<Anchor point="BOTTOMRIGHT">
-            			<Offset>
-            				<AbsDimension x="-5" y="5" />
-            			</Offset>
-            		</Anchor>
-            	</Anchors>
-            	<ScrollChild>
-            		<Frame name="$parentScrollChild">
-						<Size x="240" y="280" />
-						<Anchors>
-							<Anchor point="TOPLEFT">
-								<Offset x="0" y="0"/>
-							</Anchor>
-						</Anchors>
-            		</Frame>
-            	</ScrollChild>
-            </ScrollFrame>
-			<Button name="$parentResizeCorner">
-				<Size x="16" y="16"/>
-				<Anchors>
-					<Anchor point="BOTTOMRIGHT">
-						<Offset x="-3" y="3"/>
-					</Anchor>
-				</Anchors>
-				<Scripts>
-					<OnMouseDown>
-						if button == "LeftButton" then
-							self:GetParent():StartSizing();
-							self:GetParent().isResizing = true;
-						end
-					</OnMouseDown>
-					<OnLoad>
-						self:GetNormalTexture():SetVertexColor(0.6, 0.6, 0.6);
-					</OnLoad>
-					<OnMouseUp>
-						if button == "LeftButton" then
-							self:GetParent():StopMovingOrSizing();
-							self:GetParent().isResizing = false;
-							Cauldron:UpdateShoppingList();
-						end
-					</OnMouseUp>
-					<OnHide>
-						self:GetParent():StopMovingOrSizing()
-					</OnHide>
-				</Scripts>
-				<NormalTexture file="Interface\AddOns\Cauldron\Artwork\resize"/>
-			</Button>
-		</Frames>
-
-		<Scripts>
-			<OnLoad>
-				self:SetBackdropColor(.05,.05,.05,.8);
-				self:SetBackdropBorderColor(.4,.4,.4,1);
---				tinsert(UISpecialFrames, self:GetName());
-			</OnLoad>
-			<OnShow>
-				PlaySound("igCharacterInfoOpen");
-			</OnShow>
-			<OnHide>
-				PlaySound("igCharacterInfoClose");
-			</OnHide>
-			<OnMouseWheel>
-				return;
-			</OnMouseWheel>
-			<OnMouseDown>
-				if button == "LeftButton" then
-					self:StartMoving();
-					self.isResizing = true;
-				end
-			</OnMouseDown>
-			<OnMouseUp>
-				if button == "LeftButton" then
-					self:StopMovingOrSizing();
-					self.isResizing = false;
-					Cauldron:UpdateShoppingList();
-					-- TradeskillInfoUI:Frame_Update()
-					-- CauldronShopping:SaveShoppingListFramePosition();
-				end
-			</OnMouseUp>
-			<OnSizeChanged>
-				-- TradeskillInfoUI:Frame_Update()
-			</OnSizeChanged>
-		</Scripts>
-
-	</Frame>
-
-</Ui>
\ No newline at end of file
diff --git a/Cauldron/CauldronShoppingListUI.lua b/Cauldron/CauldronShoppingListUI.lua
deleted file mode 100644
index f30dea5..0000000
--- a/Cauldron/CauldronShoppingListUI.lua
+++ /dev/null
@@ -1,181 +0,0 @@
--- $Revision$
--- Cauldron shopping list UI functions
-
-function Cauldron:ShoppingList_Toggle()
-
-	if CauldronShoppingListFrame then
-		if CauldronShoppingListFrame:IsShown() then
-			Cauldron:HideShoppingList();
-		else
-			Cauldron:ShowShoppingList();
-		end
-	end
-
-end
-
-function Cauldron:ShowShoppingList()
-
-	if CauldronShoppingListFrame then
-		CauldronShoppingListFrame:Show();
-
-		--[[
-		local s = CauldronShoppingListFrame:GetEffectiveScale();
-
-		if self.db.profile.ShoppingListPositionX and self.db.profile.ShoppingListPositionY then
-			CauldronShoppingListFrame:SetPoint("TOPLEFT",
-											   self.db.profile.ShoppingListPositionX,
-											   self.db.profile.ShoppingListPositionY);
-		end
-
-		if self.db.profile.ShoppingListWidth then
-			CauldronShoppingListFrame:SetWidth(self.db.profile.ShoppingListWidth);
-		end
-		if self.db.profile.ShoppingListHeight then
-			CauldronShoppingListFrame:SetHeight(self.db.profile.ShoppingListHeight);
-		end
-		--]]
-
-		self.db.profile.showShoppingList = true;
-	end
-
-	Cauldron:UpdateShoppingList();
-
-end
-
-function Cauldron:HideShoppingList()
-
-	if CauldronShoppingListFrame then
-		CauldronShoppingListFrame:Hide();
-		self.db.profile.showShoppingList = false;
-	end
-
-end
-
-function Cauldron:UpdateShoppingList()
-
-	if not CauldronShoppingListFrame:IsShown() then
-		return;
-	end
-
-	local list = self.db.realm.shopping;
-
-	local reqIndex = 1;
-	local itemIndex = 1;
-
-	local width = CauldronShoppingListFrame:GetWidth();
-	local height = CauldronShoppingListFrame:GetHeight();
-
-	-- adjust inner frame sizes
-	CauldronShoppingListFrameItemsScrollFrame:SetWidth(width - 10);
-	CauldronShoppingListFrameItemsScrollFrame:SetHeight(height - 20);
-	CauldronShoppingListFrameItemsScrollFrameScrollChild:SetWidth(width - 10);
-
-	local frameAbove = nil;
-
-	-- iterate over the requestors
-	for requestor, items in pairs(list) do
-
-		if CauldronShopping:HasItems(list, requestor) then
-
-			local shoppingListRequestor = _G["CauldronShoppingListRequestor"..reqIndex];
-
-			-- create a frame for the requestor
-			if not shoppingListRequestor then
-				-- create a new frame for the skill information
-				shoppingListRequestor = CreateFrame("Button",
-													"CauldronShoppingListRequestor"..reqIndex,
-													CauldronShoppingListFrameItemsScrollFrameScrollChild,
-													"CauldronShoppingListRequestorTemplate");
-			end
-
-			_G["CauldronShoppingListRequestor"..reqIndex.."Name"]:SetText(requestor);
-			_G["CauldronShoppingListRequestor"..reqIndex.."Name"]:SetWidth(width - 10);
-
-			_G["CauldronShoppingListRequestor"..reqIndex]:SetWidth(width - 10);
-
-			-- place the frame in the scroll view
-			if frameAbove then
-				-- anchor to the frame above
-				self:debug("UpdateShoppingList: anchor frame to top left of frame above");
-				shoppingListRequestor:SetPoint("TOPLEFT", frameAbove, "BOTTOMLEFT", 0, -2);
-			else
-				-- anchor to the parent
-				self:debug("UpdateShoppingList: anchor frame to parent");
-				shoppingListRequestor:SetPoint("TOPLEFT", CauldronShoppingListFrameItemsScrollFrameScrollChild, "TOPLEFT", 0, 0);
-			end
-
-			shoppingListRequestor:Show();
-
-			frameAbove = shoppingListRequestor;
-
-			-- add items for the requestor
-			for item, amount in pairs(items) do
-
-				local shoppingListItem = _G["CauldronShoppingListItem"..itemIndex];
-
-				-- create a frame for the item
-				if not shoppingListItem then
-					-- create a new frame for the skill information
-					shoppingListItem = CreateFrame("Button",
-												   "CauldronShoppingListItem"..itemIndex,
-												   CauldronShoppingListFrameItemsScrollFrameScrollChild,
-												   "CauldronShoppingListItemTemplate");
-				end
-
-				local str = string.format("%s, %d", item, amount);
-
-				shoppingListItem.itemName = item;
-				shoppingListItem.requestor = requestor;
-
-				_G["CauldronShoppingListItem"..itemIndex.."Item"]:SetText(str);
-				_G["CauldronShoppingListItem"..itemIndex.."Item"]:SetWidth(width - 25);
-
-				_G["CauldronShoppingListItem"..itemIndex]:SetWidth(width - 25);
-
-				-- place the frame in the scroll view
-				if frameAbove then
-					-- anchor to the frame above
-					self:debug("UpdateShoppingList: anchor frame to top left of frame above");
-					shoppingListItem:SetPoint("TOPLEFT", frameAbove, "BOTTOMLEFT", 0, 0);
-				end
-
-				shoppingListItem:Show();
-
-				frameAbove = shoppingListItem;
-
-				itemIndex = itemIndex + 1;
-
-			end
-
-			reqIndex = reqIndex + 1;
-
-		end
-	end
-
-	-- set scroll child frame height
-	CauldronShoppingListFrameItemsScrollFrameScrollChild:SetHeight((reqIndex - 1) * 12 + (itemIndex - 1) * 12);
-
-	while true do
-		local frame = _G["CauldronShoppingListRequestor"..reqIndex];
-		if not frame then
-			break;
-		end
-
-		frame:Hide();
-		frame:SetHeight(0);
-
-		reqIndex = reqIndex + 1;
-	end
-	while true do
-		local frame = _G["CauldronShoppingListItem"..itemIndex];
-		if not frame then
-			break;
-		end
-
-		frame:Hide();
-		frame:SetHeight(0);
-
-		itemIndex = itemIndex + 1;
-	end
-
-end
diff --git a/Cauldron/CauldronTradeskill.lua b/Cauldron/CauldronTradeskill.lua
deleted file mode 100644
index 82065dd..0000000
--- a/Cauldron/CauldronTradeskill.lua
+++ /dev/null
@@ -1,436 +0,0 @@
--- $Revision$
--- Cauldron tradeskill functions
-
-function Cauldron:UpdateSkills()
-	self:debug("UpdateSkills enter");
-
-	local skillName = GetTradeSkillLine();
-	local baseSkillName = skillName;
-	self:debug("UpdateSkills: skillName="..skillName);
-
-	if skillName == "UNKNOWN" then
-		return;
-	end
-
-	if IsTradeSkillLinked() then
-		skillName = "Linked-"..skillName;
-	end
-
-	-- initialize the trade skill entry
-	if not self.db.realm.userdata[self.vars.playername].skills[skillName] then
-		self.db.realm.userdata[self.vars.playername].skills[skillName] = {};
-	end
-
-	-- save the skill entry in a local var
-	local skillDB = self.db.realm.userdata[self.vars.playername].skills[skillName];
-	skillDB.recipes = {};
-
-	-- initialize window information, if necessary
-	if not skillDB.window then
-		skillDB.window = {
-			search = "",
-			filter = {
-				optimal = true,
-				medium = true,
-				easy = true,
-				trivial = true,
-				haveAllReagents = false,
-				haveKeyReagents = false,
-				haveAnyReagents = false,
-				sortDifficulty = true,
-				sortAlpha = false,
-				sortBenefit = false,
-				favorites = false,
-			},
-			skills = {},
-			slots = {},
-			categories = {},
-			selected = 1,
-		};
-	end
-
-	-- make sure we're getting a full list
-	SetTradeSkillItemNameFilter(nil);
-	SetTradeSkillItemLevelFilter(0, 0);
-
-	local category = "";
-
-	for i=1,GetNumTradeSkills() do
-		local name, difficulty, avail, expanded, verb = GetTradeSkillInfo(i);
---		self:debug("UpdateSkills: name="..name.."; difficulty="..difficulty.."; avail="..avail);
-
-		if name and difficulty ~= "header" then
-			local link = GetTradeSkillItemLink(i);
-			local minMade, maxMade = GetTradeSkillNumMade(i);
-			local _, _, _, _, _, _, _, _, slot, _ = GetItemInfo(link);
-
-			local keywords = name;
-
-			-- fill in the db entry
-			skillDB.recipes[name] = {
-				['index'] = i,
-				['name'] = name,
-				['link'] = link,
-				['icon'] = GetTradeSkillIcon(i),
-				['tradeskill'] = baseSkillName,
-				['difficulty'] = difficulty,
-				['available'] = avail,
-				['minMade'] = minMade,
-				['maxMade'] = maxMade,
-
-				-- filter information
-				['slot'] = slot,
-				['defaultCategory'] = category,
-			};
-
-			-- set the action verb for this skill
-			skillDB.recipes[name].verb = verb;
-
-			-- make sure the skill window info is initialized
-			if not skillDB.window.skills[name] then
-				skillDB.window.skills[name] = {
-					['expanded'] = false,
-					['favorite'] = false,
-				};
-			end
-
-			-- make sure the category for the window is initialized
-			if category ~= "" then
-				if not skillDB.window.categories[category] then
-					skillDB.window.categories[category] = {
-						['shown'] = true,
-						['expanded'] = true,
-					};
-				end
-			end
-
-			-- populate the slot list
-			if slot and (slot ~= "") then
-				if not skillDB.window.slots[slot] then
-					skillDB.window.slots[slot] = true;
-				end
-			end
-
-			-- clear the reagent list
-			skillDB.recipes[name].reagents = {};
-
-			for j=1,GetTradeSkillNumReagents(i) do
-				local rname, rtex, rcount, hasCount = GetTradeSkillReagentInfo(i,j);
-				self:debug("UpdateSkills: rname="..tostring(rname).."; rtex="..tostring(rtex).."; rcount="..tostring(rcount).."; hasCount="..tostring(hasCount));
-
-				if rname then
-					table.insert(skillDB.recipes[name].reagents, {
-						['name'] = rname,
-						['icon'] = rtex,
-						['numRequired'] = rcount,
-						['toonHas'] = hasCount,
-						['index'] = j,
-						['skillIndex'] = i,
-					});
-
-					keywords = keywords..","..rname;
-				end
-			end
-
-			-- fill in the db entry
-			skillDB.recipes[name].keywords = keywords;
-	    else
-	    	-- save the header name
-	    	if name then
-		    	category = name;
-
-				-- expand the header, so we get all the skills
-				if not expanded then
-					ExpandTradeSkillSubClass(i);
-				end
-			end
-		end
-	end
-
-	self:debug("UpdateSkills exit");
-end
-
-function Cauldron:GetDefaultCategories(player, skillName)
-	self:debug("GetDefaultCategories enter");
-
-	local categories = {};
-
-	if self.db then
-		for name, info in pairs(self.db.realm.userdata[player].skills[skillName].window.categories) do
-			categories[name] = info.shown;
-		end
-	end
-
---	table.sort(categories);
-
-	self:debug("GetDefaultCategories exit");
-
-	return categories;
-end
-
---[[
-function Cauldron:GetCategories(skillList)
-	self:debug("GetCategories enter");
-
-	local categories = {};
-
-	if not skillList then
-		return categories;
-	end
-
-	for _, info in ipairs(skillList) do
-		table.insert(categories, info.defaultCategory);
-	end
-
-	table.sort(categories);
-
-	self:debug("GetCategories exit");
-
-	return categories;
-end
---]]
-
-function Cauldron:GetSlots(player, skillName)
-	self:debug("GetSlots enter");
-
-	local slots = {};
-
-	if self.db then
-		for name, info in pairs(self.db.realm.userdata[player].skills[skillName].window.slots) do
-			slots[name] = info;
-		end
-	end
-
---	table.sort(slots);
-
-	self:debug("GetSlots exit");
-
-	return slots;
-end
-
-function Cauldron:GetSkillList(playername, skillName)
-	self:debug("GetSkillList enter");
-
-	if (not playername) or (not skillName) then
-		self:warn("GetSkillList: playername ("..tostring(playername)..") or skillName ("..tostring(skillName)..") not set!");
-		return;
-	end
-
-	local skills = {};
-
-	for name, recipe in pairs(self.db.realm.userdata[playername].skills[skillName].recipes) do
-		self:debug("GetSkillList: name="..name);
-
-		local add = true;
-
-		-- check the search text
-		local search = self.db.realm.userdata[playername].skills[skillName].window.search or "";
-		self:debug("GetSkillList: search="..search);
-		if #search > 0 then
-			-- check for numbers
-			local minLevel, maxLevel;
-			local approxLevel = strmatch(search, "^~(%d+)");
-			-- self:debug("GetSkillList: approxLevel="..tostring(approxLevel));
-			if ( approxLevel ) then
-				minLevel = approxLevel - 2;
-				maxLevel = approxLevel + 2;
-			else
-				minLevel, maxLevel = strmatch(search, "^(%d+)%s*-*%s*(%d*)$");
-				-- self:debug("GetSkillList: minLevel="..tostring(minLevel).."; maxLevel="..tostring(maxLevel));
-			end
-			if ( minLevel ) then
-				if ( maxLevel == "" or maxLevel < minLevel ) then
-					maxLevel = minLevel;
-				end
-
-				-- TODO
-				-- self:debug("GetSkillList: TODO; filter by level");
---				SetTradeSkillItemNameFilter(nil);
---				SetTradeSkillItemLevelFilter(minLevel, maxLevel);
-			else
-				-- match name or reagents
-				self:debug("GetSkillList: match by name or reagents");
-				if not string.find(string.lower(recipe.keywords), string.lower(search)) then
-					self:debug("skipping recipe: "..name.." (keywords: "..recipe.keywords..")");
-					add = false;
-				end
-			end
-
-		end
-
-		-- check difficulty filter
-		if not self.db.realm.userdata[playername].skills[skillName].window.filter[recipe.difficulty] then
-			self:debug("skipping recipe: "..name.." (difficulty: "..recipe.difficulty..")");
-			add = false;
-		end
-
-		-- check categories
-		local catInfo = self.db.realm.userdata[playername].skills[skillName].window.categories[recipe.defaultCategory];
-		if catInfo and (not catInfo.shown) then
-			self:debug("skipping recipe: "..name.." (category: "..recipe.defaultCategory..")");
-			add = false;
-		end
-
-		-- check slot
-		--[[
-		local slotName = recipe.slot;
-		if slotName == "" then
-			slotName = "(none)";
-		end
-		local slotInfo = self.db.realm.userdata[playername].skills[skillName].window.slots[slotName];
-		self:debug("slotInfo: "..tostring(slotInfo));
-		if not slotInfo then -- more
-			self:debug("skipping recipe: "..name.." (slot: "..slotName..")");
-			add = false;
-		end
-		--]]
-
-		-- check reagent filter
-		if self.db.realm.userdata[playername].skills[skillName].window.filter.haveAllReagents then
-			-- check if the available count is 0
-			if recipe.available == 0 then
-				add = false;
-			end
-		elseif self.db.realm.userdata[playername].skills[skillName].window.filter.haveKeyReagents then
-			-- check if the reagent count for key reagents is 0
-		elseif self.db.realm.userdata[playername].skills[skillName].window.filter.haveAnyReagents then
-			-- check if the reagent count for any reagent is 0
-			for rname, rinfo in pairs(recipe.reagents) do
-				-- check possession count
-				if rinfo.toonHas == 0 then
---					if Cauldron:GetAltReagentCount(rinfo) == 0 then
-						add = false;
---					end
-				end
-			end
-		end
-
-		-- check favorites filter
-		if self.db.realm.userdata[playername].skills[skillName].window.filter.favorites then
-			if not self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].favorite then
-				self:debug("skipping recipe: "..name.." (favorite: "..tostring(self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].favorite)..")");
-				add = false;
-			end
-		end
-
-		-- we got here, add the recipe to the list
-		if add then
-			table.insert(skills, recipe);
-		end
-	end
-
-	-- sort the list
-	table.sort(skills, function(r1, r2)
-			if (not r1) or (not r2) then
-				return true;
-			end
-
-			self:debug("GetSkillList: sorting: r1.name="..r1.name.."; r2.name="..r2.name);
-			if self.db.realm.userdata[playername].skills[skillName].window.filter.sortAlpha then
-				self:debug("GetSkillList: sorting by alpha");
-				return r1.name < r2.name;
-			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortDifficulty then
-				self:debug("GetSkillList: sorting by difficulty");
-				local difficulty = {
-					optimal = 4,
-					medium = 3,
-					easy = 2,
-					trivial = 1,
-				};
-
-				self:debug("GetSkillList: r1.difficulty="..r1.difficulty);
-				self:debug("GetSkillList: r2.difficulty="..r2.difficulty);
-				return difficulty[r1.difficulty] > difficulty[r2.difficulty];
-			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortBenefit then
-				self:debug("GetSkillList: returning true for benefit sorting");
-				return true; -- TODO
-			end
-
-			self:debug("GetSkillList: returning default true");
-			return true;
-		end);
-
-	self:debug("GetSkillList exit");
-
-	return skills;
-end
-
-function Cauldron:GetSkillInfo(tradeskill, skill)
-	self:debug("GetSkillInfo enter");
-
-	-- sanity checks
-	if (not tradeskill) or (not skill) then
-		self:warn("GetSkillInfo: missing tradeskill ("..tostring(tradeskill)..") or skill ("..tostring(skill)..")!");
-		return nil;
-	end
-
-	if not self.db.realm.userdata[self.vars.playername].skills[tradeskill] then
-		return nil;
-	end
-
-	local skillInfo = self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes[skill];
-	if not skillInfo then
-		-- couldn't find a skill with the item name, so scan the list for skills that craft
-		-- the item
-		for _, recipe in pairs(self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes) do
-			local name, _ = GetItemInfo(recipe.link);
-			if name == skill then
-				return recipe;
-			end
-		end
-	end
-
-	self:debug("GetSkillInfo exit");
-
-	return skillInfo;
-end
-
-function Cauldron:GetSkillInfoForItem(item)
-
-	for tradeskill, list in pairs(self.db.realm.userdata[self.vars.playername].skills) do
-		-- skip linked skills
-		if not (string.find(tradeskill, "Linked-")) then
-			for _, recipeInfo in pairs(list.recipes) do
-				local name, _ = GetItemInfo(recipeInfo.link);
-				if name == item then
-					return recipeInfo;
-				end
-			end
-		end
-	end
-
-	return nil;
-end
-
-function Cauldron:GetRequiredItems(skillInfo, amount)
-
-	local intermediates = {};
-	local reagents = {};
-
-	-- sanity checks
-	if not skillInfo then
-		-- TODO: display error
-		return intermediates, reagents;
-	end
-
-	amount = math.max(1, tonumber(amount) or 1);
-
-	-- find out what the reagents are
-	for i, reagent in ipairs(skillInfo.reagents) do
-
-		-- copy the reagent info so we can modify the amounts
-		local r = CopyTable(reagent);
-		r.numRequired = r.numRequired * amount;
-
-		-- see if the character can make the item
-		local si = Cauldron:GetSkillInfoForItem(r.name);
-		if si then
-			table.insert(intermediates, r);
-		else
-			table.insert(reagents, r);
-		end
-	end
-
-	return intermediates, reagents;
-end
-
diff --git a/Cauldron/CauldronUtil.lua b/Cauldron/CauldronUtil.lua
deleted file mode 100644
index ab6aaf4..0000000
--- a/Cauldron/CauldronUtil.lua
+++ /dev/null
@@ -1,84 +0,0 @@
--- $Revision$
--- Cauldron utility functions
-
-function Cauldron:GetAltReagentCount(reagentInfo)
-	self:debug("GetAltReagentCount enter");
-
-	-- TODO
-
-	self:debug("GetAltReagentCount exit");
-end
-
-function Cauldron:GetPotentialCraftCount(skill)
-	self:debug("GetPotentialCraftCount enter");
-
-	local count = 0;
-
-	-- TODO
-
-	self:debug("GetPotentialCraftCount exit");
-
-	return count;
-end
-
-function Cauldron:ReagentCount(reagent)
-
-	local count = {
-		has = 0,
-		bank = 0,
-		guildBank = 0,
-		mail = 0,
-		altHas = {},
-	}
-
-	-- sanity checks
-	if not reagent then
-		-- TODO: display error
-		return count;
-	end
-
-	count.has = GetItemCount(reagent, false);
-
-
-	-- TODO: find in banks, on alts, etc.
-	if BankItems_SelfCache then
-		-- TODO
-		count.bank = BankItems_SelfCache[reagent].bank;
-		count.mail = BankItems_SelfCache[reagent].mail;
-	end
-
-	if BankItems_GuildCache then
---		count.guildBank = BankItems_GuildCache[reagent].
-	end
-
-
-	return count;
-end
-
-function Cauldron:ScanForItem(name)
-	-- look through bags
-
-end
-
-function Cauldron:SkillContainsText(recipe, text)
-
-	-- sanity checks
-	if (not recipe) or (not text) then
-		-- TODO: display error
-		return false;
-	end
-
-	if string.find(recipe.name, text) then
-		return true;
-	end
-
-	for i, reagent in ipairs(recipe.reagents) do
-		if string.find(reagent.name, text) then
-			return true;
-		end
-	end
-
-	-- TODO: check flavor text?
-
-	return false;
-end
diff --git a/Cauldron/Locale/Cauldron-enUS.lua b/Cauldron/Locale/Cauldron-enUS.lua
deleted file mode 100644
index e2b80df..0000000
--- a/Cauldron/Locale/Cauldron-enUS.lua
+++ /dev/null
@@ -1,104 +0,0 @@
--- $Revision: 1.3 $
--- Cauldron language file: enUS
-
-local L = LibStub("AceLocale-3.0"):NewLocale("Cauldron", "enUS", true)
-if not L then return end
-
---
-L["Cauldron"] = true
-L["Cauldron loaded; version "] = true
-L["Version "] = true
-L["Current log level: "] = true
-L["Setting log level: "] = true
-L["Config"] = true
-L["Show config screen"] = true
-L["Log level"] = true
-L["Change Cauldron logging level"] = true
-L["Menu"] = true
-L["Show Cauldron UI"] = true
-L["Shopping list"] = true
-L["Open shopping list window"] = true
-L["Reset"] = true
-L["Resets Cauldron to a fresh state"] = true
-
-L["Player known"] = true
-L["Player can learn"] = true
-L["Player will be able to learn"] = true
-L["Alt known"] = true
-L["Alt can learn"] = true
-L["Alt will be able to learn"] = true
-L["Unavailable"] = true
-
-L["Neutral"] = true
-L["Alliance"] = true
-L["Horde"] = true
-
-L["Version"] = true
-L["Shows the version number of the addon"] = true
-
-L["Opposing"] = true
-L["Include recipes from opposing faction"] = true
-L["Name"] = true
-L["Search for name"] = true
-L["Reagent"] = true
-L["Search for reagents"] = true
-
-L["Sort"] = true
-L["Alphabetically"] = true
-L["By difficulty"] = true
-L["By benefit"] = true
-L["Set the sorting method to use on the skills list"] = true
-
-L["Filters"] = true
-L["Difficulty"] = true
-L["Optimal"] = true
-L["Medium"] = true
-L["Easy"] = true
-L["Trivial"] = true
-L["Set whether items of this difficulty level should be shown"] = true
-L["Miscellaneous"] = true
-L["Favorites"] = true
-L["Display only favorite skills"] = true
-L["Mark this skill as a favorite"] = true
-L["Reagents"] = true
-L["Display the normal list of skills"] = true
-L["Set whether skills for which you have all the required reagents are shown in the list"] = true
-L["Set whether skills for which you have all key reagents (non-vendor available) are shown in the list"] = true
-L["Set whether skills for which you have any reagents are shown in the list"] = true
-L["Normal"] = true
-L["Have all"] = true
-L["Have key"] = true
-L["Have any"] = true
-
-L["Slots"] = true
-L["All slots"] = true
-L["(None)"] = true
-
-L["Categories"] = true
-L["All categories"] = true
-L["No categories"] = true
-
-L["Requires"] = true
-
-L["In order to make:"] = true
-L["You first have to make:"] = true
-L["You will need:"] = true
-
-L["Have %d"] = true
-L[", need %d"] = true
-
-L["Crafting %1$d of %2$s..."] = true
-
-L["Remove this item from the queue"] = true
-L["Increase the priority of this item"] = true
-L["Shift-click to move to the top of the queue"] = true
-L["Decrease the priority of this item"] = true
-L["Shift-click to move to the bottom of the queue"] = true
-L["Add this item to the shopping list"] = true
-L["Decrease the amount of this item"] = true
-
-L["Remove this item from the shopping list"] = true
-
--- error messages
-L["Crafting %1$s requires the %2$s skill."] = true
-
diff --git a/Cauldron/embeds.xml b/Cauldron/embeds.xml
deleted file mode 100644
index 4efeb90..0000000
--- a/Cauldron/embeds.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd">
-
-	<Script file="Libs\LibStub\LibStub.lua"/>
-
-	<Include file="Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
-	<Include file="Libs\AceAddon-3.0\AceAddon-3.0.xml"/>
-	<Include file="Libs\AceEvent-3.0\AceEvent-3.0.xml"/>
-	<Include file="Libs\AceTimer-3.0\AceTimer-3.0.xml"/>
-	<Include file="Libs\AceHook-3.0\AceHook-3.0.xml"/>
-	<Include file="Libs\AceDB-3.0\AceDB-3.0.xml"/>
-    <Include file="Libs\AceGUI-3.0\AceGUI-3.0.xml"/>
-	<Include file="Libs\AceLocale-3.0\AceLocale-3.0.xml"/>
-	<Include file="Libs\AceConsole-3.0\AceConsole-3.0.xml"/>
-	<Include file="Libs\AceConfig-3.0\AceConfig-3.0.xml"/>
-
-	<!--
-	<Include file="Libs\LibAbacus-3.0\lib.xml"/>
-	-->
-    <Include file="Libs\LibLogger-1.0\lib.xml"/>
-
-	<Script file="Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua"/>
-	<!-- Include file="Libs\LibPeriodicTable-3.1\modules.xml"/ -->
-
-</Ui>
\ No newline at end of file
diff --git a/CauldronMain.lua b/CauldronMain.lua
new file mode 100644
index 0000000..b61feff
--- /dev/null
+++ b/CauldronMain.lua
@@ -0,0 +1,714 @@
+-- $Revision$
+-- Cauldron main file
+
+Cauldron = LibStub("AceAddon-3.0"):NewAddon("Cauldron", "AceEvent-3.0", "AceTimer-3.0", "AceConsole-3.0", "AceHook-3.0", "LibLogger-1.0")
+local L = LibStub("AceLocale-3.0"):GetLocale("Cauldron")
+
+Cauldron.version = "0.9.7." .. string.sub("$Revision$", 12, -3);
+Cauldron.date = string.sub("$Date$", 8, 17);
+
+-- key binding names
+BINDING_HEADER_CAULDRON = "Cauldron";
+BINDING_NAME_TOGGLE_CAULDRONSHOPPINGLIST = "Toggle Shopping List Window";
+BINDING_NAME_CAULDRONRESET = "Reset Cauldron";
+-- BINDING_NAME_TOGGLE_CAULDRONCONFIG = "Toggle Config Window";
+
+Cauldron.options = {};
+Cauldron.options.buttons = {};
+
+Cauldron.vars = {};
+
+Cauldron.libs = {};
+-- Cauldron.libs.Abacus = LibStub("LibAbacus-3.0");
+-- Cauldron.libs.PT = LibStub("LibPeriodicTable-3.1");
+
+-- Cauldron:ToggleDebugLog(false);
+Cauldron:SetLogLevel(Cauldron.logLevels.INFO);
+
+CURRENT_TRADESKILL = "";
+
+function Cauldron:OnInitialize()
+	local dbDefaults = {
+		profile = {
+		},
+		realm = {
+			userdata = {}, -- Stores all known characters
+		},
+		global = {
+			difficulty = {}, -- Stores at what level difficulty is changed for all recipes.
+		}
+	}
+
+	self.db = LibStub("AceDB-3.0"):New("CauldronDB", dbDefaults)
+
+	-- set up slash command options
+	local options = {
+		desc = L["Cauldron"],
+		handler = Cauldron,
+		type = 'group',
+		args = {
+			shoppinglist = {
+				name = L["Shopping list"],
+				desc = L["Open shopping list window"],
+				type = 'toggle',
+			},
+			version = {
+				name = L["Version"],
+				desc = L["Shows the version number of the addon"],
+				type = 'execute',
+				func = function() self:DisplayVersion() end,
+			},
+			reset = {
+				name = L["Reset"],
+				desc = L["Resets Cauldron to a fresh state"],
+				type = 'execute',
+				func = function() self:Reset() end,
+			},
+--			debug = LibStub('LibLogDebug-1.0'):GetAce3OptionTable(self, 110),
+		},
+	}
+
+	-- register slash command with options
+	LibStub("AceConfig-3.0"):RegisterOptionsTable("Cauldron", options, {"cauldron"})
+
+	-- let the user know the addon is loaded
+	self:Print(L["Cauldron loaded; version "],Cauldron.version);
+end
+
+function Cauldron:InitPlayer()
+	self:debug("InitPlayer enter");
+
+	if not self.vars.playername then
+		self.vars.playername = UnitName("player");
+		if not self.db.realm.userdata[self.vars.playername] then
+			self.db.realm.userdata[self.vars.playername] = {};
+		end
+--		if not self.db.realm.userdata[self.vars.playername].knownRecipes then
+--			self.db.realm.userdata[self.vars.playername].knownRecipes = {};
+--		end
+		if not self.db.realm.userdata[self.vars.playername].skills then
+			self.db.realm.userdata[self.vars.playername].skills = {};
+		end
+		if not self.db.realm.userdata[self.vars.playername].queue then
+			self.db.realm.userdata[self.vars.playername].queue = CauldronQueue:NewQueue();
+		end
+		if not self.db.realm.shopping then
+			self.db.realm.shopping = CauldronShopping:NewList();
+		end
+	end
+
+	self:debug("InitPlayer exit");
+end
+
+function Cauldron:OnEnable()
+	self:debug("OnEnable enter");
+
+	self:InitPlayer();
+	self:RegisterEvent("TRADE_SKILL_SHOW", "OnTradeShow");
+	self:RegisterEvent("TRADE_SKILL_UPDATE", "OnSkillUpdate");
+	self:RegisterEvent("TRADE_SKILL_CLOSE", "OnTradeClose");
+	self:RegisterEvent("SKILL_LINES_CHANGED", "OnSkillUpdate");
+	self:RegisterEvent("ADDON_LOADED", "OnAddonLoaded");
+	self:RegisterEvent("UNIT_PORTRAIT_UPDATE", "OnEvent");
+	self:RegisterEvent("UPDATE_TRADESKILL_RECAST", "OnTradeSkillRecast");
+--	self:RegisterEvent("BANKFRAME_OPENED");
+--	self:RegisterEvent("BANKFRAME_CLOSED");
+--	self:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
+--	self:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED");
+--	self:RegisterEvent("MERCHANT_SHOW");
+--	self:RegisterEvent("MERCHANT_UPDATE");
+--	self:RegisterEvent("MERCHANT_CLOSED");
+	self:RegisterEvent("BAG_UPDATE", "OnBagUpdate");
+--	self:RegisterEvent("TRAINER_CLOSED");
+--	self:RegisterEvent("PLAYER_REGEN_DISABLED");
+--	self:RegisterEvent("PLAYER_REGEN_ENABLED");
+--	self:RegisterEvent("AUCTION_HOUSE_CLOSED");
+--	self:RegisterEvent("AUCTION_HOUSE_SHOW");
+	self:RegisterEvent("CRAFT_SHOW", "OnCraftShow");
+	self:RegisterEvent("CRAFT_CLOSE", "OnCraftClose");
+--	self:RegisterEvent("PLAYER_LOGOUT");
+	self:RegisterEvent("UI_ERROR_MESSAGE", "OnError");
+	self:HookTooltips();
+
+	self:debug("OnEnable exit");
+end
+
+function Cauldron:OnDisable()
+	self:debug("OnDisable enter");
+
+	self:debug("OnDisable exit");
+end
+
+function Cauldron:OnAddonLoaded(event, addon)
+	self:debug("OnAddonLoaded enter");
+
+	-- show the shopping list?
+	if self.db.profile.showShoppingList then
+		Cauldron:ShowShoppingList();
+	else
+		if CauldronShopping:ContainsItems(self.db.realm.shopping) then
+			Cauldron:ShowShoppingList();
+		end
+	end
+
+	self:debug("OnAddonLoaded exit");
+end
+
+function Cauldron:OnEvent(event, ...)
+	self:debug("OnEvent enter");
+
+	if ( event == "UNIT_PORTRAIT_UPDATE" ) then
+		local arg1 = ...;
+		if ( arg1 == "player" ) then
+			SetPortraitTexture(CauldronFramePortrait, "player");
+		end
+	end
+
+	self:debug("OnEvent exit");
+end
+
+function Cauldron:OnTradeShow()
+	self:debug("OnTradeShow enter");
+
+	-- update our known skills
+	self:debug("OnTradeShow: update known skills");
+	self:UpdateSkills();
+
+	-- show the UI frame
+	self:debug("OnTradeShow: show the UI");
+	self:Frame_Show();
+
+	self:debug("OnTradeShow exit");
+end
+
+function Cauldron:OnTradeUpdate()
+	self:debug("OnTradeUpdate enter");
+
+--	TODO
+
+	self:debug("OnTradeUpdate exit");
+end
+
+function Cauldron:OnTradeClose()
+	self:debug("OnTradeClose enter");
+
+	self:Frame_Hide();
+
+	self:debug("OnTradeClose exit");
+end
+
+function Cauldron:OnSkillUpdate()
+	self:debug("OnSkillUpdate enter");
+
+--	self:UpdateSkills();
+--	self:UpdateSpecializations();
+
+--	if not IsTradeSkillLinked() then
+--		if (GetTradeSkillLine() ~= "UNKNOWN") then
+--			self:ScheduleTimer(self.UpdateKnownRecipes, 1, self);
+--		end
+--	end
+
+	if CURRENT_TRADESKILL ~= "" then
+		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL] then
+			return;
+		end
+
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.selected = 0;
+
+		Cauldron:UpdateSkills();
+		CauldronQueue:CalculateAllRequiredItems();
+	end
+
+	self:Frame_Update();
+
+	self:debug("OnSkillUpdate exit");
+end
+
+function Cauldron:OnTradeSkillRecast()
+	self:debug("OnTradeSkillRecast enter");
+
+	self:UpdateSkills();
+
+	CauldronAmountInputBox:SetNumber(GetTradeskillRepeatCount());
+
+	self:Frame_Update();
+
+	self:debug("OnTradeSkillRecast exit");
+end
+
+function Cauldron:OnBagUpdate()
+	self:debug("OnBagUpdate enter");
+
+	if (not CauldronFrame) or (not CauldronFrame:IsShown()) then
+		return;
+	end
+
+	if self.makingItem then
+		self:debug("OnBagUpdate: self.makingItem="..self.makingItem);
+		local count = GetItemCount(self.makingItem);
+		self:debug("OnBagUpdate: count="..count);
+		self:debug("OnBagUpdate: self.itemCurrentCount="..self.itemCurrentCount);
+		if count ~= self.itemCurrentCount then
+			local delta = self.itemCurrentCount - count; -- TODO: is this necessary?
+			self:debug("OnBagUpdate: delta="..delta);
+			CauldronQueue:AdjustItemCount(Cauldron:GetQueue(), self.queueInfo.name, -1);
+			self.itemCurrentCount = count;
+		end
+	else
+		--
+	end
+
+	-- Cauldron:UpdateSkills();
+
+	self:Frame_Update();
+
+	self:debug("OnBagUpdate exit");
+end
+
+function Cauldron:OnCraftShow()
+	self:debug("OnCraftShow enter");
+
+--	TODO
+
+	self:debug("OnCraftShow exit");
+end
+
+function Cauldron:OnCraftClose()
+	self:debug("OnCraftClose enter");
+
+--	TODO
+
+	self:debug("OnCraftClose exit");
+end
+
+function Cauldron:OnError()
+	self:debug("OnError enter");
+
+--	TODO
+
+	self:debug("OnError exit");
+end
+
+function Cauldron:TradeSkillFrame_SetSelection(id)
+	self:debug("TradeSkillFrame_SetSelection enter");
+
+	-- TODO
+
+	self:debug("TradeSkillFrame_SetSelection exit");
+end
+
+function Cauldron:GetSelectedSkill()
+	self:debug("GetSelectedSkill enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local selected = self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected;
+
+	for name, info in pairs(self.db.realm.userdata[self.vars.playername].skills[skillName].recipes) do
+		if selected == info.index then
+			return info;
+		end
+	end
+
+	self:debug("GetSelectedSkill exit");
+
+	return nil;
+end
+
+function Cauldron:QueueAllTradeSkillItem()
+	self:debug("QueueAllTradeSkillItem enter");
+
+	local skillInfo = Cauldron:GetSelectedSkill();
+
+	if skillInfo then
+		local amount = skillInfo.available;
+		if amount > 0 then
+			CauldronQueue:AddItem(self.db.realm.userdata[self.vars.playername].queue, skillInfo, amount);
+
+			Cauldron:UpdateQueue();
+		else
+			-- TODO: notify player?
+		end
+	end
+
+	self:debug("QueueAllTradeSkillItem exit");
+end
+
+function Cauldron:QueueTradeSkillItem()
+	self:debug("QueueTradeSkillItem enter");
+
+	local skillInfo = Cauldron:GetSelectedSkill();
+
+	if skillInfo then
+		local amount = CauldronAmountInputBox:GetNumber();
+		if not amount or amount < 1 then
+			amount = 1;
+		end
+		CauldronQueue:AddItem(self.db.realm.userdata[self.vars.playername].queue, skillInfo, amount);
+	end
+
+	self:debug("QueueTradeSkillItem exit");
+end
+
+function Cauldron:CreateAllTradeSkillItem()
+	self:debug("CreateAllTradeSkillItem enter");
+
+	if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
+		CauldronAmountInputBox:ClearFocus();
+
+		local skillInfo = Cauldron:GetSelectedSkill();
+
+		CauldronAmountInputBox:SetNumber(skillInfo.available);
+
+		DoTradeSkill(skillInfo.index, skillInfo.available);
+	end
+
+	self:debug("CreateAllTradeSkillItem exit");
+end
+
+function Cauldron:CreateTradeSkillItem()
+	self:debug("CreateTradeSkillItem enter");
+
+	if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
+		CauldronAmountInputBox:ClearFocus();
+
+		local skillInfo = Cauldron:GetSelectedSkill();
+		local amount = CauldronAmountInputBox:GetNumber();
+
+		DoTradeSkill(skillInfo.index, amount);
+	end
+
+	self:debug("CreateTradeSkillItem exit");
+end
+
+function Cauldron:ProcessQueue()
+	self:debug("ProcessQueue enter");
+
+	if IsTradeSkillLinked() then
+		-- TODO: display error/warning
+		return;
+	end
+
+	-- find intermediate items that need to be crafted
+	local intQueue = CauldronQueue:GetIntermediates(self.db.realm.userdata[self.vars.playername].queue);
+	self:debug("ProcessQueue: intQueue="..#intQueue);
+
+	local queueInfo = nil;
+	local skillInfo = nil;
+
+	if #intQueue > 0 then
+		self:debug("ProcessQueue: processing intermediate queue items");
+
+	 	queueInfo = intQueue[1];
+		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
+		skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));
+	else
+		local queue = CauldronQueue:GetItems(self.db.realm.userdata[self.vars.playername].queue);
+		self:debug("ProcessQueue: queue="..#queue);
+
+		if #queue > 0 then
+			self:debug("ProcessQueue: processing main queue items");
+
+			queueInfo = queue[1];
+			self:debug("ProcessQueue: queueInfo="..queueInfo.name);
+			skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+			self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));
+		end
+	end
+
+	if queueInfo and skillInfo then
+		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
+
+		if queueInfo.tradeskill ~= CURRENT_TRADESKILL then
+			local msg = string.format(L["Crafting %1$s requires the %2$s skill."], queueInfo.name, queueInfo.tradeskill);
+			UIErrorsFrame:AddMessage(msg, 1.0, 0.0, 0.0);
+			return;
+		end
+
+		self:debug("ProcessQueue: process item: "..queueInfo.name);
+		Cauldron:ProcessItem(skillInfo, queueInfo, queueInfo.amount);
+	else
+		if not queueInfo then
+			self:Print("Missing queue info!");
+		end
+		if not skillInfo then
+			self:Print("Missing skill info!");
+		end
+	end
+
+	self:debug("ProcessQueue exit");
+end
+
+
+function Cauldron:ProcessItem(skillInfo, queueInfo, amount)
+	self:debug("ProcessItem enter");
+
+	if (not skillInfo) or (amount < 1) then
+		self:warn("Cauldron:ProcessItem: Missing skill info!");
+		return;
+	end
+
+	if ((not PartialPlayTime()) and (not NoPlayTime())) then
+		-- record the item we're making
+		self.makingItem, _ = GetItemInfo(skillInfo.link);
+		self:debug("ProcessItem: self.makingItem="..self.makingItem);
+		self.itemCurrentCount = GetItemCount(skillInfo.link);
+		self:debug("ProcessItem: self.itemCurrentCount="..self.itemCurrentCount);
+		self.queueInfo = queueInfo;
+
+		-- tell the user what we're doing
+		self:Print(string.format(L["Crafting %1$d of %2$s..."], amount, self.makingItem));
+
+		-- do it
+		DoTradeSkill(skillInfo.index, amount);
+	else
+		-- TODO: notify player?
+	end
+
+	self:debug("ProcessItem exit");
+end
+
+function Cauldron:RemoveQueueItem(name)
+	CauldronQueue:RemoveItem(Cauldron:GetQueue(), name);
+end
+
+function Cauldron:IncreaseItemPriority(name, top)
+	CauldronQueue:IncreasePriority(Cauldron:GetQueue(), name, top);
+end
+
+function Cauldron:DecreaseItemPriority(name, bottom)
+	CauldronQueue:DecreasePriority(Cauldron:GetQueue(), name, bottom);
+end
+
+function Cauldron:DecreaseItemCount(name)
+	CauldronQueue:AdjustItemCount(Cauldron:GetQueue(), name, -1);
+end
+
+function Cauldron:GetQueue(player)
+	self:debug("GetQueue enter");
+
+	if not player then
+		player = self.vars.playername;
+	end
+
+	local queue = self.db.realm.userdata[player].queue;
+	if not queue then
+		queue = CauldronQueue:NewQueue();
+		self.db.realm.userdata[player].queue = queue;
+	end
+
+	self:debug("GetQueue enter");
+
+	return queue;
+end
+
+function Cauldron:AddItemToShoppingList(itemName, amount)
+	CauldronShopping:AddToList(self.db.realm.shopping, self.vars.playername, itemName, amount);
+	Cauldron:ShowShoppingList();
+end
+
+function Cauldron:RemoveShoppingListItem(requestor, itemName)
+	CauldronShopping:RemoveFromList(self.db.realm.shopping, requestor, itemName, nil);
+
+--	if not CauldronShopping:ContainsItems(self.db.realm.shopping) then
+--		Cauldron:HideShoppingList();
+--	end
+end
+
+function Cauldron:LocaleString(str)
+	return L[str];
+end
+
+function Cauldron:DisplayVersion()
+	self:Print(L["Version "],Cauldron.version);
+end
+
+----------------------------------------------------------------
+--  Tooltip Functions
+----------------------------------------------------------------
+
+function Cauldron:HookTooltips()
+	self:debug("HookTooltips enter");
+
+--	self:SecureHook(GameTooltip, "SetBagItem");
+--	self:SecureHook(GameTooltip, "SetInventoryItem");
+--	self:SecureHook(GameTooltip, "SetLootItem");
+--	self:SecureHook(GameTooltip, "SetHyperlink");
+--	self:SecureHook(GameTooltip, "SetTradeSkillItem");
+--	self:SecureHook(GameTooltip, "SetMerchantItem");
+--	self:SecureHook(GameTooltip, "SetAuctionItem");
+--	self:SecureHook(GameTooltip, "SetTrainerService");
+--	self:SecureHook(GameTooltip, "SetGuildBankItem");
+--	self:SecureHook("SetItemRef");
+
+	self:debug("HookTooltips exit");
+end
+
+----------------------------------------------------------------------
+-- Property functions
+----------------------------------------------------------------------
+
+--[[ Databroker Stuff --]]
+
+local ldb = LibStub:GetLibrary("LibDataBroker-1.1", true)
+if ldb then
+	ldb:NewDataObject("Cauldron", {
+		type = "launcher",
+		text = "Cauldron shopping list",
+		icon = "Interface\\Icons\\INV_Elemental_Mote_Nether",
+		OnClick = function(frame, button)
+			if button == "LeftButton" then
+				Cauldron:ShowShoppingList();
+			elseif button == "RightButton" then
+				Cauldron:ShoppingList_Toggle();
+			end
+		end,
+		OnTooltipShow = function(tooltip)
+			tooltip:AddLine("Cauldron " .. Cauldron.version)
+		end,
+	})
+end
+
+--[[
+	Database table structure:
+
+	["userdata"] = {
+		["<character-name>"] = {
+			["queue"] = {
+				["intermediate"] = {
+					["<skill>"] = {
+						["tradeskill"] = "<tradeskill>", -- human-readable name of the tradeskill that contains this skill
+						["name"] = "<skill>", -- human-readable name of the skill
+						["amount"] = <amount>, -- amount of this skill that must be executed
+						["priority"] = <priority>, -- priority of the skill, for ordering in the queue
+						["icon"] = "<icon>", -- the icon path of the skill, for display
+						["link"] = "<link>",
+					},
+				},
+				["main"] = {
+					["<skill>"] = {
+						["tradeskill"] = "<tradeskill>",
+						["name"] = "<skill>",
+						["amount"] = <amount>,
+						["priority"] = <priority>,
+						["icon"] = "<icon>",
+						["link"] = "<link>",
+					},
+				},
+				["reagents"] = {
+					["<reagent>"] = {
+						["tradeskill"] = "<tradeskill>",
+						["name"] = "<reagent>",
+						["amount"] = <amount>,
+						["icon"] = "<icon>",
+						["link"] = "<link>",
+					},
+				},
+			},
+			["skills"] = {
+				["<tradeskill>"] = {
+					["window"] = { -- window metadata
+						["categories"] = { -- category cache of the tradeskill
+							["<category>"] = { -- name of the category
+								["shown"] = true, -- whether the category is being shown in the skill list
+							},
+							...
+						},
+						["search"] = "", -- search text the user typed in the search box
+						["filter"] = { -- flags for the filter dropdown
+							["sortAlpha"] = false, -- should the list be sorted alphabetically (mutually-exclusive to "sortDifficulty" and "sortBenefit")
+							["sortDifficulty"] = true, -- should the list be sorted by difficulty  (mutually-exclusive to "sortAlpha" and "sortBenefit")
+							["sortBenefit"] = false, -- should the list be sorted by potentcy of the benefit the crafted item/enchantment grants  (mutually-exclusive to "sortDifficulty" and "sortAlpha") UNUSED
+							["haveAllReagents"] = false, -- should only items with all required reagents be shown in the list?
+							["haveKeyReagents"] = false, -- should only items with all key reagents be shown in the list?
+							["haveAnyReagents"] = false, -- should only items with any reagents be shown in the list?
+							["optimal"] = true, -- should optimal skills be shown?
+							["medium"] = true, -- should medium skills be shown?
+							["easy"] = true, -- should easy skills be shown?
+							["trivial"] = false, -- should trivial skills be shown?
+							["favorites"] = false, -- should only favorite skills be shown?
+						},
+						["skills"] = {
+							["<skill>"] = {
+								["expanded"] = false, -- should the skill's reagents be displayed?
+								["favorite"] = false, -- is the skill a favorite?
+							},
+							...
+						},
+						["selected"] = 1, -- skill index of the selected skill (gets reset on skill update events, like skill level increases and training)
+						["slots"] = { -- slot cache
+							["INVTYPE_FEET"] = true,
+							["INVTYPE_BAG"] = true,
+							["INVTYPE_CLOAK"] = true,
+							["(none)"] = true, -- special slot for items that don't have an assigned slot
+							["INVTYPE_WRIST"] = true,
+							["INVTYPE_WAIST"] = true,
+							["INVTYPE_CHEST"] = true,
+							["INVTYPE_LEGS"] = true,
+							["INVTYPE_HAND"] = true,
+						},
+					},
+					["recipes"] = {
+						["<skill>"] = {
+							["index"] = <skill index>,
+							["name"] = "<skill>",
+							["link"] = "<link>",
+							["icon"] = "<icon>",
+							["verb"] = "<verb>", -- this is present for skills that cast, like enchantments
+							["tradeskill"] = "<tradeskill>",
+							["difficulty"] = "<difficulty>",
+							["available"] = <available>,
+							["minMade"] = <min>,
+							["maxMade"] = <max>,
+							["slot"] = "INVTYPE_LEGS",
+							["defaultCategory"] = "<category>",
+							["reagents"] = {
+								{
+									["toonHas"] = <has>, -- how many of this reagent the character has
+									["name"] = "<reagent name>",
+									["numRequired"] = <required>, -- the number required of this reagent to complete one execution of the skill
+									["index"] = <reagent index>, -- the index of the reagent, for API call usage
+									["skillIndex"] = <skill index>, -- the index of the skill, for API call usage
+									["icon"] = "<icon>",
+								}, -- [1]
+								...
+							},
+							["keywords"] = "<skill>,<reagent>,...",
+						},
+					},
+				},
+			},
+		},
+	},
+	["shopping"] = {
+		["<character-name>"] = {
+			["<reagent name>"] = <amount>,
+		},
+	},
+
+--]]
+
+function Cauldron:Reset()
+	self:Print("Resetting data structures...");
+
+	-- close the window
+	Cauldron:Frame_Hide();
+	HideUIPanel(TradeSkillFrame);
+
+	-- reset the shopping list
+	self.db.realm.shopping = CauldronShopping:NewList();
+
+	-- reset the skills for each character
+	for toon, info in pairs(self.db.realm.userdata) do
+		self.db.realm.userdata[toon] = {};
+		self.db.realm.userdata[toon].skills = {};
+		self.db.realm.userdata[toon].queue = CauldronQueue:NewQueue();
+	end
+
+	self:Print("Reset complete.");
+end
diff --git a/CauldronMain.xml b/CauldronMain.xml
new file mode 100644
index 0000000..310ee6b
--- /dev/null
+++ b/CauldronMain.xml
@@ -0,0 +1,1399 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\..\FrameXML\UI.xsd">
+
+    <!-- Templates -->
+    <Button name="CauldronButtonTemplate" inherits="UIPanelButtonTemplate" virtual="true">
+        <Size x="80" y="20" />
+        <NormalText inherits="GameFontHighlightSmall" />
+        <DisabledText inherits="GameFontDisableSmall" />
+        <HighlightText inherits="GameFontHighlightSmall" />
+        <Scripts>
+            <OnClick>
+                PlaySound("igMainMenuOptionCheckBoxOn");
+			</OnClick>
+            <OnEnter>
+                if ( self.tooltipText ) then
+                    GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+                    GameTooltip:SetText(self.tooltipText, nil, nil, nil, nil, 1);
+                end
+			</OnEnter>
+            <OnLeave>
+                GameTooltip:Hide();
+			</OnLeave>
+        </Scripts>
+    </Button>
+
+	<Button name="CauldronReagentDetailTemplate" inherits="QuestItemTemplate" virtual="true">
+		<Scripts>
+			<OnEnter>
+				GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT");
+				GameTooltip:SetTradeSkillItem(self.skillIndex, self.reagentIndex);
+				CursorUpdate(self);
+			</OnEnter>
+			<OnLeave>
+				GameTooltip:Hide();
+				ResetCursor();
+			</OnLeave>
+			<OnUpdate>
+				CursorOnUpdate(self);
+			</OnUpdate>
+			<OnClick>
+				HandleModifiedItemClick(GetTradeSkillReagentItemLink(TradeSkillFrame.selectedSkill, self:GetID()));
+			</OnClick>
+		</Scripts>
+	</Button>
+
+    <Button name="CauldronSkillItemFrameTemplate" virtual="true">
+    	<Size x="300" y="50" />
+    	<Layers>
+			<Layer level="OVERLAY">
+				<FontString name="$parentSkillName" inherits="GameFontNormal"
+							text="(name)" justifyH="LEFT" justifyV="CENTER">
+					<Size x="250" y="12"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="62" y="-4"/>
+						</Anchor>
+					</Anchors>
+				</FontString>
+				<FontString name="$parentSkillCategory" inherits="GameFontNormalSmall"
+							text="(category)" justifyH="LEFT" justifyV="CENTER">
+					<Size x="250" y="12"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="62" y="-20"/>
+						</Anchor>
+					</Anchors>
+				</FontString>
+				<FontString name="$parentSkillCooldown" inherits="GameFontRedSmall"
+							text="(cooldown)" justifyH="RIGHT" nonSpaceWrap="true" maxLines="3"
+							hidden="true">
+					<Size x="75" y="50"/>
+					<Anchors>
+						<Anchor point="TOPRIGHT">
+							<Offset x="0" y="0"/>
+						</Anchor>
+					</Anchors>
+				</FontString>
+			</Layer>
+			<Layer level="HIGHLIGHT" setAllPoints="true">
+				<Texture file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
+					<Color r="0.7" g="0.7" b="0.7" a="0.5" />
+				</Texture>
+			</Layer>
+    	</Layers>
+    	<Frames>
+			<Button name="$parentSkillIcon">
+				<Size x="37" y="37"/>
+				<Anchors>
+					<Anchor point="TOPLEFT">
+						<Offset x="24" y="-3"/>
+					</Anchor>
+				</Anchors>
+				<Layers>
+					<Layer level="ARTWORK">
+						<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT" hidden="false">
+							<Anchors>
+								<Anchor point="BOTTOMRIGHT">
+									<Offset x="-2" y="2"/>
+								</Anchor>
+							</Anchors>
+						</FontString>
+					</Layer>
+				</Layers>
+				<Scripts>
+					<OnLoad>
+						-- self.hasItem = 1;
+					</OnLoad>
+					<OnClick>
+						-- HandleModifiedItemClick(GetTradeSkillItemLink(self.skillIndex));
+						Cauldron:SkillItem_OnClick(self, button, down);
+					</OnClick>
+					<OnEnter>
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:SetTradeSkillItem(self.skillIndex);
+						CursorUpdate(self);
+					</OnEnter>
+					<OnLeave>
+						GameTooltip:Hide();
+						ResetCursor();
+					</OnLeave>
+					<OnUpdate>
+						if GameTooltip:IsOwned(self) then
+							GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+							GameTooltip:SetTradeSkillItem(self.skillIndex);
+							CursorUpdate(self);
+						end
+						CursorOnUpdate(self);
+					</OnUpdate>
+				</Scripts>
+			</Button>
+			<Button name="$parentDiscloseButton" hidden="false" inherits="ClassTrainerSkillButtonTemplate">
+				<Size x="20" y="22"/>
+				<Anchors>
+					<Anchor point="RIGHT" relativeTo="$parentSkillIcon" relativePoint="LEFT">
+						<Offset x="0" y="0"/>
+					</Anchor>
+				</Anchors>
+				<Scripts>
+					<OnLoad>
+						getglobal(self:GetName()):SetText("");
+					</OnLoad>
+					<OnClick>
+						Cauldron:CollapseItemButton_OnClick(self);
+					</OnClick>
+				</Scripts>
+			</Button>
+			<CheckButton name="$parentFavoriteButton" hidden="false" inherits="UICheckButtonTemplate">
+				<Size x="20" y="22"/>
+				<Anchors>
+					<Anchor point="TOPRIGHT">
+						<Offset x="0" y="0"/>
+					</Anchor>
+				</Anchors>
+				<Scripts>
+					<OnLoad>
+						self:SetScale(0.625);
+						getglobal(self:GetName()):SetText("");
+					</OnLoad>
+                	<OnEnter>
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Mark this skill as a favorite"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+                	</OnEnter>
+                	<OnLeave>
+                		GameTooltip:Hide();
+                		ResetCursor();
+                	</OnLeave>
+					<OnClick>
+						PlaySound("igMainMenuOptionCheckBoxOn");
+						Cauldron:FavoriteItemButton_OnClick(self);
+						Cauldron:UpdateSkillList();
+					</OnClick>
+				</Scripts>
+			</CheckButton>
+    		<Frame name="$parentReagents">
+    			<Size x="40" y="100" />
+				<Anchors>
+					<Anchor point="TOPLEFT" relativeTo="$parentSkillIcon" relativePoint="BOTTOMLEFT">
+						<Offset x="10" y="-3"/>
+					</Anchor>
+				</Anchors>
+    			<Layers>
+    				<Layer level="OVERLAY">
+    					<FontString name="$parentToolsInfo" inherits="GameFontNormal"
+    								text="(tools info)" justifyH="LEFT">
+    						<Size x="250" y="12" />
+							<Anchors>
+								<Anchor point="TOPLEFT">
+									<Offset x="0" y="0"/>
+								</Anchor>
+							</Anchors>
+							<Color r="1.0" g="1.0" b="1.0" />
+    					</FontString>
+    				</Layer>
+    			</Layers>
+    			<Frames>
+					<Button name="$parentItemDetail1" inherits="CauldronReagentDetailTemplate" id="1">
+						<Anchors>
+							<Anchor point="TOPLEFT" relativeTo="$parentToolsInfo" relativePoint="BOTTOMLEFT">
+								<Offset x="0" y="-2"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail2" inherits="CauldronReagentDetailTemplate" id="2">
+						<Anchors>
+							<Anchor point="LEFT" relativeTo="$parentItemDetail1" relativePoint="RIGHT">
+								<Offset x="5" y="0"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail3" inherits="CauldronReagentDetailTemplate" id="3">
+						<Anchors>
+							<Anchor point="TOP" relativeTo="$parentItemDetail1" relativePoint="BOTTOM">
+								<Offset x="0" y="-3"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail4" inherits="CauldronReagentDetailTemplate" id="4">
+						<Anchors>
+							<Anchor point="LEFT" relativeTo="$parentItemDetail3" relativePoint="RIGHT">
+								<Offset x="5" y="0"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail5" inherits="CauldronReagentDetailTemplate" id="5">
+						<Anchors>
+							<Anchor point="TOP" relativeTo="$parentItemDetail3" relativePoint="BOTTOM">
+								<Offset x="0" y="-3"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail6" inherits="CauldronReagentDetailTemplate" id="6">
+						<Anchors>
+							<Anchor point="LEFT" relativeTo="$parentItemDetail5" relativePoint="RIGHT">
+								<Offset x="5" y="0"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail7" inherits="CauldronReagentDetailTemplate" id="7">
+						<Anchors>
+							<Anchor point="TOP" relativeTo="$parentItemDetail7" relativePoint="BOTTOM">
+								<Offset x="0" y="-3"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+					<Button name="$parentItemDetail8" inherits="CauldronReagentDetailTemplate" id="8">
+						<Anchors>
+							<Anchor point="LEFT" relativeTo="$parentItemDetail7" relativePoint="RIGHT">
+								<Offset x="5" y="0"/>
+							</Anchor>
+						</Anchors>
+					</Button>
+    			</Frames>
+    		</Frame>
+    		<Frame name="$parentSelection" setAllPoints="true" enableMouse="true" hidden="true" frameStrata="LOW" frameLevel="1">
+    			<Layers>
+					<Layer level="OVERLAY">
+						<Texture name="$parentSelection" file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
+							<Color r="0.5" g="0.5" b="0.5" a="0.5" />
+						</Texture>
+					</Layer>
+				</Layers>
+			</Frame>
+    	</Frames>
+    	<Scripts>
+    		<OnEnter>
+    			Cauldron:SkillItem_OnEnter(self);
+    		</OnEnter>
+    		<OnLeave>
+    			Cauldron:SkillItem_OnLeave(self);
+    		</OnLeave>
+    		<OnClick>
+                PlaySound("igMainMenuOptionCheckBoxOn");
+    			Cauldron:SkillItem_OnClick(self, button, down);
+    		</OnClick>
+    	</Scripts>
+    </Button>
+
+    <Button name="CauldronQueueItemFrameTemplate" virtual="true" enableMouse="true">
+    	<Size x="300" y="39" />
+    	<Layers>
+			<Layer level="OVERLAY">
+	    		<!-- item name -->
+				<FontString name="$parentItemName" inherits="GameFontNormal"
+							text="(name)" justifyH="LEFT" justifyV="CENTER">
+					<Size x="250" y="12"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="40" y="-4"/>
+						</Anchor>
+					</Anchors>
+					<Color r="0.2" g="0.2" b="0.2" />
+				</FontString>
+				<!-- quantity info -->
+				<FontString name="$parentInfo" inherits="GameFontNormal"
+							text="(info)" justifyH="LEFT" justifyV="CENTER">
+					<Size x="250" y="12"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="40" y="-18"/>
+						</Anchor>
+					</Anchors>
+					<!-- Color r="1.0" g="1.0" b="1.0" / -->
+				</FontString>
+			</Layer>
+			<Layer level="HIGHLIGHT" setAllPoints="true">
+				<Texture file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
+					<Color r="0.8" g="0.8" b="0.8" a="0.5" />
+				</Texture>
+			</Layer>
+    	</Layers>
+    	<Frames>
+    		<!-- icon -->
+			<Button name="$parentIcon">
+				<Size x="37" y="37"/>
+				<Anchors>
+					<Anchor point="TOPLEFT">
+						<Offset x="2" y="-3"/>
+					</Anchor>
+				</Anchors>
+				<Layers>
+					<Layer level="ARTWORK">
+						<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT" hidden="false">
+							<Anchors>
+								<Anchor point="BOTTOMRIGHT">
+									<Offset x="-2" y="2"/>
+								</Anchor>
+							</Anchors>
+						</FontString>
+					</Layer>
+				</Layers>
+				<Scripts>
+					<OnLoad>
+						-- self.hasItem = 1;
+					</OnLoad>
+					<OnClick>
+						-- HandleModifiedItemClick(GetTradeSkillItemLink(TradeSkillFrame.selectedSkill));
+					</OnClick>
+					<OnEnter>
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						if self.link then
+							GameTooltip:SetHyperlink(self.link);
+						end
+						CursorUpdate(self);
+					</OnEnter>
+					<OnLeave>
+						GameTooltip:Hide();
+						ResetCursor();
+					</OnLeave>
+					<OnUpdate>
+						if GameTooltip:IsOwned(self) then
+							GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+							if self.link then
+								GameTooltip:SetHyperlink(self.link);
+							end
+							CursorUpdate(self);
+						end
+						CursorOnUpdate(self);
+					</OnUpdate>
+				</Scripts>
+			</Button>
+			<Button name="$parentRemoveItem" inherits="UIPanelCloseButton" hidden="true">
+                <Anchors>
+                    <Anchor point="TOPRIGHT">
+                        <Offset x="0" y="0"/>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                	<OnEnter>
+                		self:GetParent().inHoverButtons = true;
+
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Remove this item from the queue"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+                	</OnEnter>
+                	<OnLeave>
+                		self:GetParent().inHoverButtons = false;
+
+                		GameTooltip:Hide();
+                		ResetCursor();
+                	</OnLeave>
+                    <OnClick>
+                    	Cauldron:RemoveQueueItem(self:GetParent().itemName);
+                    	Cauldron:UpdateQueue();
+                    	Cauldron:UpdateButtons();
+                    </OnClick>
+                </Scripts>
+            </Button>
+			<Button name="$parentAddToShoppingList" inherits="UIPanelCloseButton" hidden="true">
+                <Anchors>
+                    <Anchor point="TOPRIGHT">
+                        <Offset x="0" y="0"/>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                	<OnEnter>
+                		self:GetParent().inHoverButtons = true;
+
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Add this item to the shopping list"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+                	</OnEnter>
+                	<OnLeave>
+                		self:GetParent().inHoverButtons = false;
+
+                		GameTooltip:Hide();
+                		ResetCursor();
+                	</OnLeave>
+                    <OnClick>
+                    	Cauldron:AddItemToShoppingList(self:GetParent().itemName, self:GetParent().needAmount);
+                    	Cauldron:UpdateShoppingList();
+                    </OnClick>
+                </Scripts>
+				<NormalTexture file="Interface\Buttons\UI-PlusButton-Up" />
+				<PushedTexture file="Interface\Buttons\UI-PlusButton-Down" />
+				<DisabledTexture file="Interface\Buttons\UI-PlusButton-Disabled" />
+				<HighlightTexture file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD" />
+            </Button>
+			<Button name="$parentDecrementCount" hidden="true" inherits="ClassTrainerSkillButtonTemplate">
+				<Size x="23" y="22" />
+                <Anchors>
+                    <Anchor point="TOPRIGHT">
+                        <Offset x="-16" y="-2"/>
+                    </Anchor>
+                </Anchors>
+				<Scripts>
+					<OnLoad>
+						self:RegisterForClicks("AnyUp");
+					</OnLoad>
+                	<OnEnter>
+                		self:GetParent().inHoverButtons = true;
+
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Decrease the amount of this item"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+                	</OnEnter>
+                	<OnLeave>
+                		self:GetParent().inHoverButtons = false;
+
+                		GameTooltip:Hide();
+                		ResetCursor();
+                	</OnLeave>
+					<OnClick>
+						Cauldron:DecreaseItemCount(self:GetParent().itemName);
+						Cauldron:UpdateQueue();
+                    	Cauldron:UpdateButtons();
+					</OnClick>
+				</Scripts>
+				<!--
+				<NormalTexture file="Interface\Buttons\UI-MinusButton-Up" />
+				<PushedTexture file="Interface\Buttons\UI-MinusButton-Down" />
+				<DisabledTexture file="Interface\Buttons\UI-MinusButton-Disabled" />
+				<HighlightTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Highlight" alphaMode="ADD" />
+				-->
+			</Button>
+			<Button name="$parentIncreasePriority" hidden="true">
+				<Size x="23" y="22" />
+                <Anchors>
+                    <Anchor point="TOPRIGHT">
+                        <Offset x="-16" y="-20"/>
+                    </Anchor>
+                </Anchors>
+				<Scripts>
+					<OnLoad>
+						self:RegisterForClicks("AnyUp");
+					</OnLoad>
+                	<OnEnter>
+                		self:GetParent().inHoverButtons = true;
+
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Increase the priority of this item"));
+						GameTooltip:AddLine(Cauldron:LocaleString("Shift-click to move to the top of the queue"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+                	</OnEnter>
+                	<OnLeave>
+                		self:GetParent().inHoverButtons = false;
+
+                		GameTooltip:Hide();
+                		ResetCursor();
+                	</OnLeave>
+					<OnClick>
+						Cauldron:IncreaseItemPriority(self:GetParent().itemName, IsShiftKeyDown());
+						Cauldron:UpdateQueue();
+					</OnClick>
+				</Scripts>
+				<NormalTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Up" />
+				<PushedTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Down" />
+				<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Disabled" />
+				<HighlightTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Highlight" alphaMode="ADD" />
+			</Button>
+			<Button name="$parentDecreasePriority" hidden="true">
+				<Size x="23" y="22" />
+                <Anchors>
+                    <Anchor point="TOPRIGHT">
+                        <Offset x="0" y="-20"/>
+                    </Anchor>
+                </Anchors>
+				<Scripts>
+					<OnLoad>
+						self:RegisterForClicks("AnyUp");
+					</OnLoad>
+                	<OnEnter>
+                		self:GetParent().inHoverButtons = true;
+
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Decrease the priority of this item"));
+						GameTooltip:AddLine(Cauldron:LocaleString("Shift-click to move to the bottom of the queue"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+                	</OnEnter>
+                	<OnLeave>
+                		self:GetParent().inHoverButtons = false;
+
+                		GameTooltip:Hide();
+                		ResetCursor();
+                	</OnLeave>
+					<OnClick>
+						Cauldron:DecreaseItemPriority(self:GetParent().itemName, IsShiftKeyDown());
+						Cauldron:UpdateQueue();
+					</OnClick>
+				</Scripts>
+				<NormalTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Up" />
+				<PushedTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Down" />
+				<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Disabled" />
+				<HighlightTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Highlight" alphaMode="ADD" />
+			</Button>
+    	</Frames>
+    	<Scripts>
+    		<OnEnter>
+    			if self.removeable then
+    				_G[self:GetName().."RemoveItem"]:Show();
+    				_G[self:GetName().."DecreasePriority"]:Show();
+    				_G[self:GetName().."IncreasePriority"]:Show();
+    				_G[self:GetName().."DecrementCount"]:Show();
+    			end
+    			if self.shoppable then
+    				_G[self:GetName().."AddToShoppingList"]:Show();
+    			end
+    		</OnEnter>
+    		<OnLeave>
+    			if not self.inHoverButtons then
+					_G[self:GetName().."RemoveItem"]:Hide();
+    				_G[self:GetName().."DecreasePriority"]:Hide();
+    				_G[self:GetName().."IncreasePriority"]:Hide();
+    				_G[self:GetName().."DecrementCount"]:Hide();
+    				_G[self:GetName().."AddToShoppingList"]:Hide();
+				end
+    		</OnLeave>
+    	</Scripts>
+    </Button>
+
+    <!-- Main frame -->
+    <Frame name="CauldronFrame" toplevel="true" frameStrata="MEDIUM"
+           movable="true" resizable="false" parent="UIParent" enableMouse="true"
+           hidden="true">
+        <Size x="692" y="465" />
+        <Anchors>
+            <Anchor point="CENTER" />
+        </Anchors>
+
+        <!-- Window border and background -->
+        <Layers>
+			<Layer level="BACKGROUND">
+				<Texture name="CauldronFramePortrait">
+					<Size x="60" y="60"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="7" y="-6"/>
+						</Anchor>
+					</Anchors>
+				</Texture>
+				<FontString name="$parentDummyString" inherits="GameFontNormal" hidden="true">
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="0" y="0"/>
+						</Anchor>
+					</Anchors>
+					<Size x="0" y="0"/>
+				</FontString>
+			  </Layer>
+
+            <Layer level="BORDER">
+                <Texture name="CauldronFrameBorderTopLeft"
+                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-TopLeft">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset x="0" y="0" />
+                        </Anchor>
+                    </Anchors>
+                </Texture>
+                <Texture name="CauldronFrameBorderTopMiddle"
+                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-TopMiddle">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset x="256" y="0" />
+                        </Anchor>
+                    </Anchors>
+                </Texture>
+                <Texture name="CauldronFrameBorderTopRight"
+                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-TopRight">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset x="512" y="0" />
+                        </Anchor>
+                    </Anchors>
+                </Texture>
+                <Texture name="CauldronFrameBorderBottomLeft"
+                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-BottomLeft">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset x="0" y="-256" />
+                        </Anchor>
+                    </Anchors>
+                </Texture>
+                <Texture name="CauldronFrameBorderBottomMiddle"
+                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-BottomMiddle">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset x="256" y="-256" />
+                        </Anchor>
+                    </Anchors>
+                </Texture>
+                <Texture name="CauldronFrameBorderBottomRight"
+                    file="Interface\AddOns\Cauldron\Artwork\Cauldron-Main-BottomRight">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset x="512" y="-256" />
+                        </Anchor>
+                    </Anchors>
+                </Texture>
+            </Layer>
+
+            <Layer level="ARTWORK">
+                <FontString name="CauldronFrameTitleText" inherits="GameFontNormal" text="Cauldron">
+                    <Anchors>
+                        <Anchor point="TOP" relativeTo="CauldronFrame" relativePoint="TOP">
+                            <Offset x="0" y="-18" />
+                        </Anchor>
+                    </Anchors>
+                </FontString>
+            </Layer>
+        </Layers>
+
+        <Frames>
+            <!-- Link button -->
+            <Button name="CauldronTradeSkillLinkButton" frameStrata="HIGH">
+                <Size x="32" y="16" />
+                <Anchors>
+                    <Anchor point="LEFT" relativeTo="CauldronFrameTitleText" relativePoint="RIGHT">
+                        <Offset x="5" y="0" />
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                    <OnClick>
+                        local link=GetTradeSkillListLink();
+                        if (not ChatEdit_InsertLink(link) ) then
+                            ChatFrameEditBox:Show();
+                            ChatEdit_InsertLink(link);
+                        end
+                    </OnClick>
+                    <OnEnter>
+                        GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT");
+                        GameTooltip:SetText(LINK_TRADESKILL_TOOLTIP, nil, nil, nil, nil, 1);
+                        GameTooltip:Show();
+                    </OnEnter>
+                    <OnLeave>
+                        GameTooltip:Hide();
+                    </OnLeave>
+                </Scripts>
+                <NormalTexture file="Interface\TradeSkillFrame\UI-TradeSkill-LinkButton">
+                    <TexCoords left="0" right="1.0" top="0" bottom="0.5" />
+                </NormalTexture>
+                <HighlightTexture file="Interface\TradeSkillFrame\UI-TradeSkill-LinkButton" alphaMode="ADD">
+                    <TexCoords left="0" right="1.0" top="0.5" bottom="1.0" />
+                </HighlightTexture>
+            </Button>
+
+            <!-- Filters frame -->
+            <Frame name="CauldronFiltersFrame">
+                <Size x="300" y="60" />
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="CauldronFrame" relativePoint="TOPLEFT">
+                        <Offset x="54" y="-35" />
+                    </Anchor>
+                </Anchors>
+
+                <Frames>
+                    <!-- filter dropdown -->
+                    <Frame name="CauldronFiltersFilterDropDown" inherits="UIDropDownMenuTemplate" id="1">
+                        <Size x="140" y="20" />
+                        <Anchors>
+                            <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
+                                <Offset x="0" y="0"/>
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                Cauldron:FilterDropDown_OnLoad(self);
+                            </OnLoad>
+                        </Scripts>
+                    </Frame>
+
+                    <!-- search text box -->
+			        <EditBox name="CauldronFiltersSearchEditBox" autoFocus="false">
+				        <Size x="130" y="20"/>
+				        <Anchors>
+					       <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
+						      <Offset x="155" y="-2" />
+					       </Anchor>
+				        </Anchors>
+
+				        <Layers>
+					       <Layer level="BACKGROUND">
+						      <Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
+							     <Size x="8" y="20"/>
+							     <Anchors>
+								    <Anchor point="TOPLEFT">
+									   <Offset x="-5" y="0"/>
+								    </Anchor>
+							     </Anchors>
+							     <TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
+						      </Texture>
+						      <Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
+							     <Size x="8" y="20"/>
+							     <Anchors>
+								    <Anchor point="RIGHT">
+									   <Offset x="0" y="0"/>
+								    </Anchor>
+							     </Anchors>
+							     <TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
+						      </Texture>
+						      <Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
+							     <Size x="0" y="20"/>
+							     <Anchors>
+								    <Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/>
+								    <Anchor point="RIGHT" relativeTo="$parentRight" relativePoint="LEFT"/>
+							     </Anchors>
+							     <TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
+						      </Texture>
+					       </Layer>
+				        </Layers>
+				        <Scripts>
+					       	<OnLoad>
+						      	self:SetText(SEARCH);
+							</OnLoad>
+							<OnEnterPressed>
+								self:ClearFocus();
+							</OnEnterPressed>
+							<OnEscapePressed>
+								self:ClearFocus();
+							</OnEscapePressed>
+							<OnTextChanged>
+								Cauldron:TradeSkillFilter_OnTextChanged(self);
+							</OnTextChanged>
+							<OnEditFocusLost>
+								self:HighlightText(0, 0);
+								if self:GetText() == "" then
+									self:SetText(SEARCH);
+								end
+							</OnEditFocusLost>
+							<OnEditFocusGained>
+								self:HighlightText();
+								if self:GetText() == SEARCH then
+									self:SetText("");
+								end
+							</OnEditFocusGained>
+						</Scripts>
+						<FontString inherits="ChatFontSmall"/>
+					</EditBox>
+
+                    <!-- category dropdown -->
+                    <Frame name="CauldronFiltersCategoryDropDown" inherits="UIDropDownMenuTemplate" id="4">
+                        <Size x="140" y="20" />
+                        <Anchors>
+                            <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
+                                <Offset x="0" y="-25"/>
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                Cauldron:CategoryDropDown_OnLoad(self);
+                            </OnLoad>
+                        </Scripts>
+                    </Frame>
+
+                    <!-- slot dropdown -->
+                    <Frame name="CauldronFiltersInvSlotDropDown" inherits="UIDropDownMenuTemplate" id="3">
+                        <Size x="140" y="20" />
+                        <Anchors>
+                            <Anchor point="TOPLEFT" relativeTo="CauldronFiltersFrame" relativePoint="TOPLEFT">
+                                <Offset x="137" y="-25"/>
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                Cauldron:InvSlotDropDown_OnLoad(self);
+                            </OnLoad>
+                        </Scripts>
+                    </Frame>
+
+                </Frames>
+            </Frame>
+
+            <!-- List frame -->
+            <Frame name="CauldronSkillListFrame">
+                <Size x="342" y="100" />
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="CauldronFrame" relativePoint="TOPLEFT">
+                        <Offset x="14" y="-90" />
+                    </Anchor>
+                </Anchors>
+
+                <Frames>
+					<Frame name="$parentExpandButtonFrame">
+						<Size x="54" y="33"/>
+						<Anchors>
+							<Anchor point="TOPLEFT">
+								<Offset x="-3" y="20"/>
+							</Anchor>
+						</Anchors>
+						<Layers>
+							<Layer level="BACKGROUND">
+								<Texture name="$parentExpandTabLeft" file="Interface\ClassTrainerFrame\UI-ClassTrainer-ExpandTab-Left">
+									<Size x="8" y="32"/>
+									<Anchors>
+										<Anchor point="TOPLEFT"/>
+									</Anchors>
+								</Texture>
+								<Texture name="$parentExpandTabMiddle" file="Interface\QuestFrame\UI-QuestLogSortTab-Middle">
+									<Size x="38" y="32"/>
+									<Anchors>
+										<Anchor point="LEFT" relativeTo="$parentExpandTabLeft" relativePoint="RIGHT">
+											<Offset x="0" y="6"/>
+										</Anchor>
+									</Anchors>
+								</Texture>
+								<Texture name="$parentExpandTabRight" file="Interface\QuestFrame\UI-QuestLogSortTab-Right">
+									<Size x="8" y="32"/>
+									<Anchors>
+										<Anchor point="LEFT" relativeTo="$parentExpandTabMiddle" relativePoint="RIGHT"/>
+									</Anchors>
+								</Texture>
+							</Layer>
+						</Layers>
+						<Frames>
+							<Button name="$parentCollapseAllButton" hidden="false" inherits="ClassTrainerSkillButtonTemplate">
+								<Size x="40" y="22"/>
+								<Anchors>
+									<Anchor point="LEFT" relativeTo="$parentExpandTabLeft" relativePoint="RIGHT">
+										<Offset x="0" y="3"/>
+									</Anchor>
+								</Anchors>
+								<Scripts>
+									<OnLoad>
+										getglobal(self:GetName()):SetText(ALL);
+									</OnLoad>
+									<OnClick>
+										Cauldron:CollapseAllButton_OnClick(self);
+									</OnClick>
+								</Scripts>
+							</Button>
+						</Frames>
+					</Frame>
+					<ScrollFrame name="$parentScrollFrame" inherits="ClassTrainerDetailScrollFrameTemplate">
+						<Size x="300" y="338" />
+						<Anchors>
+							<Anchor point="TOPLEFT" relativeTo="CauldronSkillListFrame" relativePoint="TOPLEFT">
+								<Offset x="0" y="-8"/>
+							</Anchor>
+						</Anchors>
+						<ScrollChild>
+							<Frame name="$parentScrollChild">
+								<Size x="300" y="338" />
+								<Anchors>
+									<Anchor point="TOPLEFT">
+										<Offset x="0" y="0"/>
+									</Anchor>
+								</Anchors>
+								<Frames>
+								</Frames>
+							</Frame>
+						</ScrollChild>
+					</ScrollFrame>
+                </Frames>
+            </Frame>
+
+            <!-- Skill Info frame -->
+            <Frame name="CauldronSkillInfoFrame">
+                <Size x="330" y="100" />
+                <Anchors>
+                    <Anchor point="TOPRIGHT" relativeTo="CauldronFrame" relativePoint="TOPRIGHT">
+                        <Offset x="-10" y="-36" />
+                    </Anchor>
+                </Anchors>
+
+                <Layers>
+                    <Layer level="OVERLAY">
+                        <FontString inherits="GameFontNormal" text="Queue">
+                            <Anchors>
+                                <Anchor point="TOP" relativeTo="CauldronSkillInfoFrame" relativePoint="TOP">
+                                    <Offset x="0" y="-18" />
+                                </Anchor>
+                            </Anchors>
+                        </FontString>
+                    </Layer>
+                </Layers>
+
+                <Frames>
+        			<StatusBar name="CauldronRankFrame" drawLayer="ARTWORK"
+        					   minValue="0" maxValue="1" defaultValue="0"
+        					   enableMouse="false">
+        				<Size x="325" y="14"/>
+        				<Anchors>
+        					<Anchor point="TOPLEFT">
+        						<Offset x="0" y="-2"/>
+        					</Anchor>
+        				</Anchors>
+        				<Layers>
+        					<Layer level="OVERLAY">
+                                <FontString name="$parentSkillName" inherits="GameFontHighlightSmall" justifyH="LEFT">
+                                    <Size x="320" y="9"/>
+                                    <Anchors>
+                                        <Anchor point="TOP" relativeTo="CauldronRankFrame">
+                                            <Offset x="0" y="-2"/>
+                                        </Anchor>
+                                    </Anchors>
+                                    <Color r="1.0" g="1.0" b="0.0" a="1.0" />
+                                </FontString>
+        						<FontString name="$parentSkillRank" inherits="GameFontHighlightSmall" justifyH="RIGHT">
+        							<Size x="320" y="9"/>
+        							<Anchors>
+        								<Anchor point="TOP" relativeTo="CauldronRankFrame">
+        									<Offset x="0" y="-2"/>
+        								</Anchor>
+        							</Anchors>
+        						</FontString>
+        					</Layer>
+        					<Layer level="BORDER">
+        						<Texture name="$parentBorder" file="Interface\PaperDollInfoFrame\UI-Character-Skills-BarBorder">
+        							<Size x="334" y="27"/>
+        							<Anchors>
+        								<Anchor point="LEFT">
+        									<Offset x="-5" y="0"/>
+        								</Anchor>
+        							</Anchors>
+        						</Texture>
+        					</Layer>
+        					<Layer level="BACKGROUND">
+        						<Texture name="$parentBackground">
+        							<Color r="1.0" g="1.0" b="1.0" a="0.2"/>
+        						</Texture>
+        					</Layer>
+        				</Layers>
+        				<Scripts>
+        					<!--
+        					<OnLoad>
+        						self:RegisterEvent("SKILL_LINES_CHANGED");
+        					</OnLoad>
+        					<OnEvent>
+        						if event == "SKILL_LINES_CHANGED" then
+        							Cauldron:Frame_Update();
+        						end
+        					</OnEvent>
+        					-->
+        				</Scripts>
+        				<BarTexture name="$parentBar" file="Interface\PaperDollInfoFrame\UI-Character-Skills-Bar" drawLayer="ARTWORK" />
+        				<BarColor r="0.25" g="0.25" b="0.75" />
+        			</StatusBar>
+                </Frames>
+            </Frame>
+
+            <!-- Queue frame -->
+            <Frame name="CauldronQueueFrame">
+                <Size x="320" y="400" />
+                <Anchors>
+                    <Anchor point="TOPRIGHT" relativeTo="CauldronFrame" relativePoint="TOPRIGHT">
+                        <Offset x="-20" y="-76" />
+                    </Anchor>
+                </Anchors>
+
+                <Frames>
+                	<Frame name="$parentQueueEmpty">
+						<Size x="302" y="360" />
+                		<Anchors>
+                			<Anchor point="TOPLEFT">
+								<Offset x="0" y="0" />
+                			</Anchor>
+                		</Anchors>
+						<Layers>
+							<Layer level="OVERLAY">
+								<FontString name="$parentText" inherits="QuestTitleFont"
+											text="The queue is empty!"
+											justifyH="CENTER" justifyV="CENTER">
+									<Size x="302" y="360" />
+									<Anchors>
+										<Anchor point="TOPLEFT">
+											<Offset x="0" y="0" />
+										</Anchor>
+									</Anchors>
+									<Color r="0.2" g="0.2" b="0.2" />
+								</FontString>
+							</Layer>
+						</Layers>
+                	</Frame>
+
+					<ScrollFrame name="$parentScrollFrame" inherits="ClassTrainerDetailScrollFrameTemplate" hidden="true">
+						<Size x="302" y="360" />
+						<Anchors>
+							<Anchor point="TOPLEFT">
+								<Offset x="0" y="0"/>
+							</Anchor>
+						</Anchors>
+						<ScrollChild>
+							<Frame name="$parentQueueSections">
+								<Size x="302" y="360" />
+								<Anchors>
+									<Anchor point="TOPLEFT">
+										<Offset x="0" y="0"/>
+									</Anchor>
+								</Anchors>
+								<Frames>
+									<Frame name="$parentMainItemsHeader">
+										<Size x="300" y="12" />
+										<Anchors>
+											<Anchor point="TOPLEFT">
+												<Offset x="0" y="0" />
+											</Anchor>
+										</Anchors>
+										<Layers>
+											<Layer level="OVERLAY">
+												<FontString name="$parentText" inherits="QuestFont" text="">
+													<Anchors>
+														<Anchor point="TOPLEFT">
+															<Offset x="0" y="0" />
+														</Anchor>
+													</Anchors>
+													<Color r="0.2" g="0.2" b="0.2" />
+												</FontString>
+											</Layer>
+										</Layers>
+									</Frame>
+									<Frame name="$parentMainItems">
+										<Size x="300" y="1" />
+										<Anchors>
+											<Anchor point="TOPLEFT" relativeTo="$parentMainItemsHeader" relativePoint="BOTTOMLEFT">
+												<Offset x="0" y="-2" />
+											</Anchor>
+										</Anchors>
+									</Frame>
+									<Frame name="$parentSecondaryItemsHeader">
+										<Size x="300" y="12" />
+										<Anchors>
+											<Anchor point="TOPLEFT" relativeTo="$parentMainItems" relativePoint="BOTTOMLEFT">
+												<Offset x="0" y="-2" />
+											</Anchor>
+										</Anchors>
+										<Layers>
+											<Layer level="OVERLAY">
+												<FontString name="$parentText" inherits="QuestFont" text="">
+													<Anchors>
+														<Anchor point="TOPLEFT">
+															<Offset x="0" y="0" />
+														</Anchor>
+													</Anchors>
+													<Color r="0.2" g="0.2" b="0.2" />
+												</FontString>
+											</Layer>
+										</Layers>
+									</Frame>
+									<Frame name="$parentSecondaryItems">
+										<Size x="300" y="1" />
+										<Anchors>
+											<Anchor point="TOPLEFT" relativeTo="$parentSecondaryItemsHeader" relativePoint="BOTTOMLEFT">
+												<Offset x="0" y="-2" />
+											</Anchor>
+										</Anchors>
+									</Frame>
+									<Frame name="$parentReagentsHeader">
+										<Size x="300" y="12" />
+										<Anchors>
+											<Anchor point="TOPLEFT" relativeTo="$parentSecondaryItems" relativePoint="BOTTOMLEFT">
+												<Offset x="0" y="-2" />
+											</Anchor>
+										</Anchors>
+										<Layers>
+											<Layer level="OVERLAY">
+												<FontString name="$parentText" inherits="QuestFont" text="">
+													<Anchors>
+														<Anchor point="TOPLEFT">
+															<Offset x="0" y="0" />
+														</Anchor>
+													</Anchors>
+													<Color r="0.2" g="0.2" b="0.2" />
+												</FontString>
+											</Layer>
+										</Layers>
+									</Frame>
+									<Frame name="$parentReagents">
+										<Size x="300" y="1" />
+										<Anchors>
+											<Anchor point="TOPLEFT" relativeTo="$parentReagentsHeader" relativePoint="BOTTOMLEFT">
+												<Offset x="0" y="-2" />
+											</Anchor>
+										</Anchors>
+									</Frame>
+								</Frames>
+							</Frame>
+						</ScrollChild>
+					</ScrollFrame>
+                </Frames>
+            </Frame>
+
+            <!-- Close button -->
+            <Button name="CauldronFrameCloseButton" inherits="UIPanelCloseButton">
+                <Anchors>
+                    <Anchor point="TOPRIGHT" relativeTo="CauldronFrame" relativePoint="TOPRIGHT">
+                        <Offset x="-2" y="-8"/>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                    <OnClick>
+                        HideUIPanel(TradeSkillFrame);
+						PlaySound("igCharacterInfoClose");
+                    </OnClick>
+                </Scripts>
+            </Button>
+
+            <!-- Buttons frame -->
+            <Frame name="CauldronButtonsFrame">
+                <Size x="684" y="25" />
+                <Anchors>
+                    <Anchor point="BOTTOMLEFT" relativeTo="CauldronFrame" relativePoint="BOTTOMLEFT">
+                        <Offset x="13" y="0" />
+                    </Anchor>
+                </Anchors>
+
+                <Frames>
+
+                    <!-- Queue All button -->
+                    <Button name="CauldronQueueAllButton" inherits="CauldronButtonTemplate" text="Queue All">
+                        <Anchors>
+                            <Anchor point="TOPLEFT">
+                                <Offset x="0" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                getglobal(self:GetName()):Disable();
+                            </OnLoad>
+                            <OnClick>
+                            	Cauldron:QueueAllTradeSkillItem();
+								Cauldron:UpdateQueue();
+                            	Cauldron:UpdateButtons();
+                            </OnClick>
+                        </Scripts>
+                    </Button>
+
+                    <!-- Create All button (disabled) -->
+                    <Button name="CauldronCreateAllButton" inherits="CauldronButtonTemplate" text="CREATE_ALL">
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronQueueAllButton" relativePoint="RIGHT">
+                                <Offset x="0" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                getglobal(self:GetName()):Disable();
+                            </OnLoad>
+							<OnClick>
+								Cauldron:CreateAllTradeSkillItem();
+							</OnClick>
+                        </Scripts>
+                    </Button>
+
+                    <!-- Number input -->
+                    <Button name="CauldronAmountDecrementButton">
+                        <Size x="23" y="22" />
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronCreateAllButton" relativePoint="RIGHT">
+                                <Offset x="0" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnClick>
+                                Cauldron:AmountDecrement_OnClick();
+                                CauldronAmountInputBox:ClearFocus();
+							</OnClick>
+                        </Scripts>
+                        <NormalTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Up" />
+                        <PushedTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Down" />
+                        <DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Disabled" />
+                        <HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" />
+                    </Button>
+                    <EditBox name="CauldronAmountInputBox" letters="3" numeric="true" autoFocus="false">
+                        <Size x="30" y="20" />
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronAmountDecrementButton" relativePoint="RIGHT">
+                                <Offset x="4" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Layers>
+                            <Layer level="BACKGROUND">
+                                <Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
+                                    <Size x="8" y="20" />
+                                    <Anchors>
+                                        <Anchor point="TOPLEFT">
+                                            <Offset x="-5" y="0" />
+                                        </Anchor>
+                                    </Anchors>
+                                    <TexCoords left="0" right="0.0625" top="0" bottom="0.625" />
+                                </Texture>
+                                <Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
+                                    <Size x="8" y="20" />
+                                    <Anchors>
+                                        <Anchor point="RIGHT">
+                                            <Offset x="0" y="0" />
+                                        </Anchor>
+                                    </Anchors>
+                                    <TexCoords left="0.9375" right="1.0" top="0" bottom="0.625" />
+                                </Texture>
+                                <Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
+                                    <Size x="10" y="20" />
+                                    <Anchors>
+                                        <Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT" />
+                                        <Anchor point="RIGHT" relativeTo="$parentRight" relativePoint="LEFT" />
+                                    </Anchors>
+                                    <TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625" />
+                                </Texture>
+                            </Layer>
+                        </Layers>
+                        <Scripts>
+                        	<OnLoad>
+                        		self:SetText("1");
+                        	</OnLoad>
+                            <OnEnterPressed>
+                                self:ClearFocus();
+							</OnEnterPressed>
+                            <OnEscapePressed>
+                                self:ClearFocus();
+							</OnEscapePressed>
+                            <OnTextChanged>
+                                if ( self:GetText() == "0" ) then
+									self:SetText("1");
+                                end
+							</OnTextChanged>
+                            <OnEditFocusLost>
+                                self:HighlightText(0, 0);
+							</OnEditFocusLost>
+                            <OnEditFocusGained>
+                                self:HighlightText();
+							</OnEditFocusGained>
+                        </Scripts>
+                        <FontString inherits="ChatFontNormal" />
+                    </EditBox>
+                    <Button name="CauldronAmountIncrementButton">
+                        <Size x="23" y="22" />
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronAmountInputBox" relativePoint="RIGHT">
+                                <Offset x="-3" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnClick>
+                                Cauldron:AmountIncrement_OnClick();
+                                CauldronAmountInputBox:ClearFocus();
+                            </OnClick>
+                        </Scripts>
+                        <NormalTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Up" />
+                        <PushedTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Down" />
+                        <DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Disabled" />
+                        <HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" />
+                    </Button>
+
+                    <!-- Create button (disabled) -->
+                    <Button name="CauldronCreateButton" inherits="CauldronButtonTemplate" text="CREATE">
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronAmountIncrementButton" relativePoint="RIGHT">
+                                <Offset x="0" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                getglobal(self:GetName()):Disable();
+                            </OnLoad>
+							<OnClick>
+								Cauldron:CreateTradeSkillItem();
+							</OnClick>
+                        </Scripts>
+                    </Button>
+
+                    <!-- Queue button -->
+                    <Button name="CauldronQueueButton" inherits="CauldronButtonTemplate" text="Queue">
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronCreateButton" relativePoint="RIGHT">
+                                <Offset x="0" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                getglobal(self:GetName()):Disable();
+                            </OnLoad>
+							<OnClick>
+								Cauldron:QueueTradeSkillItem();
+								Cauldron:UpdateQueue();
+                            	Cauldron:UpdateButtons();
+							</OnClick>
+                        </Scripts>
+                    </Button>
+
+                    <!-- spacer -->
+
+                    <!-- Process button (disabled) -->
+                    <Button name="CauldronProcessButton" inherits="CauldronButtonTemplate" text="Process">
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronQueueButton" relativePoint="RIGHT">
+                                <Offset x="10" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                getglobal(self:GetName()):Disable();
+                            </OnLoad>
+							<OnClick>
+								Cauldron:ProcessQueue();
+							</OnClick>
+                        </Scripts>
+                    </Button>
+
+                    <!-- Clear Queue button (disabled) -->
+                    <Button name="CauldronClearQueueButton" inherits="CauldronButtonTemplate" text="Clear Queue">
+                        <Size x="90" y="20" />
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronProcessButton" relativePoint="RIGHT">
+                                <Offset x="0" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnLoad>
+                                getglobal(self:GetName()):Disable();
+                            </OnLoad>
+							<OnClick>
+								CauldronQueue:ClearQueue(Cauldron:GetQueue());
+								Cauldron:UpdateQueue();
+							</OnClick>
+                        </Scripts>
+                    </Button>
+
+                    <!-- spacer -->
+
+                    <!-- Close button -->
+                    <Button name="CauldronCloseButton" inherits="CauldronButtonTemplate" text="CLOSE">
+                        <Anchors>
+                            <Anchor point="LEFT" relativeTo="CauldronClearQueueButton" relativePoint="RIGHT">
+                                <Offset x="12" y="0" />
+                            </Anchor>
+                        </Anchors>
+                        <Scripts>
+                            <OnClick>
+								HideUIPanel(TradeSkillFrame);
+								PlaySound("igCharacterInfoClose");
+                            </OnClick>
+                        </Scripts>
+                    </Button>
+                </Frames>
+            </Frame>
+        </Frames>
+
+        <Scripts>
+            <OnLoad>
+                self:SetBackdropColor(.05,.05,.05,.8);
+                self:SetBackdropBorderColor(.4,.4,.4,1);
+                tinsert(UISpecialFrames, self:GetName());
+            </OnLoad>
+            <OnShow>
+                PlaySound("igCharacterInfoOpen");
+            </OnShow>
+            <OnHide>
+                --HideUIPanel(CauldronFrame);
+                PlaySound("igCharacterInfoClose");
+            </OnHide>
+            <OnMouseWheel>
+                return;
+            </OnMouseWheel>
+        </Scripts>
+    </Frame>
+
+</Ui>
diff --git a/CauldronMainUI.lua b/CauldronMainUI.lua
new file mode 100644
index 0000000..09eb7af
--- /dev/null
+++ b/CauldronMainUI.lua
@@ -0,0 +1,1646 @@
+-- $Revision$
+-- Cauldron user interface logic
+
+local L = LibStub("AceLocale-3.0"):GetLocale("Cauldron")
+
+-- CauldronUI = LibStub("AceAddon-3.0"):NewAddon("CauldronUI", "AceEvent-3.0", "AceConsole-3.0", "LibDebugLog-1.0")
+
+function Cauldron:Frame_Show()
+ 	self:debug("Frame_Show enter");
+
+ 	self:debug("Frame_Show: close dropdown menus");
+ 	CloseDropDownMenus();
+
+--	self:UpdateFramePosition();
+--	self:UpdateFrameStrata();
+
+ 	self:debug("Frame_Show: show our frame");
+ 	ShowUIPanel(CauldronFrame);
+
+	if TradeSkillFrame then
+		self:debug("Frame_Show: hide the original tradeskill frame");
+
+		-- hide the original tradeskill frame
+		TradeSkillFrame:SetAlpha(0);
+--		TradeSkillFrame:ClearAllPoints();
+--		TradeSkillFrame:SetPoint("TOPLEFT", 0, 900);
+		CauldronFrame:SetPoint("TOPLEFT", TradeSkillFrame, "TOPLEFT", 0, 0);
+	end
+
+ 	self:RegisterMessage("Cauldron_Update", "OnCauldronUpdate");
+
+ 	self:debug("Frame_Show: call Frame_Update()");
+	self:Frame_Update();
+
+ 	self:debug("Frame_Show exit");
+end
+
+function Cauldron:Frame_Hide()
+ 	self:debug("Frame_Hide enter");
+
+ 	self:UnregisterEvent("Cauldron_Update")
+ 	HideUIPanel(CauldronFrame);
+
+ 	self:debug("Frame_Hide exit");
+end
+
+function Cauldron:Frame_Toggle()
+ 	self:debug("Frame_Toggle enter");
+
+ 	if CauldronFrame:IsVisible() then
+		self:debug("Frame_Toggle: call Frame_Hide()");
+ 		Cauldron:Frame_Hide();
+ 	else
+		self:debug("Frame_Toggle: call Frame_Show()");
+ 		Cauldron:Frame_Show();
+ 	end
+
+ 	self:debug("Frame_Toggle exit");
+end
+
+function Cauldron:Frame_Update()
+ 	self:debug("Frame_Update enter");
+
+	local numTradeSkills = GetNumTradeSkills();
+	self:debug("Frame_Update numTradeSkills: ",numTradeSkills);
+--	local skillOffset = FauxScrollFrame_GetOffset(TradeSkillListScrollFrame);
+	local name, rank, maxRank = GetTradeSkillLine();
+	self:debug("Frame_Update name: ",name,"; rank: ",rank,"; maxRank: ",maxRank);
+
+	if name == "UNKNOWN" then
+		return;
+	end
+
+	Cauldron:UpdateSkills();
+
+	if CURRENT_TRADESKILL ~= name then
+		self:debug("Frame_Update: current skill changed");
+
+		StopTradeSkillRepeat();
+
+		if ( CURRENT_TRADESKILL ~= "" ) then
+			-- To fix problem with switching between two tradeskills
+--			UIDropDownMenu_Initialize(TradeSkillInvSlotDropDown, TradeSkillInvSlotDropDown_Initialize);
+--			UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, 1);
+
+--			UIDropDownMenu_Initialize(TradeSkillSubClassDropDown, TradeSkillSubClassDropDown_Initialize);
+--			UIDropDownMenu_SetSelectedID(TradeSkillSubClassDropDown, 1);
+		end
+		CURRENT_TRADESKILL = name;
+	end
+
+	-- update the frame dimensions
+    -- <Size x="692" y="465" />
+	CauldronFrame:SetHeight(465);
+	CauldronFrame:SetWidth(692);
+
+	-- display skill name, level/progress
+	self:debug("Frame_Update: display skill level/progress");
+	self:UpdateSkillInfo(name, rank, maxRank);
+
+	-- update search text box
+	self:debug("Frame_Update: display search text");
+	self:UpdateSearchText();
+
+	-- TODO: update dropdowns
+	self:debug("Frame_Update: update dropdowns");
+	self:UpdateFilterDropDowns();
+
+	-- display list of matching skills
+	self:debug("Frame_Update: display list of skills");
+	self:UpdateSkillList();
+
+	-- display queue
+	self:debug("Frame_Update: display queue");
+	self:UpdateQueue();
+
+	-- update buttons
+	self:debug("Frame_Update: update buttons");
+	self:UpdateButtons();
+
+ 	self:debug("Frame_Update exit");
+end
+
+function Cauldron:UpdateSkillInfo(skillName, rank, maxRank)
+	self:debug("UpdateSkillInfo enter");
+
+	CauldronRankFrameSkillName:SetText(skillName);
+
+	CauldronRankFrame:SetStatusBarColor(0.0, 0.0, 1.0, 0.5);
+	CauldronRankFrameBackground:SetVertexColor(0.0, 0.0, 0.75, 0.5);
+	CauldronRankFrame:SetMinMaxValues(0, maxRank);
+	CauldronRankFrame:SetValue(rank);
+	CauldronRankFrameSkillRank:SetText(rank.."/"..maxRank);
+
+	self:debug("UpdateSkillInfo exit");
+end
+
+function Cauldron:UpdateSearchText()
+	self:debug("UpdateSearchText enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local searchText = self.db.realm.userdata[self.vars.playername].skills[skillName].window.search or "";
+	if searchText == "" then
+		searchText = SEARCH;
+	end
+	CauldronFiltersSearchEditBox:SetText(searchText);
+
+	self:debug("UpdateSearchText exit");
+end
+
+function Cauldron:UpdateFilterDropDowns()
+	self:debug("UpdateFilterDropDowns enter");
+
+	self:debug("UpdateFilterDropDowns exit");
+end
+
+function Cauldron:UpdateSkillList()
+	self:debug("UpdateSkillList enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local skillList = Cauldron:GetSkillList(self.vars.playername, skillName);
+	self:debug("UpdateSkillList: skillList="..#skillList);
+
+	local height = 0;
+
+	-- iterate over the list of skills
+	for i, skillInfo in ipairs(skillList) do
+		self:debug("UpdateSkillList: i="..i);
+
+		local skillFrame = _G["CauldronSkillItem"..i];
+
+		-- check if we have a frame for this position
+		if not skillFrame then
+			-- create a new frame for the skill information
+			skillFrame = CreateFrame("Button",
+									 "CauldronSkillItem"..i,
+									 CauldronSkillListFrameScrollFrameScrollChild,
+									 "CauldronSkillItemFrameTemplate");
+		end
+
+		skillFrame:SetID(i);
+		skillFrame.skillIndex = skillInfo.index;
+
+		-- set selection
+		if self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected == skillInfo.index then
+			_G["CauldronSkillItem"..i.."Selection"]:Show();
+		else
+			_G["CauldronSkillItem"..i.."Selection"]:Hide();
+		end
+
+		-- populate the frame
+		local frame = nil;
+
+		-- set name and difficulty color
+		frame = _G["CauldronSkillItem"..i.."SkillName"];
+		local nameText = skillInfo.name;
+		local potentialCount = Cauldron:GetPotentialCraftCount(skillInfo);
+		if potentialCount > 0 then
+			nameText = nameText.." ["..skillInfo.available.."/"..potentialCount.."]";
+		elseif skillInfo.available > 0 then
+			nameText = nameText.." ["..skillInfo.available.."]";
+		end
+		frame:SetText(nameText);
+		if TradeSkillTypeColor then
+			local color = TradeSkillTypeColor[skillInfo.difficulty];
+			if color then
+				frame:SetFontObject(color.font);
+				frame.r = color.r;
+				frame.g = color.g;
+				frame.b = color.b;
+			end
+		end
+
+		-- set category
+		frame = _G["CauldronSkillItem"..i.."SkillCategory"];
+		frame:SetText(skillInfo.defaultCategory);
+		if TradeSkillTypeColor then
+			frame:SetFontObject(TradeSkillTypeColor.header.font);
+			frame.r = TradeSkillTypeColor.header.r;
+			frame.g = TradeSkillTypeColor.header.g;
+			frame.b = TradeSkillTypeColor.header.b;
+		end
+
+		-- set favorite check button
+		frame = _G["CauldronSkillItem"..i.."FavoriteButton"];
+		frame:SetChecked(self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite);
+		frame.skillInfo = skillInfo;
+
+		-- set cooldown
+		frame = _G["CauldronSkillItem"..i.."SkillCooldown"];
+		local cooldown = GetTradeSkillCooldown(skillInfo.index);
+		if cooldown then
+			if not frame:IsVisible() then
+				frame:Show();
+			end
+			frame:SetText(SecondsToTime(cooldown));
+		else
+			if frame:IsVisible() then
+				frame:Hide();
+			end
+		end
+
+		-- set the icon
+		frame = _G["CauldronSkillItem"..i.."SkillIcon"];
+		frame:SetNormalTexture(skillInfo.icon);
+		frame.skillIndex = skillInfo.index;
+
+		-- set the craft count
+		frame = _G["CauldronSkillItem"..i.."SkillIconCount"];
+		local minMade, maxMade = skillInfo.minMade, skillInfo.maxMade;
+		if maxMade > 1 then
+			if minMade == maxMade then
+				frame:SetText(minMade);
+			else
+				frame:SetText(minMade.."-"..maxMade);
+			end
+			if frame:GetWidth() > 39 then
+				frame:SetText("~"..floor((minMade + maxMade)/2));
+			end
+		else
+			frame:SetText("");
+		end
+
+		-- set the disclosure button texture
+		frame = _G["CauldronSkillItem"..i.."DiscloseButton"];
+		frame.skillInfo = skillInfo;
+		self:debug("UpdateSkillList: skillInfo.name="..skillInfo.name);
+		local reagentsExpanded = self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
+		self:debug("UpdateSkillList: reagentsExpanded="..tostring(reagentsExpanded));
+		if reagentsExpanded then
+			frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+
+			_G["CauldronSkillItem"..i.."Reagents"]:Show();
+
+			-- fill in the tools info
+			local spellFocus = BuildColoredListString(GetTradeSkillTools(skillInfo.index));
+			local toolsFrame = _G["CauldronSkillItem"..i.."ReagentsToolsInfo"];
+			if spellFocus then
+				self:debug("UpdateSkillList: skill has a spell focus");
+
+				toolsFrame:Show();
+				toolsFrame:SetText(L["Requires"]..": "..spellFocus);
+				toolsFrame:SetHeight(15);
+			else
+				self:debug("UpdateSkillList: skill doesn't have a spell focus");
+
+				toolsFrame:Hide();
+				toolsFrame:SetText("");
+				toolsFrame:SetHeight(0);
+			end
+
+			-- fill in the reagents
+			_G["CauldronSkillItem"..i.."Reagents"]:SetScale(0.86);
+			local reagentCount = #skillInfo.reagents;
+
+			for j=1,8 do
+				local reagentFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j];
+
+				if j > reagentCount then
+					reagentFrame:Hide();
+				else
+					local reagentInfo = skillInfo.reagents[j];
+
+					reagentFrame.skillIndex = skillInfo.index;
+					reagentFrame.reagentIndex = reagentInfo.index;
+
+					local reagentNameFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Name"];
+					local reagentCountFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Count"];
+
+					reagentFrame:Show();
+					SetItemButtonTexture(reagentFrame, reagentInfo.icon);
+					reagentNameFrame:SetText(reagentInfo.name);
+
+					local playerReagentCount = reagentInfo.toonHas;
+
+					if playerReagentCount < reagentInfo.numRequired then
+						-- Grayout items
+						SetItemButtonTextureVertexColor(reagentFrame, 0.5, 0.5, 0.5);
+						reagentNameFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+					else
+						SetItemButtonTextureVertexColor(reagentFrame, 1.0, 1.0, 1.0);
+						reagentNameFrame:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+					end
+					if playerReagentCount >= 100 then
+						playerReagentCount = "*";
+					end
+					reagentCountFrame:SetText(playerReagentCount.."/"..reagentInfo.numRequired);
+				end
+			end
+
+			local reagentRows = math.floor((reagentCount - 1) / 2) + 1;
+			_G["CauldronSkillItem"..i.."Reagents"]:SetHeight(toolsFrame:GetHeight() + (reagentRows * _G["CauldronSkillItem"..i.."ReagentsItemDetail1"]:GetHeight()));
+			_G["CauldronSkillItem"..i]:SetHeight(_G["CauldronSkillItem"..i.."SkillIcon"]:GetHeight() + _G["CauldronSkillItem"..i.."Reagents"]:GetHeight());
+		else
+			_G["CauldronSkillItem"..i.."Reagents"]:Hide();
+
+			frame:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+			_G["CauldronSkillItem"..i]:SetHeight(_G["CauldronSkillItem"..i.."SkillIcon"]:GetHeight());
+		end
+
+		-- place the frame in the scroll view
+		if i > 1 then
+			-- anchor to the frame above
+			self:debug("UpdateSkillList: anchor frame to top left of frame above");
+			skillFrame:SetPoint("TOPLEFT", _G["CauldronSkillItem"..(i-1)], "BOTTOMLEFT", 0, -2);
+		else
+			-- anchor to the parent
+			self:debug("UpdateSkillList: anchor frame to parent");
+			skillFrame:SetPoint("TOPLEFT", 0, 0);
+		end
+
+		-- adjust the scroll child size
+		height = height + skillFrame:GetHeight();
+		self:debug("UpdateSkillList: height="..height);
+		CauldronSkillListFrameScrollFrameScrollChild:SetHeight(height);
+
+		-- show the frame
+		self:debug("UpdateSkillList: show the frame");
+		skillFrame:Show();
+	end
+
+	-- hide any remaining frames
+	local j = #skillList + 1;
+	while true do
+		local frame = _G["CauldronSkillItem"..j];
+		if not frame then
+			break;
+		end
+
+		frame:Hide();
+		frame:SetHeight(0);
+
+		j = j + 1;
+	end
+
+	self:debug("UpdateSkillList exit");
+end
+
+function Cauldron:UpdateButtons()
+	self:debug("UpdateButtons enter");
+
+	if IsTradeSkillLinked() then
+		CauldronQueueAllButton:Hide();
+		CauldronQueueButton:Hide();
+		CauldronAmountDecrementButton:Hide();
+		CauldronAmountInputBox:Hide();
+		CauldronAmountIncrementButton:Hide();
+		CauldronCreateAllButton:Hide();
+		CauldronCreateButton:Hide();
+		CauldronProcessButton:Hide();
+		CauldronClearQueueButton:Hide();
+		return;
+	else
+		CauldronQueueAllButton:Show();
+		CauldronQueueButton:Show();
+		CauldronAmountDecrementButton:Show();
+		CauldronAmountInputBox:Show();
+		CauldronAmountIncrementButton:Show();
+		CauldronCreateAllButton:Show();
+		CauldronCreateButton:Show();
+		CauldronProcessButton:Show();
+		CauldronClearQueueButton:Show();
+	end
+
+	local skillInfo = Cauldron:GetSelectedSkill();
+
+	if skillInfo then
+		if skillInfo.verb then
+			CauldronQueueAllButton:Hide();
+			CauldronQueueButton:Hide();
+			CauldronCreateAllButton:Hide();
+
+			CauldronCreateButton:Enable();
+			CauldronCreateButton:SetText(skillInfo.verb or CREATE);
+		else
+			CauldronQueueAllButton:Enable();
+			CauldronQueueButton:Enable();
+
+			if skillInfo.available then
+				CauldronCreateAllButton:Enable();
+				CauldronCreateButton:Enable();
+				CauldronCreateButton:SetText(CREATE);
+			end
+		end
+	else
+		CauldronQueueAllButton:Disable();
+		CauldronQueueButton:Disable();
+		CauldronCreateAllButton:Disable();
+		CauldronCreateButton:Disable();
+	end
+
+	if #CauldronQueue:GetItems(self.db.realm.userdata[self.vars.playername].queue, CURRENT_TRADESKILL) > 0 then
+		CauldronProcessButton:Enable();
+		CauldronClearQueueButton:Enable();
+	else
+		CauldronProcessButton:Disable();
+		CauldronClearQueueButton:Disable();
+	end
+
+	self:debug("UpdateButtons exit");
+end
+
+function Cauldron:UpdateQueue()
+	self:debug("UpdateQueue enter");
+
+	if not CauldronFrame:IsShown() then
+		return;
+	end
+
+	local queue = self.db.realm.userdata[self.vars.playername].queue;
+	local itemQueue = {};
+
+	local skillName = CURRENT_TRADESKILL;
+	if not IsTradeSkillLinked() then
+		itemQueue = CauldronQueue:GetItems(queue);
+	end
+
+	if #itemQueue == 0 then
+		self:debug("UpdateQueue: display empty queue");
+
+		-- queue is empty, display the empty message
+		CauldronQueueFrameQueueEmpty:Show();
+		CauldronQueueFrameScrollFrame:Hide();
+
+		if IsTradeSkillLinked() then
+			CauldronQueueFrameQueueEmptyText:SetText("No queue for linked tradeskills.");
+		else
+			CauldronQueueFrameQueueEmptyText:SetText("The queue is empty!\nMake something.");
+		end
+
+		return;
+	end
+
+	self:debug("UpdateQueue: display queue");
+
+	-- queue has items, show them
+	CauldronQueueFrameQueueEmpty:Hide();
+	CauldronQueueFrameScrollFrame:Show();
+
+	local itemFrameHeight = 39;
+
+	local height = 0;
+
+	CauldronQueueFrameScrollFrameQueueSectionsMainItemsHeaderText:SetText(L["In order to make:"]);
+	-- adjust the scroll child size
+	CauldronQueueFrameScrollFrameQueueSectionsMainItems:SetHeight(#itemQueue * itemFrameHeight);
+
+	for i, queueInfo in ipairs(itemQueue) do
+		local queueItemFrame = _G["CauldronQueueItem"..i];
+
+		-- check if we have a frame for this position
+		if not queueItemFrame then
+			-- create a new frame for the skill information
+			queueItemFrame = CreateFrame("Button",
+									 	 "CauldronQueueItem"..i,
+									 	 CauldronQueueFrameScrollFrameQueueSectionsMainItems,
+									 	 "CauldronQueueItemFrameTemplate");
+		end
+
+		queueItemFrame:SetID(i);
+		queueItemFrame.itemName = queueInfo.name;
+		queueItemFrame.removeable = true;
+		queueItemFrame.shoppable = false;
+		queueItemFrame.inHoverButtons = false;
+
+		_G["CauldronQueueItem"..i.."RemoveItem"]:Hide();
+		_G["CauldronQueueItem"..i.."RemoveItem"]:SetScale(0.75);
+		_G["CauldronQueueItem"..i.."IncreasePriority"]:Hide();
+		_G["CauldronQueueItem"..i.."DecreasePriority"]:Hide();
+		_G["CauldronQueueItem"..i.."DecrementCount"]:Hide();
+		_G["CauldronQueueItem"..i.."AddToShoppingList"]:Hide();
+
+		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		if not skillInfo then
+			-- the skill isn't available (character doesn't know it?)
+			-- TODO
+		end
+
+		-- initialize the frame object
+		local frame = nil;
+
+		-- set name and difficulty color
+		frame = _G["CauldronQueueItem"..i.."ItemName"];
+		frame:SetText(queueInfo.name);
+		if skillInfo then
+			local color = TradeSkillTypeColor[skillInfo.difficulty];
+			if color then
+				frame:SetFontObject(color.font);
+				frame:SetTextColor(color.r, color.g, color.b, 1.0);
+				frame.r = color.r;
+				frame.g = color.g;
+				frame.b = color.b;
+			end
+		else
+			-- TODO: default color info
+		end
+
+		-- set quantity info
+		frame = _G["CauldronQueueItem"..i.."Info"];
+		local infoText = queueInfo.tradeskill;
+		-- TODO: alts/bank/etc.
+		frame:SetText(infoText);
+--		frame:SetTextColor(1.0, 1.0, 0.2, 1.0);
+--		frame:SetShadowOffset(0, 0);
+
+		-- set the icon
+		frame = _G["CauldronQueueItem"..i.."Icon"];
+		frame:SetNormalTexture(queueInfo.icon);
+		frame.link = queueInfo.link;
+
+		-- set the amount
+		frame = _G["CauldronQueueItem"..i.."IconCount"];
+		frame:SetText(queueInfo.amount);
+
+		-- place the frame in the scroll view
+		if i > 1 then
+			-- anchor to the frame above
+			self:debug("UpdateQueue: anchor frame to top left of frame above");
+			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueItem"..(i-1)], "BOTTOMLEFT", 0, 0);
+		else
+			-- anchor to the parent
+			self:debug("UpdateQueue: anchor frame to parent");
+			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsMainItems, "TOPLEFT", 0, 0);
+		end
+
+--		height = height + queueItemFrame:GetHeight() + 2;
+--		self:debug("UpdateQueue: height="..height);
+
+		-- show the frame
+		self:debug("UpdateQueue: show the frame");
+		queueItemFrame:Show();
+	end
+
+	-- hide any remaining frames
+	local j = #itemQueue + 1;
+	while true do
+		local frame = _G["CauldronQueueItem"..j];
+		if not frame then
+			break;
+		end
+
+		_G["CauldronQueueItem"..j] = nil;
+
+		frame:Hide();
+		frame:SetHeight(0);
+
+		j = j + 1;
+	end
+
+	local intQueue = CauldronQueue:GetIntermediates(queue);
+	local reagentList = CauldronQueue:GetReagents(queue);
+
+	-- store the intermediate queue and the reagent list
+--	self.db.realm.userdata[self.vars.playername].intQueue = intQueue;
+--	self.db.realm.userdata[self.vars.playername].reagentList = reagentList;
+
+	-- display intermediate queue, maybe
+	if #intQueue == 0 then
+		self:debug("UpdateQueue: intermediate queue is empty, hide header and item frames");
+		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:SetHeight(1);
+		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeaderText:SetText("");
+		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(1);
+	else
+		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:SetHeight(12);
+		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeaderText:SetText(L["You first have to make:"]);
+
+		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(#intQueue * itemFrameHeight);
+
+		local intHeight = 0;
+
+		for i, queueInfo in ipairs(intQueue) do
+			local queueItemFrame = _G["CauldronQueueIntItem"..i];
+
+			-- check if we have a frame for this position
+			if not queueItemFrame then
+				-- create a new frame for the skill information
+				queueItemFrame = CreateFrame("Button",
+											 "CauldronQueueIntItem"..i,
+											 CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems,
+											 "CauldronQueueItemFrameTemplate");
+			end
+
+			queueItemFrame:SetID(i);
+			queueItemFrame.itemName = queueInfo.name;
+			queueItemFrame.removeable = false;
+			queueItemFrame.shoppable = false;
+			queueItemFrame.inHoverButtons = false;
+
+			-- don't show the remove button
+			_G["CauldronQueueIntItem"..i.."RemoveItem"]:Hide();
+			_G["CauldronQueueIntItem"..i.."RemoveItem"]:SetScale(0.75);
+			_G["CauldronQueueIntItem"..i.."IncreasePriority"]:Hide();
+			_G["CauldronQueueIntItem"..i.."DecreasePriority"]:Hide();
+			_G["CauldronQueueIntItem"..i.."DecrementCount"]:Hide();
+			_G["CauldronQueueIntItem"..i.."AddToShoppingList"]:Hide();
+
+			local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+			if not skillInfo then
+				-- the skill isn't available (character doesn't know it?)
+				-- TODO
+			end
+
+			-- populate the frame
+			local frame = nil;
+
+			-- set name and difficulty color
+			frame = _G["CauldronQueueIntItem"..i.."ItemName"];
+			frame:SetText(queueInfo.name);
+			if skillInfo then
+				local color = TradeSkillTypeColor[skillInfo.difficulty];
+				if color then
+					frame:SetFontObject(color.font);
+					frame:SetTextColor(color.r, color.g, color.b, 1.0);
+					frame.r = color.r;
+					frame.g = color.g;
+					frame.b = color.b;
+				end
+			else
+				frame:SetFont("GameFontNormal", 12);
+--				frame:SetTextColor(1.0, 1.0, 1.0, 1.0);
+				frame.r = 1.0;
+				frame.g = 1.0;
+				frame.b = 1.0;
+			end
+
+			-- set quantity info
+			frame = _G["CauldronQueueIntItem"..i.."Info"];
+			local countInfo = Cauldron:ReagentCount(queueInfo.name);
+			local infoText = string.format(queueInfo.tradeskill.."; "..L["Have %d"], countInfo.has);
+			local need = math.max(0, queueInfo.amount - countInfo.has);
+			if need > 0 then
+				infoText = infoText..string.format(L[", need %d"], need);
+			end
+			-- alts/bank/etc.
+			frame:SetText(infoText);
+			frame:SetTextColor(0.1, 0.1, 0.1, 1.0);
+			frame:SetShadowOffset(0, 0);
+
+			-- set the icon
+			frame = _G["CauldronQueueIntItem"..i.."Icon"];
+			frame:SetNormalTexture(queueInfo.icon);
+			frame.link = queueInfo.link;
+
+			-- set the amount
+			frame = _G["CauldronQueueIntItem"..i.."IconCount"];
+			frame:SetText(queueInfo.amount);
+
+			-- place the frame in the scroll view
+			if i > 1 then
+				-- anchor to the frame above
+				self:debug("UpdateQueue: anchor frame to top left of frame above");
+				queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueIntItem"..(i-1)], "BOTTOMLEFT", 0, 0);
+			else
+				-- anchor to the parent
+				self:debug("UpdateQueue: anchor frame to parent");
+				queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems, "TOPLEFT", 0, 0);
+			end
+
+			-- adjust the scroll child size
+--			intHeight = intHeight + queueItemFrame:GetHeight() + 2;
+--			self:debug("UpdateQueue: height="..height);
+--			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(intHeight);
+
+			-- show the frame
+			self:debug("UpdateQueue: show the frame");
+			queueItemFrame:Show();
+		end
+	end
+
+	-- hide any remaining frames
+	local j = #intQueue + 1;
+	while true do
+		local frame = _G["CauldronQueueIntItem"..j];
+		if not frame then
+			break;
+		end
+
+		_G["CauldronQueueIntItem"..j] = nil;
+
+		frame:Hide();
+		frame:SetHeight(0);
+
+		j = j + 1;
+	end
+
+	-- display reagent list
+
+	CauldronQueueFrameScrollFrameQueueSectionsReagentsHeaderText:SetText(L["You will need:"]);
+	CauldronQueueFrameScrollFrameQueueSectionsReagents:SetHeight(#reagentList * itemFrameHeight);
+
+	local reagentHeight = 0;
+
+	for i, queueInfo in ipairs(reagentList) do
+		local queueItemFrame = _G["CauldronQueueReagentItem"..i];
+
+		-- check if we have a frame for this position
+		if not queueItemFrame then
+			-- create a new frame for the skill information
+			queueItemFrame = CreateFrame("Button",
+										 "CauldronQueueReagentItem"..i,
+										 CauldronQueueFrameScrollFrameQueueSectionsReagents,
+										 "CauldronQueueItemFrameTemplate");
+		end
+
+		local countInfo = Cauldron:ReagentCount(queueInfo.name);
+		local need = math.max(0, queueInfo.amount - countInfo.has);
+
+		queueItemFrame:SetID(i);
+		queueItemFrame.skillIndex = queueInfo.skillIndex;
+		queueItemFrame.index = queueInfo.index;
+		queueItemFrame.itemName = queueInfo.name;
+		queueItemFrame.removeable = false;
+		queueItemFrame.shoppable = true;
+		queueItemFrame.inHoverButtons = false;
+		queueItemFrame.needAmount = need;
+
+		-- don't show the remove button
+		_G["CauldronQueueReagentItem"..i.."RemoveItem"]:Hide();
+		_G["CauldronQueueReagentItem"..i.."RemoveItem"]:SetScale(0.75);
+		_G["CauldronQueueReagentItem"..i.."IncreasePriority"]:Hide();
+		_G["CauldronQueueReagentItem"..i.."DecreasePriority"]:Hide();
+		_G["CauldronQueueReagentItem"..i.."DecrementCount"]:Hide();
+		_G["CauldronQueueReagentItem"..i.."AddToShoppingList"]:Hide();
+		_G["CauldronQueueReagentItem"..i.."AddToShoppingList"]:SetScale(0.5);
+
+		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		if not skillInfo then
+			-- TODO
+		end
+
+		-- populate the frame
+		local frame = nil;
+
+		-- set name and difficulty color
+		frame = _G["CauldronQueueReagentItem"..i.."ItemName"];
+		frame:SetText(queueInfo.name);
+		frame:SetShadowOffset(0, 0);
+		frame:SetFont("GameFontNormal", 12);
+		frame:SetTextColor(0.1, 0.1, 0.1, 1.0);
+		frame.r = 1.0;
+		frame.g = 1.0;
+		frame.b = 1.0;
+
+		-- set quantity info
+		frame = _G["CauldronQueueReagentItem"..i.."Info"];
+		local countInfo = Cauldron:ReagentCount(queueInfo.name);
+		local qtyText = string.format(L["Have %d"], countInfo.has);
+		if need > 0 then
+			qtyText = qtyText..string.format(L[", need %d"], need);
+		end
+		-- TODO: alts/bank/etc.
+		frame:SetText(qtyText);
+		frame:SetTextColor(0.4, 0.4, 0.4, 1.0);
+		frame:SetShadowOffset(0, 0);
+
+		-- set the icon
+		frame = _G["CauldronQueueReagentItem"..i.."Icon"];
+		frame:SetNormalTexture(queueInfo.icon);
+		frame.link = queueInfo.link;
+--		local playerReagentCount = 0; -- TODO
+--		if playerReagentCount < queueInfo.amount then
+--			frame:SetVertexColor(0.5, 0.5, 0.5, 1.0);
+--			frame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+--		else
+--			frame:SetVertexColor(1.0, 1.0, 1.0, 1.0);
+--			frame:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+--		end
+
+		-- set the amount
+		frame = _G["CauldronQueueReagentItem"..i.."IconCount"];
+		frame:SetText(queueInfo.amount);
+
+		-- place the frame in the scroll view
+		if i > 1 then
+			-- anchor to the frame above
+			self:debug("UpdateQueue: anchor frame to top left of frame above");
+			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueReagentItem"..(i-1)], "BOTTOMLEFT", 0, 0);
+		else
+			-- anchor to the parent
+			self:debug("UpdateQueue: anchor frame to parent");
+			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsReagents, "TOPLEFT", 0, 0);
+		end
+
+		-- adjust the scroll child size
+--		reagentHeight = reagentHeight + queueItemFrame:GetHeight() + 2;
+--		self:debug("UpdateQueue: height="..height);
+--		CauldronQueueFrameScrollFrameQueueSectionsReagents:SetHeight(reagentHeight);
+
+		-- show the frame
+		self:debug("UpdateQueue: show the frame");
+		queueItemFrame:Show();
+	end
+
+	-- hide any remaining frames
+	local j = #reagentList + 1;
+	while true do
+		local frame = _G["CauldronQueueReagentItem"..j];
+		if not frame then
+			break;
+		end
+
+		_G["CauldronQueueReagentItem"..j] = nil;
+
+		frame:Hide();
+		frame:SetHeight(0);
+
+		j = j + 1;
+	end
+--]]
+	-- adjust the height of the scroll frame
+	local h = CauldronQueueFrameScrollFrameQueueSectionsMainItemsHeader:GetHeight() +
+			CauldronQueueFrameScrollFrameQueueSectionsMainItems:GetHeight() +
+			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:GetHeight() +
+			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:GetHeight() +
+			CauldronQueueFrameScrollFrameQueueSectionsReagentsHeader:GetHeight() +
+			CauldronQueueFrameScrollFrameQueueSectionsReagents:GetHeight();
+	CauldronQueueFrameScrollFrameQueueSections:SetHeight(h);
+	CauldronQueueFrameScrollFrame:UpdateScrollChildRect();
+
+	self:debug("UpdateQueue exit");
+end
+
+function Cauldron:SaveFramePosition()
+ 	self:debug("SaveFramePosition enter");
+
+-- TODO
+
+ 	self:debug("SaveFramePosition exit");
+end
+
+function Cauldron:OnCauldronUpdate()
+	self:debug("OnCauldronUpdate enter");
+
+--	self:Search();
+ 	local selectionIndex
+ 	if self.vars.selectionIndex == 0 then
+ 		selectionIndex = self:GetFirstTradeSkill();
+ 	else
+ 		selectionIndex = self.vars.selectionIndex;
+ 	end
+
+	self:debug("OnCauldronUpdate exit");
+end
+
+function Cauldron:FilterDropDown_OnLoad(dropdown)
+	self:debug("FilterDropDown_OnLoad enter");
+
+--[[
+	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
+		return;
+	end
+--]]
+
+	UIDropDownMenu_Initialize(dropdown, Cauldron.FilterDropDown_Initialize);
+	UIDropDownMenu_SetText(CauldronFiltersFilterDropDown, L["Filters"]);
+
+	self:debug("FilterDropDown_OnLoad exit");
+end
+
+function Cauldron:InvSlotDropDown_OnLoad(dropdown)
+	self:debug("InvSlotDropDown_OnLoad enter");
+
+--[[
+	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
+		return;
+	end
+--]]
+
+	UIDropDownMenu_Initialize(dropdown, Cauldron.InvSlotDropDown_Initialize);
+	UIDropDownMenu_SetText(CauldronFiltersInvSlotDropDown, L["Slots"]);
+
+	self:debug("InvSlotDropDown_OnLoad exit");
+end
+
+function Cauldron:CategoryDropDown_OnLoad(dropdown)
+	self:debug("CategoryDropDown_OnLoad enter");
+
+--[[
+	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
+		return;
+	end
+--]]
+
+	UIDropDownMenu_Initialize(dropdown, Cauldron.CategoryDropDown_Initialize);
+	UIDropDownMenu_SetText(CauldronFiltersCategoryDropDown, L["Categories"]);
+
+	self:debug("CategoryDropDown_OnLoad exit");
+end
+
+function Cauldron:FilterDropDown_Initialize(level)
+	Cauldron:debug("FilterDropDown_Initialize enter");
+
+--[[
+	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
+		return;
+	end
+--]]
+
+	if not Cauldron.db then
+		return;
+	end
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	UIDropDownMenu_SetText(CauldronFiltersFilterDropDown, L["Filters"]);
+
+	-- sorting
+
+	local sortingTitle = {
+		text = L["Sort"],
+		isTitle = true,
+		tooltipTitle = "",
+		tooltipText = "",
+	};
+	UIDropDownMenu_AddButton(sortingTitle);
+
+	local sortAlpha = {
+		text = L["Alphabetically"],
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortAlpha,
+		tooltipTitle = L["Alphabetically"],
+		tooltipText = L["Set the sorting method to use on the skills list"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
+		arg1 = "alpha",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(sortAlpha);
+
+	local sortDifficulty = {
+		text = L["By difficulty"],
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDifficulty,
+		tooltipTitle = L["By difficulty"],
+		tooltipText = L["Set the sorting method to use on the skills list"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
+		arg1 = "difficulty",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(sortDifficulty);
+
+	--[[
+	local sortBenefit = {
+		text = L["By benefit"],
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit,
+		tooltipTitle = L["By benefit"],
+		tooltipText = L["Set the sorting method to use on the skills list"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
+		arg1 = "benefit",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(sortBenefit);
+	--]]
+
+	-- spacer
+	UIDropDownMenu_AddButton({
+		text = "",
+		notClickable = true,
+	});
+
+	-- skill difficulty
+
+	local difficultyTitle = {
+		text = L["Difficulty"],
+		isTitle = true,
+		tooltipTitle = "",
+		tooltipText = "",
+	};
+	UIDropDownMenu_AddButton(difficultyTitle);
+
+	local difficultyOptimal = {
+		text = L["Optimal"],
+--		textR = 1.0,
+--		textG = 1.0,
+--		textB = 1.0,
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.optimal,
+--		keepShownOnClick = true,
+		tooltipTitle = L["Optimal"],
+		tooltipText = L["Set whether items of this difficulty level should be shown"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
+		arg1 = "optimal",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(difficultyOptimal);
+
+	local difficultyMedium = {
+		text = L["Medium"],
+--		textR = 1.0,
+--		textG = 1.0,
+--		textB = 1.0,
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.medium,
+--		keepShownOnClick = true,
+		tooltipTitle = L["Medium"],
+		tooltipText = L["Set whether items of this difficulty level should be shown"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
+		arg1 = "medium",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(difficultyMedium);
+
+	local difficultyEasy = {
+		text = L["Easy"],
+--		textR = 1.0,
+--		textG = 1.0,
+--		textB = 1.0,
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.easy,
+--		keepShownOnClick = true,
+		tooltipTitle = L["Easy"],
+		tooltipText = L["Set whether items of this difficulty level should be shown"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
+		arg1 = "easy",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(difficultyEasy);
+
+	local difficultyTrivial = {
+		text = L["Trivial"],
+--		textR = 1.0,
+--		textG = 1.0,
+--		textB = 1.0,
+		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.trivial,
+--		keepShownOnClick = true,
+		tooltipTitle = L["Trivial"],
+		tooltipText = L["Set whether items of this difficulty level should be shown"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_ToggleDifficulty(arg1) end,
+		arg1 = "trivial",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(difficultyTrivial);
+
+	-- spacer
+	UIDropDownMenu_AddButton({
+		text = "",
+		notClickable = true,
+	});
+
+	if not IsTradeSkillLinked() then
+		local miscTitle = {
+			text = L["Miscellaneous"],
+			isTitle = true,
+			tooltipTitle = "",
+			tooltipText = "",
+		};
+		UIDropDownMenu_AddButton(miscTitle);
+
+		-- favorites
+		local faves = {
+			text = L["Favorites"],
+			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites,
+			tooltipTitle = L["Favorites"],
+			tooltipText = L["Display only favorite skills"],
+			func = function(arg1, arg2) Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites; Cauldron:UpdateSkillList(); end,
+			arg1 = "favorite",
+			arg2 = "",
+		};
+		UIDropDownMenu_AddButton(faves);
+
+		-- spacer
+		UIDropDownMenu_AddButton({
+			text = "",
+			notClickable = true,
+		});
+	end
+
+	-- reagents availability
+
+	local reagentsTitle = {
+		text = L["Reagents"],
+		isTitle = true,
+		tooltipTitle = "",
+		tooltipText = "",
+	};
+	UIDropDownMenu_AddButton(reagentsTitle);
+
+	-- force check "normal" if the list is linked
+	if IsTradeSkillLinked() then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
+	end
+
+	local normal = {
+		text = L["Normal"],
+		checked = Cauldron:ReagentsFilterNormalCheck(),
+		tooltipTitle = L["Reagents"],
+		tooltipText = L["Display the normal list of skills"],
+		func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
+		arg1 = "normal",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(normal);
+
+	if not IsTradeSkillLinked() then
+
+		local haveAllReagents = {
+			text = L["Have all"],
+			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents,
+			tooltipTitle = L["Reagents"],
+			tooltipText = L["Set whether skills for which you have all the required reagents are shown in the list"],
+			func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
+			arg1 = "all",
+			arg2 = "",
+		};
+		UIDropDownMenu_AddButton(haveAllReagents);
+
+		--[[
+		local haveKeyReagents = {
+			text = L["Have key"],
+			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents,
+			tooltipTitle = L["Reagents"],
+			tooltipText = L["Set whether skills for which you have all key reagents (non-vendor available) are shown in the list"],
+			func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
+			arg1 = "key",
+			arg2 = "",
+		};
+		UIDropDownMenu_AddButton(haveKeyReagents);
+		--]]
+
+		local haveAnyReagents = {
+			text = L["Have any"],
+			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents,
+			tooltipTitle = L["Reagents"],
+			tooltipText = L["Set whether skills for which you have any reagents are shown in the list"],
+			func = function(arg1, arg2) Cauldron:FilterDropDown_SetReagentFilter(arg1) end,
+			arg1 = "any",
+			arg2 = "",
+		};
+		UIDropDownMenu_AddButton(haveAnyReagents);
+
+	end
+
+	Cauldron:debug("FilterDropDown_Initialize exit");
+end
+
+function Cauldron:FilterDropDown_SetSort(info)
+	self:debug("FilterDropDown_SetSort enter");
+
+	local sort = info.arg1;
+
+	if sort == "alpha" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortAlpha = true;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortDifficulty = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit = false;
+	elseif sort == "difficulty" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortAlpha = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortDifficulty = true;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit = false;
+	elseif sort == "benefit" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortAlpha = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortDifficulty = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter.sortBenefit = true;
+	end
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("FilterDropDown_SetSort exit");
+end
+
+function Cauldron:ReagentsFilterNormalCheck()
+	self:debug("ReagentsFilterNormalCheck enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local checked = true;
+
+	if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents or
+	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents or
+	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents then
+	   	checked = false;
+	end
+
+	self:debug("ReagentsFilterNormalCheck exit");
+
+	return checked;
+end
+
+function Cauldron:FilterDropDown_SetReagentFilter(info)
+	self:debug("FilterDropDown_SetReagentFilter enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local reagents = info.arg1;
+
+	if reagents == "normal" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
+	elseif reagents == "all" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = true;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
+	elseif reagents == "key" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = true;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
+	elseif reagents == "any" then
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
+	   	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = true;
+	end
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("FilterDropDown_SetReagentFilter exit");
+end
+
+function Cauldron:FilterDropDown_ToggleDifficulty(info)
+	self:debug("FilterDropDown_ToggleDifficulty enter");
+
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter[info.arg1] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter[info.arg1];
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("FilterDropDown_ToggleDifficulty exit");
+end
+
+function Cauldron:InvSlotDropDown_Initialize(level)
+	Cauldron:debug("InvSlotDropDown_Initialize enter");
+
+--[[
+	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
+		return;
+	end
+--]]
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	UIDropDownMenu_SetText(CauldronFiltersInvSlotDropDown, L["Slots"]);
+
+	local all = {
+		text = L["All slots"],
+		checked = false,
+		tooltipTitle = L["All slots"],
+		func = function(arg1, arg2) Cauldron:InvSlotDropDown_SetSlot(arg1) end,
+		arg1 = "all",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(all);
+
+	local none = {
+		text = L["(None)"],
+		checked = true,
+		tooltipTitle = L["(None)"],
+		func = function(arg1, arg2) Cauldron:InvSlotDropDown_SetSlot(arg1) end,
+		arg1 = "none",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(none);
+
+	local slots = Cauldron:GetSlots(Cauldron.vars.playername, skillName);
+
+	for name, _ in pairs(slots) do
+		if slot ~= "" then
+			local slot = {
+				text = _G[name],
+				checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[name],
+				tooltipTitle = _G[name],
+				func = function(arg1, arg2) Cauldron:InvSlotDropDown_SetSlot(arg1) end,
+				arg1 = name,
+				arg2 = "",
+			};
+			UIDropDownMenu_AddButton(slot);
+		end
+	end
+
+	Cauldron:debug("InvSlotDropDown_Initialize exit");
+end
+
+function Cauldron:SlotsFilterAllCheck()
+	self:debug("SlotsFilterAllCheck enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local checked = true;
+
+	if Cauldron.db then
+		for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots) do
+			if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[name] then
+				checked = false;
+				break;
+			end
+		end
+	end
+
+	self:debug("SlotsFilterAllCheck exit");
+
+	return checked;
+end
+
+function Cauldron:InvSlotDropDown_SetSlot(info)
+	self:debug("InvSlotDropDown_SetSlot enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	self:debug("InvSlotDropDown_SetSlot: info.arg1="..info.arg1);
+
+	if info.arg1 == "all" then
+		self:debug("InvSlotDropDown_SetSlot: selecting all slots...");
+		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots["(none)"] = true;
+		for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots) do
+			self:debug("InvSlotDropDown_SetSlot: name="..name);
+			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[name] = true;
+		end
+	elseif info.arg1 == "none" then
+		self:debug("InvSlotDropDown_SetSlot: selecting special 'none' slot...");
+		local slotName = "(none)";
+		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName] then
+			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName] = true;
+		else
+			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slotName];
+		end
+	else
+		self:debug("InvSlotDropDown_SetSlot: select a specific slot: "..info.arg1);
+		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1] then
+			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1] = true;
+		else
+			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[info.arg1];
+		end
+	end
+
+	self:debug("InvSlotDropDown_SetSlot exit");
+end
+
+function Cauldron:CategoryDropDown_Initialize(level)
+	Cauldron:debug("CategoryDropDown_Initialize enter");
+
+--[[
+	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
+		return;
+	end
+--]]
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	UIDropDownMenu_SetText(CauldronFiltersCategoryDropDown, L["Categories"]);
+
+	local all = {
+		text = L["All categories"],
+		checked = false, -- Cauldron:CategoriesFilterAllCheck(),
+		tooltipTitle = L["All categories"],
+		func = function(arg1, arg2) Cauldron:CategoryDropDown_SetCategory(arg1) end,
+		arg1 = "all",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(all);
+
+	local none = {
+		text = L["No categories"],
+		checked = false, -- Cauldron:CategoriesFilterAllCheck(),
+		tooltipTitle = L["No categories"],
+		func = function(arg1, arg2) Cauldron:CategoryDropDown_SetCategory(arg1) end,
+		arg1 = "none",
+		arg2 = "",
+	};
+	UIDropDownMenu_AddButton(none);
+
+	local categories = Cauldron:GetDefaultCategories(Cauldron.vars.playername, skillName);
+
+	-- sort the category list by alpha
+	local c = {};
+	for name, _ in pairs(categories) do
+		table.insert(c, name);
+	end
+
+	table.sort(c);
+
+	for i, name in ipairs(c) do
+		local category = {
+			text = name,
+			checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name].shown,
+			tooltipTitle = name,
+			func = function(arg1, arg2) Cauldron:CategoryDropDown_SetCategory(arg1) end,
+			arg1 = name,
+			arg2 = "",
+		};
+		UIDropDownMenu_AddButton(category);
+	end
+
+	Cauldron:debug("CategoryDropDown_Initialize exit");
+end
+
+--[[
+function Cauldron:CategoriesFilterAllCheck()
+	self:debug("CategoriesFilterAllCheck enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local checked = true;
+
+	for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories) do
+		if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name] then
+			checked = false;
+			break;
+		end
+	end
+
+	self:debug("CategoriesFilterAllCheck exit");
+
+	return checked;
+end
+--]]
+
+function Cauldron:CategoryDropDown_SetCategory(info)
+	self:debug("CategoryDropDown_SetCategory enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	if info.arg1 == "all" or info.arg1 == "none" then
+		for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories) do
+			local checked = (info.arg1 == "all");
+			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name].shown = checked;
+		end
+	else
+		if not IsShiftKeyDown() then
+			-- uncheck everything
+			for name, _ in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories) do
+				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[name].shown = false;
+			end
+
+			-- check the clicked item
+			Cauldron.db.realm.userdata[self.vars.playername].skills[skillName].window.categories[info.arg1].shown = true;
+		else
+			Cauldron.db.realm.userdata[self.vars.playername].skills[skillName].window.categories[info.arg1].shown = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.categories[info.arg1].shown;
+		end
+	end
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("CategoryDropDown_SetCategory exit");
+end
+
+function Cauldron:CollapseAllButton_OnClick(button)
+	self:debug("CollapseAllButton_OnClick enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	-- reset all the expanded fields to false
+	for name, info in pairs(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills) do
+		info.expanded = false;
+	end
+
+	-- unselect the selected skill
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = 0;
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("CollapseAllButton_OnClick exit");
+end
+
+function Cauldron:CollapseItemButton_OnClick(button)
+	self:debug("CollapseItemButton_OnClick enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local skillInfo = button.skillInfo;
+
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = skillInfo.index;
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("CollapseItemButton_OnClick exit");
+end
+
+function Cauldron:SkillItem_OnEnter(frame)
+	self:debug("SkillItem_OnEnter enter");
+
+	local id = frame:GetID();
+	self:debug("SkillItem_OnEnter: id="..id);
+
+	local name = _G["CauldronSkillItem"..id.."SkillName"];
+	if name then
+--		name:
+	end
+
+	-- TODO
+
+	self:debug("SkillItem_OnEnter exit");
+end
+
+function Cauldron:SkillItem_OnLeave(frame)
+	self:debug("SkillItem_OnLeave enter");
+
+
+
+	self:debug("SkillItem_OnLeave exit");
+end
+
+function Cauldron:SkillItem_OnClick(frame, button, down)
+	self:debug("SkillItem_OnClick enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+	self:debug("SkillItem_OnClick: skillName="..skillName);
+
+	-- select this frame
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = frame.skillIndex;
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+	Cauldron:UpdateButtons();
+
+	self:debug("SkillItem_OnClick exit");
+end
+
+function Cauldron:TradeSkillFilter_OnTextChanged(frame)
+	self:debug("TradeSkillFilter_OnTextChanged enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local text = frame:GetText();
+	if text == SEARCH then
+		text = "";
+	end
+
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.search = text;
+
+	-- update the UI
+	Cauldron:UpdateSkillList();
+
+	self:debug("TradeSkillFilter_OnTextChanged exit");
+end
+
+function Cauldron:AmountDecrement_OnClick()
+	self:debug("AmountDecrement_OnClick enter");
+
+	local num = CauldronAmountInputBox:GetNumber();
+	num = math.max(1, num - 1);
+	CauldronAmountInputBox:SetNumber(num);
+
+	self:debug("AmountDecrement_OnClick exit");
+end
+
+function Cauldron:AmountIncrement_OnClick()
+	self:debug("AmountIncrement_OnClick enter");
+
+	local num = CauldronAmountInputBox:GetNumber();
+	num = math.min(999, num + 1);
+	CauldronAmountInputBox:SetNumber(num);
+
+	self:debug("AmountIncrement_OnClick exit");
+end
+
+function Cauldron:FavoriteItemButton_OnClick(button)
+	self:debug("FavoriteItemButton_OnClick enter");
+
+	local skillName = CURRENT_TRADESKILL;
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	local skillInfo = button.skillInfo;
+
+	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite = button:GetChecked();
+
+	self:debug("FavoriteItemButton_OnClick exit");
+end
diff --git a/CauldronQueue.lua b/CauldronQueue.lua
new file mode 100644
index 0000000..b6b3550
--- /dev/null
+++ b/CauldronQueue.lua
@@ -0,0 +1,463 @@
+-- $Revision$
+-- Cauldron queue management functions
+
+CauldronQueue = {};
+
+--[[
+	The following table describes a queue item in the "main" and "intermediate"
+	sections of the queue:
+
+	queueItem = {
+		["name"] = "<name of skill>",
+		["icon"] = "<icon path>",
+		["tradeskill"] = "<name of tradeskill>",
+		["amount"] = <amount>,
+		["priority"] = <priority>,
+		["link"] = "<link>",
+	};
+
+	The following table describes a reagent needed by items in the queue.
+
+	reagent = {
+		["name"] = "<name of item>",
+		["icon"] = "<icon path>",
+		["amount"] = <amount>,
+		["tradeskill"] = "<tradeskill that caused this reagent to be listed>",
+		["link"] = "<link>",
+	};
+--]]
+
+function CauldronQueue:NewQueue()
+	local queue = {
+		["main"] = {},
+		["intermediate"] = {},
+		["reagents"] = {},
+	};
+
+	return queue;
+end
+
+function CauldronQueue:NewItem(name, icon, amount, priority, tradeskill, link)
+
+	local queueItem = {
+		["name"] = name or "",
+		["icon"] = icon or "",
+		["tradeskill"] = tradeskill or "",
+		["link"] = link,
+		["amount"] = amount or 1,
+		["priority"] = priority or 0,
+	};
+
+	return queueItem;
+end
+
+function CauldronQueue:NewReagent(name, icon, amount, tradeskill, link)
+
+	local reagent = {
+		["name"] = name or "",
+		["icon"] = icon or "",
+		["amount"] = amount or 1,
+		["tradeskill"] = tradeskill,
+		["link"] = link,
+	};
+
+	return reagent;
+end
+
+function CauldronQueue:GetItems(queue)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return nil;
+	end
+
+	local items = {};
+
+	for _, item in pairs(queue.main) do
+		if item.amount > 0 then
+			table.insert(items, item);
+		end
+	end
+
+	-- sort the list
+	table.sort(items, function(r1, r2) return r2.priority < r1.priority; end);
+
+	return items;
+end
+
+function CauldronQueue:GetIntermediates(queue)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return nil;
+	end
+
+	local items = {};
+
+	for _, item in pairs(queue.intermediate) do
+--		if tradeskill then
+--			if tradeskill == item.tradeskill then
+--				table.insert(items, item);
+--			end
+--		else
+			table.insert(items, item);
+--		end
+	end
+
+	-- sort the list
+--	table.sort(items, function(r1, r2) return r2.priority < r1.priority; end);
+
+	return items;
+end
+
+function CauldronQueue:GetReagents(queue)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return nil;
+	end
+
+	local items = {};
+
+	for _, item in pairs(queue.reagents) do
+--		if tradeskill then
+--			if tradeskill == item.tradeskill then
+--				table.insert(items, item);
+--			end
+--		else
+			table.insert(items, item);
+--		end
+	end
+
+	return items;
+end
+
+function CauldronQueue:AddItem(queue, skillInfo, amount, suppressCalc)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return;
+	end
+
+	if not queue.main then
+		queue.main = {};
+	end
+
+	-- look for the item in the "main" section
+	local item = queue.main[skillInfo.name];
+	if item then
+		-- it's there, so increase the amount
+		item.amount = item.amount + amount;
+	else
+		-- it's not there, so create a new instance
+		queue.main[skillInfo.name] = CauldronQueue:NewItem(skillInfo.name, skillInfo.icon, amount, nil, skillInfo.tradeskill);
+	end
+
+	if not suppressCalc then
+		CauldronQueue:CalculateAllRequiredItems(queue);
+	end
+end
+
+function CauldronQueue:CalculateAllRequiredItems(queue)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return;
+	end
+
+	-- reset the intermediate and reagent lists
+	queue.intermediate = {};
+	queue.reagents = {};
+
+	-- iterate over the queued items
+	for name, queueInfo in pairs(queue.main) do
+		local skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
+		CauldronQueue:CalculateRequiredItems(queue, skillInfo, queueInfo.amount);
+	end
+
+end
+
+function CauldronQueue:CalculateRequiredItems(queue, skillInfo, amount)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return;
+	end
+
+	-- get the intermediates and reagents for the item
+	local intermediates, reagents = Cauldron:GetRequiredItems(skillInfo, amount);
+
+	-- check the intermediate list; if the item is available somewhere (inventory, bank, alt, etc.)
+	-- then move it to the reagent list; otherwise, update the intermediate list in the queue
+
+	-- update the intermediate and reagent lists
+	for i, reagent in ipairs(intermediates) do
+		local count = Cauldron:ReagentCount(reagent.name);
+
+		if count.has >= reagent.numRequired then
+			-- add the item to the reagent list if the character has all the required amount
+			table.insert(reagents, reagent);
+		else
+			local amount = reagent.numRequired;
+
+			-- if the character has some, add that amount to the reagent list
+			if count.has > 0 then
+				-- create a reagent copy of the item
+				local newItem = CopyTable(reagent);
+				newItem.numRequired = count.has;
+
+				table.insert(reagents, newItem);
+
+				-- adjust item count to how many need to be crafted
+				amount = reagent.numRequired - count.has;
+			end
+
+			-- add the remaining amount to the intermediate list
+			if amount > 0 then
+				-- adjust the amount if the item produces more than one per execution
+				local intSkillInfo = Cauldron:GetSkillInfoForItem(reagent.name);
+				if intSkillInfo then
+					if intSkillInfo.minMade > 1 then
+						-- we ignore maxMade, since if it is greater than minMade, then the amount
+						-- produced is variable, so we err on the side of caution and account for
+						-- only ever making the minimum possible; besides, each execution of the
+						-- skill will cause the reagent list to be reassessed, so producing more
+						-- will be handled appropriately
+						amount = math.ceil(amount / intSkillInfo.minMade);
+					end
+				end
+
+				CauldronQueue:AddIntermediate(queue, reagent, amount);
+
+				-- add the intermediate's reagents also
+				CauldronQueue:CalculateRequiredItems(queue, intSkillInfo, amount);
+			end
+		end
+	end
+
+	for i, reagent in ipairs(reagents) do
+		CauldronQueue:AddReagent(queue, reagent, reagent.numRequired, skillInfo.tradeskill);
+	end
+
+end
+
+function CauldronQueue:AddIntermediate(queue, reagent, amount)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return;
+	end
+
+	amount = math.max(0, tonumber(amount) or 0);
+
+	if not queue.intermediate then
+		queue.intermediate = {};
+	end
+
+	-- look for the item in the "intermediate" section
+	local item = queue.intermediate[reagent.name];
+	if item then
+		-- it's there, so increase the amount
+		item.amount = item.amount + amount;
+	else
+		local skillInfo = Cauldron:GetSkillInfoForItem(reagent.name);
+
+		-- it's not there, so create a new instance
+		queue.intermediate[reagent.name] = CauldronQueue:NewItem(reagent.name, reagent.icon, amount, nil, skillInfo.tradeskill);
+	end
+
+end
+
+function CauldronQueue:AddReagent(queue, reagent, amount, tradeskill)
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return;
+	end
+
+	amount = math.max(1, tonumber(amount) or 1);
+
+	if not queue.reagents then
+		queue.reagents = {};
+	end
+
+	-- look for the item in the "reagents" section
+	local item = queue.reagents[reagent.name];
+	if item then
+		-- it's there, so increase the amount
+		item.amount = (tonumber(item.amount) or 0) + amount;
+	else
+		-- it's not there, so create a new instance
+		queue.reagents[reagent.name] = CauldronQueue:NewReagent(reagent.name, reagent.icon, amount, tradeskill);
+	end
+
+end
+
+function CauldronQueue:AdjustItemCount(queue, name, delta)
+
+	-- sanity checks
+	if not queue then
+		Cauldron:warn("CauldronQueue:AdjustItemCount: queue not found!");
+		return;
+	end
+
+	local item = queue.main[name];
+--[[
+	for qName, qInfo in pairs(queue.main) do
+		if name == qInfo.item then
+			item = qInfo;
+			break;
+		end
+	end
+--]]
+	Cauldron:debug("AdjustItemCount: item="..tostring(item));
+	if item then
+		Cauldron:debug("AdjustItemCount: item.amount="..item.amount);
+		item.amount = item.amount + delta;
+		Cauldron:debug("AdjustItemCount: item.amount(delta)="..item.amount);
+
+		if item.amount < 1 then
+			Cauldron:debug("AdjustItemCount: remove item: "..name);
+			queue.main[name] = nil;
+		end
+	end
+
+	Cauldron:debug("AdjustItemCount: calculate required items");
+	CauldronQueue:CalculateAllRequiredItems(queue);
+
+end
+
+function CauldronQueue:RemoveItem(queue, itemName)
+	Cauldron:debug("RemoveItem enter");
+
+	-- sanity checks
+	if (not queue) and (not itemName) then
+		-- TODO: display error
+		return;
+	end
+
+	if queue.main[itemName] then
+		queue.main[itemName] = nil;
+
+		CauldronQueue:CalculateAllRequiredItems(queue);
+	end
+
+	Cauldron:debug("RemoveItem exit");
+end
+
+function CauldronQueue:IncreasePriority(queue, itemName, top)
+	Cauldron:debug("IncreasePriority enter");
+
+	-- sanity checks
+	if (not queue) and (not itemName) then
+		-- TODO: display error
+		return;
+	end
+
+	local item = queue.main[itemName];
+	if item then
+		local priority = item.priority + 1;
+		local highest = 0;
+
+		if top then
+			for _, info in pairs(queue.main) do
+				if info.priority > highest then
+					highest = info.priority;
+				end
+			end
+
+			priority = highest + 1;
+		end
+
+		item.priority = priority;
+	end
+
+	Cauldron:debug("IncreasePriority exit");
+end
+
+function CauldronQueue:DecreasePriority(queue, itemName, bottom)
+	Cauldron:debug("DecreasePriority enter");
+
+	-- sanity checks
+	if (not queue) and (not itemName) then
+		-- TODO: display error
+		return;
+	end
+
+	local item = queue.main[itemName];
+	if item then
+		local priority = item.priority - 1;
+		local lowest = 0;
+
+		if top then
+			for _, info in pairs(queue.main) do
+				if info.priority < lowest then
+					lowest = info.priority;
+				end
+			end
+
+			priority = lowest - 1;
+		end
+
+		item.priority = priority;
+	end
+
+	Cauldron:debug("DecreasePriority exit");
+end
+
+function CauldronQueue:ClearQueue(queue)
+	Cauldron:debug("ClearQueue enter");
+
+	-- sanity checks
+	if not queue then
+		-- TODO: display error
+		return;
+	end
+
+	--[[
+	if tradeskill then
+		Cauldron:debug("ClearQueue: clearing tradeskill: "..tradeskill);
+
+		-- set aside the current main queue
+		Cauldron:debug("ClearQueue: set aside main table");
+		local main = queue.main;
+
+		-- clear out the tables
+		Cauldron:debug("ClearQueue: clear out tables");
+		queue.main = {};
+
+		-- iterate over the items and re-add the ones not for the specified tradeskill
+		Cauldron:debug("ClearQueue: iterate over items");
+		for i, item in ipairs(main) do
+			Cauldron:debug("ClearQueue: item: "..i);
+			if item.tradeskill ~= tradeskill then
+				-- get the skill for the item
+				Cauldron:debug("ClearQueue: item.tradeskill: "..item.tradeskill);
+				local skillInfo = Cauldron:GetSkillInfo(item.tradeskill, item.name);
+
+				-- recalculate
+				Cauldron:debug("ClearQueue: recalculate");
+				CauldronQueue:AddItem(queue, skillInfo, item.amount, true);
+			end
+		end
+
+		CauldronQueue:CalculateAllRequiredItems(queue);
+	else
+	--]]
+
+	queue.main = {};
+	queue.intermediate = {};
+	queue.reagents = {};
+
+	Cauldron:debug("ClearQueue exit");
+end
+
+
diff --git a/CauldronShoppingList.lua b/CauldronShoppingList.lua
new file mode 100644
index 0000000..50299c8
--- /dev/null
+++ b/CauldronShoppingList.lua
@@ -0,0 +1,145 @@
+-- $Revision$
+-- Cauldron shopping list functions
+
+CauldronShopping = {};
+
+--[[
+	list = {
+		["<requestor>"] = {
+			["<item name>"] = <quantity>,
+			["<item name>"] = <quantity>,
+			...
+		},
+		["<requestor>"] = {
+			...
+		},
+	};
+--]]
+
+function CauldronShopping:NewList()
+
+	local list = {};
+
+	return list;
+end
+
+function CauldronShopping:AddToList(list, requestor, itemName, quantity)
+
+	-- sanity checks
+	if (not list) and (not requestor) and (not itemName) then
+		-- TODO: display error
+		return;
+	end
+
+	quantity = math.max(1, tonumber(quantity) or 1);
+
+	if not list[requestor] then
+		-- initialize the list for the requestor
+		list[requestor] = {};
+	end
+
+	if list[requestor][itemName] then
+		list[requestor][itemName] = list[requestor][itemName] + quantity;
+	else
+		list[requestor][itemName] = quantity;
+	end
+
+end
+
+function CauldronShopping:RemoveFromList(list, requestor, itemName, quantity)
+	-- sanity checks
+	if not list then
+		-- TODO: display error
+		return;
+	end
+
+	if not list[requestor] then
+		-- initialize the list for the requestor
+		list[requestor] = {};
+	end
+
+	if list[requestor][itemName] then
+		if quantity then
+			list[requestor][itemName] = list[requestor][itemName] - quantity;
+			if list[requestor][itemName] < 1 then
+				list[requestor][itemName] = nil;
+			end
+		else
+			list[requestor][itemName] = nil;
+		end
+	end
+end
+
+function CauldronShopping:GetRequestors(list)
+
+	if not list then
+		-- TODO: display error
+		return;
+	end
+
+	local requestors = {};
+
+	for name, _ in pairs(list) do
+		table.insert(requestors, name);
+	end
+
+	return requestors;
+end
+
+function CauldronShopping:ContainsItems(list)
+
+	if not list then
+		Cauldron:warn("CauldronShopping:ContainsItems: missing list!");
+		return false;
+	end
+
+	for _, items in pairs(list) do
+		for _, amount in pairs(items) do
+			if amount > 0 then
+				return true;
+			end
+		end
+	end
+
+	return false;
+end
+
+function CauldronShopping:HasItems(list, requestor)
+
+	if not list then
+		Cauldron:warn("CauldronShopping:HasItems: missing list!");
+		return false;
+	end
+
+	if list[requestor] then
+		for _, amount in pairs(list[requestor]) do
+			if amount > 0 then
+				return true;
+			end
+		end
+	end
+
+	return false;
+end
+
+function CauldronShopping:GetRequestedItems(list, requestor)
+end
+
+function CauldronShopping:EmptyShoppingList(list, requestor)
+
+	if not list then
+		Cauldron:warn("CauldronShopping:EmptyShoppingList: missing list!");
+		return;
+	end
+
+	for r, _ in pairs(list) do
+		if requestor then
+			if requestor == r then
+				list[r] = nil;
+			end
+		else
+			list[r] = nil;
+		end
+	end
+
+end
diff --git a/CauldronShoppingList.xml b/CauldronShoppingList.xml
new file mode 100644
index 0000000..e17dc5f
--- /dev/null
+++ b/CauldronShoppingList.xml
@@ -0,0 +1,232 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\..\FrameXML\UI.xsd">
+    <!-- $Revision$ -->
+
+    <!-- templates -->
+    <Frame name="CauldronShoppingListRequestorTemplate" virtual="true">
+    	<Size x="240" y="12" />
+    	<Layers>
+			<Layer level="OVERLAY">
+				<FontString name="$parentName" inherits="GameFontNormal"
+							text="(name)" justifyH="LEFT" justifyV="CENTER">
+					<Size x="240" y="12"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="0" y="0"/>
+						</Anchor>
+					</Anchors>
+				</FontString>
+			</Layer>
+    	</Layers>
+    </Frame>
+
+    <Frame name="CauldronShoppingListItemTemplate" virtual="true">
+    	<Size x="240" y="12" />
+    	<Layers>
+			<Layer level="OVERLAY">
+				<FontString name="$parentItem" inherits="GameFontNormal"
+							text="(item)" justifyH="LEFT" justifyV="CENTER">
+					<Size x="225" y="12"/>
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset x="10" y="0"/>
+						</Anchor>
+					</Anchors>
+					<Color r="1.0" g="1.0" b="1.0" />
+				</FontString>
+			</Layer>
+    	</Layers>
+    	<Frames>
+            <Button name="$parentCloseButton" inherits="UIPanelCloseButton">
+                <Anchors>
+                    <Anchor point="RIGHT">
+                        <Offset>
+                            <AbsDimension x="0" y="0"/>
+                        </Offset>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                	<OnLoad>
+                		self:SetScale(0.6);
+                	</OnLoad>
+					<OnEnter>
+						GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+						GameTooltip:ClearLines();
+						GameTooltip:AddLine(Cauldron:LocaleString("Remove this item from the shopping list"));
+						GameTooltip:Show();
+						CursorUpdate(self);
+					</OnEnter>
+					<OnLeave>
+						GameTooltip:Hide();
+						ResetCursor();
+					</OnLeave>
+                    <OnClick>
+                        Cauldron:RemoveShoppingListItem(self:GetParent().requestor, self:GetParent().itemName);
+                        Cauldron:UpdateShoppingList();
+                    </OnClick>
+                </Scripts>
+            </Button>
+    	</Frames>
+    </Frame>
+
+	<!-- main window -->
+	<Frame name="CauldronShoppingListFrame" toplevel="true"
+		   frameStrata="LOW" parent="UIParent"
+		   movable="true" resizable="true" enableMouse="true" hidden="true">
+		<Size x="250" y="300" />
+
+		<ResizeBounds>
+			<minResize>
+				<AbsDimension x="75" y="75"/>
+			</minResize>
+			<maxResize>
+				<AbsDimension x="400" y="900"/>
+			</maxResize>
+		</ResizeBounds>
+		<Anchors>
+			<Anchor point="TOPRIGHT" relativeTo="UIParent" relativePoint="TOPRIGHT">
+				<Offset>
+					<AbsDimension x="-50" y="-200" />
+				</Offset>
+			</Anchor>
+		</Anchors>
+		<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background"
+				  edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="false">
+			<BackgroundInsets>
+				<AbsInset left="0" right="0" top="0" bottom="0" />
+			</BackgroundInsets>
+			<EdgeSize>
+				<AbsValue val="2" />
+			</EdgeSize>
+		</Backdrop>
+
+		<!-- Window Title -->
+		<Layers>
+			<Layer level="BORDER">
+				<FontString name="$parentTitleText" inherits="GameFontNormal" text="Shopping List">
+					<Anchors>
+						<Anchor point="TOP" relativeTo="CauldronShoppingListFrame" relativePoint="TOP">
+							<Offset>
+								<AbsDimension x="0" y="-4"/>
+							</Offset>
+						</Anchor>
+					</Anchors>
+				</FontString>
+			</Layer>
+		</Layers>
+
+		<Frames>
+            <!-- Close button -->
+            <Button name="$parentCloseButton" inherits="UIPanelCloseButton">
+                <Anchors>
+                    <Anchor point="TOPRIGHT">
+                        <Offset>
+                            <AbsDimension x="0" y="0"/>
+                        </Offset>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                	<OnLoad>
+                		self:SetScale(0.75);
+                	</OnLoad>
+                    <OnClick>
+                        Cauldron:HideShoppingList();
+                    </OnClick>
+                </Scripts>
+            </Button>
+            <ScrollFrame name="$parentItemsScrollFrame">
+            	<Size x="240" y="280" />
+            	<Anchors>
+            		<Anchor point="TOPLEFT">
+            			<Offset>
+            				<AbsDimension x="5" y="-20" />
+            			</Offset>
+            		</Anchor>
+            		<Anchor point="BOTTOMRIGHT">
+            			<Offset>
+            				<AbsDimension x="-5" y="5" />
+            			</Offset>
+            		</Anchor>
+            	</Anchors>
+            	<ScrollChild>
+            		<Frame name="$parentScrollChild">
+						<Size x="240" y="280" />
+						<Anchors>
+							<Anchor point="TOPLEFT">
+								<Offset x="0" y="0"/>
+							</Anchor>
+						</Anchors>
+            		</Frame>
+            	</ScrollChild>
+            </ScrollFrame>
+			<Button name="$parentResizeCorner">
+				<Size x="16" y="16"/>
+				<Anchors>
+					<Anchor point="BOTTOMRIGHT">
+						<Offset x="-3" y="3"/>
+					</Anchor>
+				</Anchors>
+				<Scripts>
+					<OnMouseDown>
+						if button == "LeftButton" then
+							self:GetParent():StartSizing();
+							self:GetParent().isResizing = true;
+						end
+					</OnMouseDown>
+					<OnLoad>
+						self:GetNormalTexture():SetVertexColor(0.6, 0.6, 0.6);
+					</OnLoad>
+					<OnMouseUp>
+						if button == "LeftButton" then
+							self:GetParent():StopMovingOrSizing();
+							self:GetParent().isResizing = false;
+							Cauldron:UpdateShoppingList();
+						end
+					</OnMouseUp>
+					<OnHide>
+						self:GetParent():StopMovingOrSizing()
+					</OnHide>
+				</Scripts>
+				<NormalTexture file="Interface\AddOns\Cauldron\Artwork\resize"/>
+			</Button>
+		</Frames>
+
+		<Scripts>
+			<OnLoad>
+				self:SetBackdropColor(.05,.05,.05,.8);
+				self:SetBackdropBorderColor(.4,.4,.4,1);
+--				tinsert(UISpecialFrames, self:GetName());
+			</OnLoad>
+			<OnShow>
+				PlaySound("igCharacterInfoOpen");
+			</OnShow>
+			<OnHide>
+				PlaySound("igCharacterInfoClose");
+			</OnHide>
+			<OnMouseWheel>
+				return;
+			</OnMouseWheel>
+			<OnMouseDown>
+				if button == "LeftButton" then
+					self:StartMoving();
+					self.isResizing = true;
+				end
+			</OnMouseDown>
+			<OnMouseUp>
+				if button == "LeftButton" then
+					self:StopMovingOrSizing();
+					self.isResizing = false;
+					Cauldron:UpdateShoppingList();
+					-- TradeskillInfoUI:Frame_Update()
+					-- CauldronShopping:SaveShoppingListFramePosition();
+				end
+			</OnMouseUp>
+			<OnSizeChanged>
+				-- TradeskillInfoUI:Frame_Update()
+			</OnSizeChanged>
+		</Scripts>
+
+	</Frame>
+
+</Ui>
\ No newline at end of file
diff --git a/CauldronShoppingListUI.lua b/CauldronShoppingListUI.lua
new file mode 100644
index 0000000..f30dea5
--- /dev/null
+++ b/CauldronShoppingListUI.lua
@@ -0,0 +1,181 @@
+-- $Revision$
+-- Cauldron shopping list UI functions
+
+function Cauldron:ShoppingList_Toggle()
+
+	if CauldronShoppingListFrame then
+		if CauldronShoppingListFrame:IsShown() then
+			Cauldron:HideShoppingList();
+		else
+			Cauldron:ShowShoppingList();
+		end
+	end
+
+end
+
+function Cauldron:ShowShoppingList()
+
+	if CauldronShoppingListFrame then
+		CauldronShoppingListFrame:Show();
+
+		--[[
+		local s = CauldronShoppingListFrame:GetEffectiveScale();
+
+		if self.db.profile.ShoppingListPositionX and self.db.profile.ShoppingListPositionY then
+			CauldronShoppingListFrame:SetPoint("TOPLEFT",
+											   self.db.profile.ShoppingListPositionX,
+											   self.db.profile.ShoppingListPositionY);
+		end
+
+		if self.db.profile.ShoppingListWidth then
+			CauldronShoppingListFrame:SetWidth(self.db.profile.ShoppingListWidth);
+		end
+		if self.db.profile.ShoppingListHeight then
+			CauldronShoppingListFrame:SetHeight(self.db.profile.ShoppingListHeight);
+		end
+		--]]
+
+		self.db.profile.showShoppingList = true;
+	end
+
+	Cauldron:UpdateShoppingList();
+
+end
+
+function Cauldron:HideShoppingList()
+
+	if CauldronShoppingListFrame then
+		CauldronShoppingListFrame:Hide();
+		self.db.profile.showShoppingList = false;
+	end
+
+end
+
+function Cauldron:UpdateShoppingList()
+
+	if not CauldronShoppingListFrame:IsShown() then
+		return;
+	end
+
+	local list = self.db.realm.shopping;
+
+	local reqIndex = 1;
+	local itemIndex = 1;
+
+	local width = CauldronShoppingListFrame:GetWidth();
+	local height = CauldronShoppingListFrame:GetHeight();
+
+	-- adjust inner frame sizes
+	CauldronShoppingListFrameItemsScrollFrame:SetWidth(width - 10);
+	CauldronShoppingListFrameItemsScrollFrame:SetHeight(height - 20);
+	CauldronShoppingListFrameItemsScrollFrameScrollChild:SetWidth(width - 10);
+
+	local frameAbove = nil;
+
+	-- iterate over the requestors
+	for requestor, items in pairs(list) do
+
+		if CauldronShopping:HasItems(list, requestor) then
+
+			local shoppingListRequestor = _G["CauldronShoppingListRequestor"..reqIndex];
+
+			-- create a frame for the requestor
+			if not shoppingListRequestor then
+				-- create a new frame for the skill information
+				shoppingListRequestor = CreateFrame("Button",
+													"CauldronShoppingListRequestor"..reqIndex,
+													CauldronShoppingListFrameItemsScrollFrameScrollChild,
+													"CauldronShoppingListRequestorTemplate");
+			end
+
+			_G["CauldronShoppingListRequestor"..reqIndex.."Name"]:SetText(requestor);
+			_G["CauldronShoppingListRequestor"..reqIndex.."Name"]:SetWidth(width - 10);
+
+			_G["CauldronShoppingListRequestor"..reqIndex]:SetWidth(width - 10);
+
+			-- place the frame in the scroll view
+			if frameAbove then
+				-- anchor to the frame above
+				self:debug("UpdateShoppingList: anchor frame to top left of frame above");
+				shoppingListRequestor:SetPoint("TOPLEFT", frameAbove, "BOTTOMLEFT", 0, -2);
+			else
+				-- anchor to the parent
+				self:debug("UpdateShoppingList: anchor frame to parent");
+				shoppingListRequestor:SetPoint("TOPLEFT", CauldronShoppingListFrameItemsScrollFrameScrollChild, "TOPLEFT", 0, 0);
+			end
+
+			shoppingListRequestor:Show();
+
+			frameAbove = shoppingListRequestor;
+
+			-- add items for the requestor
+			for item, amount in pairs(items) do
+
+				local shoppingListItem = _G["CauldronShoppingListItem"..itemIndex];
+
+				-- create a frame for the item
+				if not shoppingListItem then
+					-- create a new frame for the skill information
+					shoppingListItem = CreateFrame("Button",
+												   "CauldronShoppingListItem"..itemIndex,
+												   CauldronShoppingListFrameItemsScrollFrameScrollChild,
+												   "CauldronShoppingListItemTemplate");
+				end
+
+				local str = string.format("%s, %d", item, amount);
+
+				shoppingListItem.itemName = item;
+				shoppingListItem.requestor = requestor;
+
+				_G["CauldronShoppingListItem"..itemIndex.."Item"]:SetText(str);
+				_G["CauldronShoppingListItem"..itemIndex.."Item"]:SetWidth(width - 25);
+
+				_G["CauldronShoppingListItem"..itemIndex]:SetWidth(width - 25);
+
+				-- place the frame in the scroll view
+				if frameAbove then
+					-- anchor to the frame above
+					self:debug("UpdateShoppingList: anchor frame to top left of frame above");
+					shoppingListItem:SetPoint("TOPLEFT", frameAbove, "BOTTOMLEFT", 0, 0);
+				end
+
+				shoppingListItem:Show();
+
+				frameAbove = shoppingListItem;
+
+				itemIndex = itemIndex + 1;
+
+			end
+
+			reqIndex = reqIndex + 1;
+
+		end
+	end
+
+	-- set scroll child frame height
+	CauldronShoppingListFrameItemsScrollFrameScrollChild:SetHeight((reqIndex - 1) * 12 + (itemIndex - 1) * 12);
+
+	while true do
+		local frame = _G["CauldronShoppingListRequestor"..reqIndex];
+		if not frame then
+			break;
+		end
+
+		frame:Hide();
+		frame:SetHeight(0);
+
+		reqIndex = reqIndex + 1;
+	end
+	while true do
+		local frame = _G["CauldronShoppingListItem"..itemIndex];
+		if not frame then
+			break;
+		end
+
+		frame:Hide();
+		frame:SetHeight(0);
+
+		itemIndex = itemIndex + 1;
+	end
+
+end
diff --git a/CauldronTradeskill.lua b/CauldronTradeskill.lua
new file mode 100644
index 0000000..82065dd
--- /dev/null
+++ b/CauldronTradeskill.lua
@@ -0,0 +1,436 @@
+-- $Revision$
+-- Cauldron tradeskill functions
+
+function Cauldron:UpdateSkills()
+	self:debug("UpdateSkills enter");
+
+	local skillName = GetTradeSkillLine();
+	local baseSkillName = skillName;
+	self:debug("UpdateSkills: skillName="..skillName);
+
+	if skillName == "UNKNOWN" then
+		return;
+	end
+
+	if IsTradeSkillLinked() then
+		skillName = "Linked-"..skillName;
+	end
+
+	-- initialize the trade skill entry
+	if not self.db.realm.userdata[self.vars.playername].skills[skillName] then
+		self.db.realm.userdata[self.vars.playername].skills[skillName] = {};
+	end
+
+	-- save the skill entry in a local var
+	local skillDB = self.db.realm.userdata[self.vars.playername].skills[skillName];
+	skillDB.recipes = {};
+
+	-- initialize window information, if necessary
+	if not skillDB.window then
+		skillDB.window = {
+			search = "",
+			filter = {
+				optimal = true,
+				medium = true,
+				easy = true,
+				trivial = true,
+				haveAllReagents = false,
+				haveKeyReagents = false,
+				haveAnyReagents = false,
+				sortDifficulty = true,
+				sortAlpha = false,
+				sortBenefit = false,
+				favorites = false,
+			},
+			skills = {},
+			slots = {},
+			categories = {},
+			selected = 1,
+		};
+	end
+
+	-- make sure we're getting a full list
+	SetTradeSkillItemNameFilter(nil);
+	SetTradeSkillItemLevelFilter(0, 0);
+
+	local category = "";
+
+	for i=1,GetNumTradeSkills() do
+		local name, difficulty, avail, expanded, verb = GetTradeSkillInfo(i);
+--		self:debug("UpdateSkills: name="..name.."; difficulty="..difficulty.."; avail="..avail);
+
+		if name and difficulty ~= "header" then
+			local link = GetTradeSkillItemLink(i);
+			local minMade, maxMade = GetTradeSkillNumMade(i);
+			local _, _, _, _, _, _, _, _, slot, _ = GetItemInfo(link);
+
+			local keywords = name;
+
+			-- fill in the db entry
+			skillDB.recipes[name] = {
+				['index'] = i,
+				['name'] = name,
+				['link'] = link,
+				['icon'] = GetTradeSkillIcon(i),
+				['tradeskill'] = baseSkillName,
+				['difficulty'] = difficulty,
+				['available'] = avail,
+				['minMade'] = minMade,
+				['maxMade'] = maxMade,
+
+				-- filter information
+				['slot'] = slot,
+				['defaultCategory'] = category,
+			};
+
+			-- set the action verb for this skill
+			skillDB.recipes[name].verb = verb;
+
+			-- make sure the skill window info is initialized
+			if not skillDB.window.skills[name] then
+				skillDB.window.skills[name] = {
+					['expanded'] = false,
+					['favorite'] = false,
+				};
+			end
+
+			-- make sure the category for the window is initialized
+			if category ~= "" then
+				if not skillDB.window.categories[category] then
+					skillDB.window.categories[category] = {
+						['shown'] = true,
+						['expanded'] = true,
+					};
+				end
+			end
+
+			-- populate the slot list
+			if slot and (slot ~= "") then
+				if not skillDB.window.slots[slot] then
+					skillDB.window.slots[slot] = true;
+				end
+			end
+
+			-- clear the reagent list
+			skillDB.recipes[name].reagents = {};
+
+			for j=1,GetTradeSkillNumReagents(i) do
+				local rname, rtex, rcount, hasCount = GetTradeSkillReagentInfo(i,j);
+				self:debug("UpdateSkills: rname="..tostring(rname).."; rtex="..tostring(rtex).."; rcount="..tostring(rcount).."; hasCount="..tostring(hasCount));
+
+				if rname then
+					table.insert(skillDB.recipes[name].reagents, {
+						['name'] = rname,
+						['icon'] = rtex,
+						['numRequired'] = rcount,
+						['toonHas'] = hasCount,
+						['index'] = j,
+						['skillIndex'] = i,
+					});
+
+					keywords = keywords..","..rname;
+				end
+			end
+
+			-- fill in the db entry
+			skillDB.recipes[name].keywords = keywords;
+	    else
+	    	-- save the header name
+	    	if name then
+		    	category = name;
+
+				-- expand the header, so we get all the skills
+				if not expanded then
+					ExpandTradeSkillSubClass(i);
+				end
+			end
+		end
+	end
+
+	self:debug("UpdateSkills exit");
+end
+
+function Cauldron:GetDefaultCategories(player, skillName)
+	self:debug("GetDefaultCategories enter");
+
+	local categories = {};
+
+	if self.db then
+		for name, info in pairs(self.db.realm.userdata[player].skills[skillName].window.categories) do
+			categories[name] = info.shown;
+		end
+	end
+
+--	table.sort(categories);
+
+	self:debug("GetDefaultCategories exit");
+
+	return categories;
+end
+
+--[[
+function Cauldron:GetCategories(skillList)
+	self:debug("GetCategories enter");
+
+	local categories = {};
+
+	if not skillList then
+		return categories;
+	end
+
+	for _, info in ipairs(skillList) do
+		table.insert(categories, info.defaultCategory);
+	end
+
+	table.sort(categories);
+
+	self:debug("GetCategories exit");
+
+	return categories;
+end
+--]]
+
+function Cauldron:GetSlots(player, skillName)
+	self:debug("GetSlots enter");
+
+	local slots = {};
+
+	if self.db then
+		for name, info in pairs(self.db.realm.userdata[player].skills[skillName].window.slots) do
+			slots[name] = info;
+		end
+	end
+
+--	table.sort(slots);
+
+	self:debug("GetSlots exit");
+
+	return slots;
+end
+
+function Cauldron:GetSkillList(playername, skillName)
+	self:debug("GetSkillList enter");
+
+	if (not playername) or (not skillName) then
+		self:warn("GetSkillList: playername ("..tostring(playername)..") or skillName ("..tostring(skillName)..") not set!");
+		return;
+	end
+
+	local skills = {};
+
+	for name, recipe in pairs(self.db.realm.userdata[playername].skills[skillName].recipes) do
+		self:debug("GetSkillList: name="..name);
+
+		local add = true;
+
+		-- check the search text
+		local search = self.db.realm.userdata[playername].skills[skillName].window.search or "";
+		self:debug("GetSkillList: search="..search);
+		if #search > 0 then
+			-- check for numbers
+			local minLevel, maxLevel;
+			local approxLevel = strmatch(search, "^~(%d+)");
+			-- self:debug("GetSkillList: approxLevel="..tostring(approxLevel));
+			if ( approxLevel ) then
+				minLevel = approxLevel - 2;
+				maxLevel = approxLevel + 2;
+			else
+				minLevel, maxLevel = strmatch(search, "^(%d+)%s*-*%s*(%d*)$");
+				-- self:debug("GetSkillList: minLevel="..tostring(minLevel).."; maxLevel="..tostring(maxLevel));
+			end
+			if ( minLevel ) then
+				if ( maxLevel == "" or maxLevel < minLevel ) then
+					maxLevel = minLevel;
+				end
+
+				-- TODO
+				-- self:debug("GetSkillList: TODO; filter by level");
+--				SetTradeSkillItemNameFilter(nil);
+--				SetTradeSkillItemLevelFilter(minLevel, maxLevel);
+			else
+				-- match name or reagents
+				self:debug("GetSkillList: match by name or reagents");
+				if not string.find(string.lower(recipe.keywords), string.lower(search)) then
+					self:debug("skipping recipe: "..name.." (keywords: "..recipe.keywords..")");
+					add = false;
+				end
+			end
+
+		end
+
+		-- check difficulty filter
+		if not self.db.realm.userdata[playername].skills[skillName].window.filter[recipe.difficulty] then
+			self:debug("skipping recipe: "..name.." (difficulty: "..recipe.difficulty..")");
+			add = false;
+		end
+
+		-- check categories
+		local catInfo = self.db.realm.userdata[playername].skills[skillName].window.categories[recipe.defaultCategory];
+		if catInfo and (not catInfo.shown) then
+			self:debug("skipping recipe: "..name.." (category: "..recipe.defaultCategory..")");
+			add = false;
+		end
+
+		-- check slot
+		--[[
+		local slotName = recipe.slot;
+		if slotName == "" then
+			slotName = "(none)";
+		end
+		local slotInfo = self.db.realm.userdata[playername].skills[skillName].window.slots[slotName];
+		self:debug("slotInfo: "..tostring(slotInfo));
+		if not slotInfo then -- more
+			self:debug("skipping recipe: "..name.." (slot: "..slotName..")");
+			add = false;
+		end
+		--]]
+
+		-- check reagent filter
+		if self.db.realm.userdata[playername].skills[skillName].window.filter.haveAllReagents then
+			-- check if the available count is 0
+			if recipe.available == 0 then
+				add = false;
+			end
+		elseif self.db.realm.userdata[playername].skills[skillName].window.filter.haveKeyReagents then
+			-- check if the reagent count for key reagents is 0
+		elseif self.db.realm.userdata[playername].skills[skillName].window.filter.haveAnyReagents then
+			-- check if the reagent count for any reagent is 0
+			for rname, rinfo in pairs(recipe.reagents) do
+				-- check possession count
+				if rinfo.toonHas == 0 then
+--					if Cauldron:GetAltReagentCount(rinfo) == 0 then
+						add = false;
+--					end
+				end
+			end
+		end
+
+		-- check favorites filter
+		if self.db.realm.userdata[playername].skills[skillName].window.filter.favorites then
+			if not self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].favorite then
+				self:debug("skipping recipe: "..name.." (favorite: "..tostring(self.db.realm.userdata[playername].skills[skillName].window.skills[recipe.name].favorite)..")");
+				add = false;
+			end
+		end
+
+		-- we got here, add the recipe to the list
+		if add then
+			table.insert(skills, recipe);
+		end
+	end
+
+	-- sort the list
+	table.sort(skills, function(r1, r2)
+			if (not r1) or (not r2) then
+				return true;
+			end
+
+			self:debug("GetSkillList: sorting: r1.name="..r1.name.."; r2.name="..r2.name);
+			if self.db.realm.userdata[playername].skills[skillName].window.filter.sortAlpha then
+				self:debug("GetSkillList: sorting by alpha");
+				return r1.name < r2.name;
+			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortDifficulty then
+				self:debug("GetSkillList: sorting by difficulty");
+				local difficulty = {
+					optimal = 4,
+					medium = 3,
+					easy = 2,
+					trivial = 1,
+				};
+
+				self:debug("GetSkillList: r1.difficulty="..r1.difficulty);
+				self:debug("GetSkillList: r2.difficulty="..r2.difficulty);
+				return difficulty[r1.difficulty] > difficulty[r2.difficulty];
+			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortBenefit then
+				self:debug("GetSkillList: returning true for benefit sorting");
+				return true; -- TODO
+			end
+
+			self:debug("GetSkillList: returning default true");
+			return true;
+		end);
+
+	self:debug("GetSkillList exit");
+
+	return skills;
+end
+
+function Cauldron:GetSkillInfo(tradeskill, skill)
+	self:debug("GetSkillInfo enter");
+
+	-- sanity checks
+	if (not tradeskill) or (not skill) then
+		self:warn("GetSkillInfo: missing tradeskill ("..tostring(tradeskill)..") or skill ("..tostring(skill)..")!");
+		return nil;
+	end
+
+	if not self.db.realm.userdata[self.vars.playername].skills[tradeskill] then
+		return nil;
+	end
+
+	local skillInfo = self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes[skill];
+	if not skillInfo then
+		-- couldn't find a skill with the item name, so scan the list for skills that craft
+		-- the item
+		for _, recipe in pairs(self.db.realm.userdata[self.vars.playername].skills[tradeskill].recipes) do
+			local name, _ = GetItemInfo(recipe.link);
+			if name == skill then
+				return recipe;
+			end
+		end
+	end
+
+	self:debug("GetSkillInfo exit");
+
+	return skillInfo;
+end
+
+function Cauldron:GetSkillInfoForItem(item)
+
+	for tradeskill, list in pairs(self.db.realm.userdata[self.vars.playername].skills) do
+		-- skip linked skills
+		if not (string.find(tradeskill, "Linked-")) then
+			for _, recipeInfo in pairs(list.recipes) do
+				local name, _ = GetItemInfo(recipeInfo.link);
+				if name == item then
+					return recipeInfo;
+				end
+			end
+		end
+	end
+
+	return nil;
+end
+
+function Cauldron:GetRequiredItems(skillInfo, amount)
+
+	local intermediates = {};
+	local reagents = {};
+
+	-- sanity checks
+	if not skillInfo then
+		-- TODO: display error
+		return intermediates, reagents;
+	end
+
+	amount = math.max(1, tonumber(amount) or 1);
+
+	-- find out what the reagents are
+	for i, reagent in ipairs(skillInfo.reagents) do
+
+		-- copy the reagent info so we can modify the amounts
+		local r = CopyTable(reagent);
+		r.numRequired = r.numRequired * amount;
+
+		-- see if the character can make the item
+		local si = Cauldron:GetSkillInfoForItem(r.name);
+		if si then
+			table.insert(intermediates, r);
+		else
+			table.insert(reagents, r);
+		end
+	end
+
+	return intermediates, reagents;
+end
+
diff --git a/CauldronUtil.lua b/CauldronUtil.lua
new file mode 100644
index 0000000..ab6aaf4
--- /dev/null
+++ b/CauldronUtil.lua
@@ -0,0 +1,84 @@
+-- $Revision$
+-- Cauldron utility functions
+
+function Cauldron:GetAltReagentCount(reagentInfo)
+	self:debug("GetAltReagentCount enter");
+
+	-- TODO
+
+	self:debug("GetAltReagentCount exit");
+end
+
+function Cauldron:GetPotentialCraftCount(skill)
+	self:debug("GetPotentialCraftCount enter");
+
+	local count = 0;
+
+	-- TODO
+
+	self:debug("GetPotentialCraftCount exit");
+
+	return count;
+end
+
+function Cauldron:ReagentCount(reagent)
+
+	local count = {
+		has = 0,
+		bank = 0,
+		guildBank = 0,
+		mail = 0,
+		altHas = {},
+	}
+
+	-- sanity checks
+	if not reagent then
+		-- TODO: display error
+		return count;
+	end
+
+	count.has = GetItemCount(reagent, false);
+
+
+	-- TODO: find in banks, on alts, etc.
+	if BankItems_SelfCache then
+		-- TODO
+		count.bank = BankItems_SelfCache[reagent].bank;
+		count.mail = BankItems_SelfCache[reagent].mail;
+	end
+
+	if BankItems_GuildCache then
+--		count.guildBank = BankItems_GuildCache[reagent].
+	end
+
+
+	return count;
+end
+
+function Cauldron:ScanForItem(name)
+	-- look through bags
+
+end
+
+function Cauldron:SkillContainsText(recipe, text)
+
+	-- sanity checks
+	if (not recipe) or (not text) then
+		-- TODO: display error
+		return false;
+	end
+
+	if string.find(recipe.name, text) then
+		return true;
+	end
+
+	for i, reagent in ipairs(recipe.reagents) do
+		if string.find(reagent.name, text) then
+			return true;
+		end
+	end
+
+	-- TODO: check flavor text?
+
+	return false;
+end
diff --git a/Locale/Cauldron-enUS.lua b/Locale/Cauldron-enUS.lua
new file mode 100644
index 0000000..e2b80df
--- /dev/null
+++ b/Locale/Cauldron-enUS.lua
@@ -0,0 +1,104 @@
+-- $Revision: 1.3 $
+-- Cauldron language file: enUS
+
+local L = LibStub("AceLocale-3.0"):NewLocale("Cauldron", "enUS", true)
+if not L then return end
+
+--
+L["Cauldron"] = true
+L["Cauldron loaded; version "] = true
+L["Version "] = true
+L["Current log level: "] = true
+L["Setting log level: "] = true
+L["Config"] = true
+L["Show config screen"] = true
+L["Log level"] = true
+L["Change Cauldron logging level"] = true
+L["Menu"] = true
+L["Show Cauldron UI"] = true
+L["Shopping list"] = true
+L["Open shopping list window"] = true
+L["Reset"] = true
+L["Resets Cauldron to a fresh state"] = true
+
+L["Player known"] = true
+L["Player can learn"] = true
+L["Player will be able to learn"] = true
+L["Alt known"] = true
+L["Alt can learn"] = true
+L["Alt will be able to learn"] = true
+L["Unavailable"] = true
+
+L["Neutral"] = true
+L["Alliance"] = true
+L["Horde"] = true
+
+L["Version"] = true
+L["Shows the version number of the addon"] = true
+
+L["Opposing"] = true
+L["Include recipes from opposing faction"] = true
+L["Name"] = true
+L["Search for name"] = true
+L["Reagent"] = true
+L["Search for reagents"] = true
+
+L["Sort"] = true
+L["Alphabetically"] = true
+L["By difficulty"] = true
+L["By benefit"] = true
+L["Set the sorting method to use on the skills list"] = true
+
+L["Filters"] = true
+L["Difficulty"] = true
+L["Optimal"] = true
+L["Medium"] = true
+L["Easy"] = true
+L["Trivial"] = true
+L["Set whether items of this difficulty level should be shown"] = true
+L["Miscellaneous"] = true
+L["Favorites"] = true
+L["Display only favorite skills"] = true
+L["Mark this skill as a favorite"] = true
+L["Reagents"] = true
+L["Display the normal list of skills"] = true
+L["Set whether skills for which you have all the required reagents are shown in the list"] = true
+L["Set whether skills for which you have all key reagents (non-vendor available) are shown in the list"] = true
+L["Set whether skills for which you have any reagents are shown in the list"] = true
+L["Normal"] = true
+L["Have all"] = true
+L["Have key"] = true
+L["Have any"] = true
+
+L["Slots"] = true
+L["All slots"] = true
+L["(None)"] = true
+
+L["Categories"] = true
+L["All categories"] = true
+L["No categories"] = true
+
+L["Requires"] = true
+
+L["In order to make:"] = true
+L["You first have to make:"] = true
+L["You will need:"] = true
+
+L["Have %d"] = true
+L[", need %d"] = true
+
+L["Crafting %1$d of %2$s..."] = true
+
+L["Remove this item from the queue"] = true
+L["Increase the priority of this item"] = true
+L["Shift-click to move to the top of the queue"] = true
+L["Decrease the priority of this item"] = true
+L["Shift-click to move to the bottom of the queue"] = true
+L["Add this item to the shopping list"] = true
+L["Decrease the amount of this item"] = true
+
+L["Remove this item from the shopping list"] = true
+
+-- error messages
+L["Crafting %1$s requires the %2$s skill."] = true
+
diff --git a/embeds.xml b/embeds.xml
new file mode 100644
index 0000000..4efeb90
--- /dev/null
+++ b/embeds.xml
@@ -0,0 +1,26 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd">
+
+	<Script file="Libs\LibStub\LibStub.lua"/>
+
+	<Include file="Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
+	<Include file="Libs\AceAddon-3.0\AceAddon-3.0.xml"/>
+	<Include file="Libs\AceEvent-3.0\AceEvent-3.0.xml"/>
+	<Include file="Libs\AceTimer-3.0\AceTimer-3.0.xml"/>
+	<Include file="Libs\AceHook-3.0\AceHook-3.0.xml"/>
+	<Include file="Libs\AceDB-3.0\AceDB-3.0.xml"/>
+    <Include file="Libs\AceGUI-3.0\AceGUI-3.0.xml"/>
+	<Include file="Libs\AceLocale-3.0\AceLocale-3.0.xml"/>
+	<Include file="Libs\AceConsole-3.0\AceConsole-3.0.xml"/>
+	<Include file="Libs\AceConfig-3.0\AceConfig-3.0.xml"/>
+
+	<!--
+	<Include file="Libs\LibAbacus-3.0\lib.xml"/>
+	-->
+    <Include file="Libs\LibLogger-1.0\lib.xml"/>
+
+	<Script file="Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua"/>
+	<!-- Include file="Libs\LibPeriodicTable-3.1\modules.xml"/ -->
+
+</Ui>
\ No newline at end of file