Quantcast
--[[
************************************************************************
Scanner.lua
Vendor/trainer scanning for Ackis Recipe List.
************************************************************************
File date: @file-date-iso@
File hash: @file-abbreviated-hash@
Project hash: @project-abbreviated-hash@
Project version: @project-version@
************************************************************************
Please see http://www.wowace.com/addons/arl/ for more information.
************************************************************************
This source code is released under All Rights Reserved.
************************************************************************
--- Vendor/trainer scanning for Ackis Recipe List.
@class file
@name Scanner.lua
@release 2.0
************************************************************************
]]--

-------------------------------------------------------------------------------
-- Upvalued Lua API.
-------------------------------------------------------------------------------
local _G = getfenv(0)

-- Functions
local ipairs, pairs = _G.ipairs, _G.pairs
local tonumber, tostring = _G.tonumber, _G.tostring
local type = _G.type

-- Libraries
local bit = _G.bit
local string = _G.string
local table = _G.table

-------------------------------------------------------------------------------
-- AddOn namespace.
-------------------------------------------------------------------------------
local FOLDER_NAME, private = ...

local LibStub = _G.LibStub

local addon = LibStub("AceAddon-3.0"):GetAddon(private.addon_name)
local L = LibStub("AceLocale-3.0"):GetLocale(private.addon_name)

-------------------------------------------------------------------------------
-- Constants
-------------------------------------------------------------------------------
local F = private.filter_flags
local A = private.acquire_types

local NO_ROLE_FLAG	-- Populated at the end of the file.

-------------------------------------------------------------------------------
-- Functions/methods
-------------------------------------------------------------------------------
local function LoadAllRecipes()
	local recipe_list = private.recipe_list

	if addon.db.profile.autoloaddb then
		-- Make sure the lookup lists are loaded as well, since they are no longer automatically loaded in addon:OnEnable().
		if addon.InitializeLookups then
			addon:InitializeLookups()
		end

		for index, prof in pairs(private.professions) do
			addon:InitializeProfession(prof)
		end
	end
	return recipe_list
end

-------------------------------------------------------------------------------
-- Creates a reverse lookup for a recipe list
-------------------------------------------------------------------------------
local GetReverseLookup
do
	local reverse_lookup = {}

	function GetReverseLookup(recipe_list)
		if not recipe_list then
			addon:Print(L["DATAMINER_NODB_ERROR"])
			return
		end
		table.wipe(reverse_lookup)

		for i in pairs(recipe_list) do
			--if t[recipe_list[i].name] then addon:Print("Dupe: " .. i) end
			reverse_lookup[recipe_list[i].name] = i
		end
		return reverse_lookup
	end

end

-------------------------------------------------------------------------------
-- Tooltip for data-mining.
-------------------------------------------------------------------------------
local ARLDatamineTT = _G.CreateFrame("GameTooltip", "ARLDatamineTT", _G.UIParent, "GameTooltipTemplate")

do
	-- Tables used in addon:ScanTrainerData
	local scanned_recipes, scanned_items, output = {}, {}, {}
	local missing_spell_ids, extra_spell_ids, fixed_item_spell_ids = {}, {}, {}
	local mismatched_levels, mismatched_levels_unconfirmed = {}, {}
	local itemless_spells = {}

	--- Function to compare which recipes are available from a trainer and compare with the internal ARL database.
	-- @name AckisRecipeList:ScanTrainerData
	-- @param autoscan True when autoscan is enabled in preferences, it will surpress output letting you know when a scan has occured.
	-- @return Does a comparison of the information in your internal ARL database, and those items which are available on the trainer.
	-- Compares the acquire information of the ARL database with what is available on the trainer.
	function addon:ScanTrainerData(autoscan)
		if not _G.UnitExists("target") or _G.UnitIsPlayer("target") or _G.UnitIsEnemy("player", "target") then
			if not autoscan then
				self:Print(L["DATAMINER_TRAINER_NOTTARGETTED"])
			end
			return
		end

		if not _G.IsTradeskillTrainer() then
			if not autoscan then
				self:Print(L["DATAMINER_SKILLLEVEL_ERROR"])
			end
			return
		end
		local recipe_list = LoadAllRecipes()	-- Get internal database

		if not recipe_list then
			self:Print(L["DATAMINER_NODB_ERROR"])
			return
		end

		-- Get the initial trainer filters
		local avail = _G.GetTrainerServiceTypeFilter("available")
		local unavail = _G.GetTrainerServiceTypeFilter("unavailable")
		local used = _G.GetTrainerServiceTypeFilter("used")

		-- Clear the trainer filters
		_G.SetTrainerServiceTypeFilter("available", 1)
		_G.SetTrainerServiceTypeFilter("unavailable", 1)
		_G.SetTrainerServiceTypeFilter("used", 1)

		if _G.GetNumTrainerServices() == 0 then
			self:Print("Warning: Trainer is bugged, reporting 0 trainer items.")
		end
		table.wipe(scanned_items)
		table.wipe(scanned_recipes)

		local trainer_profession = _G.GetTrainerServiceSkillLine(1)

		for index = 1, _G.GetNumTrainerServices(), 1 do
			local item_name = _G.GetTrainerServiceInfo(index)
			local item_id = private.ItemLinkToID(_G.GetTrainerServiceItemLink(index))
			local _, skill_level = _G.GetTrainerServiceSkillReq(index)

			if not skill_level then
				skill_level = 0
			end

			if item_id then
				scanned_items[item_id] = skill_level
			else
				scanned_recipes[item_name] = skill_level
			end
		end
		table.wipe(missing_spell_ids)
		table.wipe(extra_spell_ids)
		table.wipe(fixed_item_spell_ids)
		table.wipe(mismatched_levels)
		table.wipe(mismatched_levels_unconfirmed)
		table.wipe(output)

		-- Dump out trainer info
		local trainer_id = tonumber(_G.UnitGUID("target"):sub(-12,-9), 16)
		local trainer_name = _G.UnitName("target")

		for spell_id, recipe in pairs(recipe_list) do
			if trainer_profession == recipe.profession then
				local train_data = recipe.acquire_data[A.TRAINER]
				local matching_trainer = false

				if train_data then
					for id_num in pairs(train_data) do
						if id_num == trainer_id then
							matching_trainer = true
							break
						end
					end
				end
				local matching_item = scanned_items[recipe:CraftedItemID()]
				local matching_recipe = scanned_recipes[recipe.name]

				if recipe:CraftedItemID() then
					matching_recipe = nil
				end
				local trainer_entry = private.trainer_list[trainer_id]
				local trainer_x, trainer_y = _G.GetPlayerMapPosition("player")
				trainer_x = ("%.2f"):format(trainer_x * 100)
				trainer_y = ("%.2f"):format(trainer_y * 100)

				if trainer_entry and trainer_entry.coord_x ~= trainer_x or trainer_entry.coord_y ~= trainer_y then
					table.insert(output, ("%s appears to have different coordinates (%s, %s) than those in the database (%s, %s) - a trainer dump for %s will fix this."):format(trainer_name, trainer_entry.coord_x, trainer_entry.coord_y, trainer_x, trainer_y, trainer_profession))
					trainer_entry.coord_x = trainer_x
					trainer_entry.coord_y = trainer_y
				elseif not trainer_entry then
					table.insert(output, ("%s was not found in the trainer list - a trainer dump for %s will fix this."):format(trainer_name, trainer_profession))
					_G.SetMapToCurrentZone() -- Make sure were are looking at the right zone

					private:AddTrainer(trainer_id, trainer_name, _G.GetRealZoneText(), trainer_x, trainer_y, private.Player.faction)
				end

				if matching_item or matching_recipe then
					if not matching_trainer then
						table.insert(missing_spell_ids, spell_id)

						recipe:AddTrainer(trainer_id)

						if not recipe:HasFilter("common1", "TRAINER") then
							recipe:AddFilters(F.TRAINER)

							if matching_item then
								table.insert(output, ("Added trainer flag to recipe with spell ID %d. (matching crafted item ID %d)"):format(spell_id, recipe:CraftedItemID()))
							elseif matching_recipe then
								table.insert(output, ("Added trainer flag to recipe with spell ID %d. (matching recipe name \"%s\")"):format(spell_id, recipe.name))
							end
						end
					end
					local recipe_skill = recipe:SkillLevels()

					if matching_item and matching_item ~= recipe_skill then
						table.insert(mismatched_levels, spell_id)
					elseif matching_recipe and matching_recipe ~= recipe_skill then
						table.insert(mismatched_levels_unconfirmed, spell_id)
					end
				elseif matching_trainer then
					table.wipe(itemless_spells)

					if not recipe:CraftedItemID() then
						for item_id in pairs(scanned_items) do
							if recipe.name == _G.GetItemInfo(item_id) then
								recipe:SetCraftedItemID(item_id)
								itemless_spells[spell_id] = true
							end
						end
					end

					if itemless_spells[spell_id] then
						table.insert(fixed_item_spell_ids, spell_id)
					else
						table.insert(extra_spell_ids, spell_id)
					end
				end
			end
		end
		local found_missing = #missing_spell_ids > 0
		local found_extra = #extra_spell_ids > 0
		local found_fixed_item = #fixed_item_spell_ids > 0
		local found_wrong_level = #mismatched_levels > 0
		local found_unconfirmed_level = #mismatched_levels_unconfirmed > 0

		if found_missing then
			table.insert(output, "\nTrainer is missing from the following entries:")
			table.sort(missing_spell_ids)

			for index in ipairs(missing_spell_ids) do
				local spell_id = missing_spell_ids[index]
				table.insert(output, ("%d (%s)"):format(spell_id, recipe_list[spell_id].name))
			end
		end

		if found_extra then
			table.insert(output, "\nRecipes which are wrongly assigned to the trainer:")
			table.sort(extra_spell_ids)

			for index in ipairs(extra_spell_ids) do
				local spell_id = extra_spell_ids[index]
				local recipe = recipe_list[spell_id]
				local crafted_item = recipe:CraftedItemID()

				if crafted_item then
					table.insert(output, ("%d (%s) - Crafted item ID set to %d (%s)"):format(spell_id, recipe.name, crafted_item, _G.GetItemInfo(crafted_item) or _G.UNKNOWN))
				else
					table.insert(output, ("%d (%s)"):format(spell_id, recipe.name))
				end
			end
		end

		if found_fixed_item then
			table.insert(output, "\nRecipes which had no crafted item ID, but will once a dump is performed:")
			table.sort(fixed_item_spell_ids)

			for index in ipairs(fixed_item_spell_ids) do
				local spell_id = fixed_item_spell_ids[index]
				table.insert(output, ("%d (%s)"):format(spell_id, recipe_list[spell_id].name))
			end
		end

		if found_wrong_level then
			table.insert(output, "\nRecipes which had an incorrect skill level, but will not once a dump is performed:")
			table.sort(mismatched_levels)

			for index in ipairs(mismatched_levels) do
				local spell_id = mismatched_levels[index]
				local recipe = recipe_list[spell_id]
				local recipe_skill = recipe:SkillLevels()
				local corrected_skill = scanned_items[recipe:CraftedItemID()]
				table.insert(output, ("%d (%s): Corrected skill level from %d to %d."):format(spell_id, recipe.name, recipe_skill, corrected_skill))
				recipe:SetSkillLevels(corrected_skill)
			end
		end

		if found_unconfirmed_level then
			table.insert(output, "\nRecipes with possible incorrect skill levels - unable to confirm:")
			table.sort(mismatched_levels_unconfirmed)

			for index in ipairs(mismatched_levels_unconfirmed) do
				local spell_id = mismatched_levels_unconfirmed[index]
				local recipe = recipe_list[spell_id]
				local recipe_skill = recipe:SkillLevels()
				table.insert(output, ("%d (%s): Skill set to %d; trainer reports %d."):format(spell_id, recipe.name, recipe_skill, scanned_recipes[recipe.name]))
			end
		end

		if #output > 0 then
			table.insert(output, 1, ("ARL Version: %s"):format(self.version))
			table.insert(output, 2, L["DATAMINER_TRAINER_INFO"]:format(trainer_name, trainer_id))
			if found_extra and trainer_profession == private.professions.Engineering then
				table.insert(output, "\nSome goggles may be listed as extra. These goggles ONLY show up for the classes who can make them, so they may be false positives.")
			end

			self:DisplayTextDump(nil, nil, table.concat(output, "\n"))
		end
		-- Reset the filters to what they were before
		_G.SetTrainerServiceTypeFilter("available", avail or 0)
		_G.SetTrainerServiceTypeFilter("unavailable", unavail or 0)
		_G.SetTrainerServiceTypeFilter("used", used or 0)
	end
end	-- do

--- Generates tradeskill links for all professions so you can scan them for completeness.
-- @name AckisRecipeList:GenerateLinks
-- @return Generates tradeskill links with all recipes.  Used for testing to see if a recipe is missing from the database or not.
function addon:GenerateLinks()
	-- This code adopted from Gnomish Yellow Pages with permission

	local guid = _G.UnitGUID("player")
	local playerGUID = guid:gsub("0x0+","")

	-- Listing of all tradeskill professions
	local tradelist = {51304, 51300, 51313, 51306, 45363, 51311, 51302, 51309, 51296, 45542}

--[[
	local encodingLength = floor((#recipeList+5) / 6)

	local encodedString = ("/"):rep(encodingLength)
]]--
	local bitmap = {}
	bitmap[45542] = "8bffAA" -- First Aid  100%   17/17 recipes
	--bitmap[51296] = "2/6///7///9f///7//////////g///B" -- Cooking  98.2%  166/169 recipes
	bitmap[51296] = "GEgAGAjmFAwBAxAzfex//DgAgPA6HtgAI8lC"
	--bitmap[51306] = "4/////////////3nFA+///9+/P7//f//n//9dgdJgHA87/3f/TolD" -- Engineering (53)
	bitmap[51306] = "4/////////////3nFA+///9+/P7//f//n//9dgdJgHA87/3f/Tol3B" -- Engineering
	bitmap[51302] = "e+//ff////d//u//v//n+vv7/+ujr7/9////bg/+////f344//dA4I8j/X//B4/vu5/////////////////nvA8/M8/D" -- Leatherworking  85.4%   451/528 recipes
	bitmap[51304] = "2//v//////f////3//v///////5//////////9/////v" -- Alchemy 100%   251/251 recipes
	bitmap[51300] = "2//////f7fM//f/f53/+//7///ze8c6q/f9///P2/////m4BAA2XIG+dFA8//PC////4//z//////////Pwvy//H" -- Blacksmithing 82.9%   413/498 recipes
	bitmap[51309] = "4//+/76J7//v7/ve+/XR9fLb2f3nN3vLc6vS0+Hf8/XG7/VAIh9B+/f6/////3/////9/f1wCB" -- Tailoring   83.37%   341/409 recipes
	bitmap[51311] = "8//3////fzj//u//////v/7///9///33////////Pw////////////////////////3///////////////////////////D" -- Jewelcrafting  97.5%   540/554 recipes
	bitmap[45363] = "g////7////3///////////////////////////////////////////////////f///////////f" --Inscription 99.77%    439/440 recipes
	bitmap[51313] = "4//////////7///////////w//+//9/n7///////3f//////ZsD" -- Enchanting   94.3%    279/296 recipes

	for i in pairs(tradelist) do

		local tradeName = _G.GetSpellInfo(tradelist[i])
		local tradelink = {}
		tradelink[1] = "|cffffd000|Htrade:"
		tradelink[2] = tradelist[i]
		tradelink[3] = ":450:450:"
		tradelink[4] = playerGUID
		tradelink[5] = ":"
		tradelink[6] = bitmap[tradelist[i]]
		tradelink[7] = "|h["
		tradelink[8] = tradeName
		tradelink[9] = "]|h|r"

		if (bitmap[tradelist[i]]) then
			self:Print(table.concat(tradelink, ""))
		else
			self:Print("There currently is not a generated tradeskill link for: " .. tradeName)
		end
--		/script DEFAULT_CHAT_FRAME:AddMessage(GetTradeSkillListLink():gsub("\124","\124\124"))
	end

end

do
	local ORDERED_PROFESSIONS = private.ordered_professions

	local recipe_list = {}
	local output = {}

	local function Sort_AscID(a, b)
		local reca, recb = private.recipe_list[a], private.recipe_list[b]

		return reca.spell_id < recb.spell_id
	end

	local function SortRecipesByID()
		local sorted_recipes = addon.sorted_recipes
		table.wipe(sorted_recipes)

		for n, v in pairs(recipe_list) do
			table.insert(sorted_recipes, n)
		end
		table.sort(sorted_recipes, Sort_AscID)
	end

	-------------------------------------------------------------------------------
	--- Scans the items in the specified profession
	-------------------------------------------------------------------------------
	local function ProfessionScan(prof_name)
		local master_list = LoadAllRecipes()

		if not master_list then
			addon:Print(L["DATAMINER_NODB_ERROR"])
			return
		end
		table.wipe(recipe_list)

		if prof_name == private.professions["Smelting"]:lower() then
			prof_name = private.mining_name:lower()
		end

		for i in pairs(master_list) do
			local prof = master_list[i].profession:lower()

			if prof and prof == prof_name then
				recipe_list[i] = master_list[i]
			end
		end
		SortRecipesByID()
		table.wipe(output)

		-- Parse the entire recipe database
		for index, id in ipairs(addon.sorted_recipes) do
			local ttscantext = addon:TooltipScanRecipe(id, false, true)

			if ttscantext and ttscantext ~= "" then
				table.insert(output, ttscantext)
			end
		end

		if #output == 0 then
			addon:Debug("ProfessionScan(): output is empty.")
		end
		addon:DisplayTextDump(nil, nil, table.concat(output, "\n"))
		ARLDatamineTT:Hide()
	end

	--- Parses all recipes for a specified profession, scanning their tool tips.
	-- @name AckisRecipeList:ScanProfession
	-- @usage AckisRecipeList:ScanProfession("first aid")
	-- @param prof_name The profession name or the spell ID of it, which you wish to scan.
	-- @return Recipes in the given profession have their tooltips scanned.
	function addon:ScanProfession(prof_name)
		if type(prof_name) == "number" then
			prof_name = _G.GetSpellInfo(prof_name)
		end

		local found = false
		prof_name = prof_name:lower()

		local scan_all = prof_name == "all"

		if not scan_all then
			for idx, name in ipairs(ORDERED_PROFESSIONS) do
				if prof_name == name:lower() then
					found = true
					break
				end
			end

			if not found then
				self:Print(L["DATAMINER_NODB_ERROR"])
				return
			end

			ProfessionScan(prof_name)
		else
			for idx, name in ipairs(ORDERED_PROFESSIONS) do
				ProfessionScan(name:lower())
			end
		end
	end

	local function RecipeDump(id, single)
		local recipe = private.recipe_list[id or 1]

		if single and not recipe then
			addon:Print("Invalid recipe ID.")
			return
		end
		recipe:Dump(output)
	end

	-------------------------------------------------------------------------------
	--- Dumps the items in the specified profession
	-------------------------------------------------------------------------------
	local function ProfessionDump(prof_name)
		local master_list = LoadAllRecipes()

		if not master_list then
			addon:Print(L["DATAMINE_NODB_ERROR"])
			return
		end
		table.wipe(recipe_list)

		if prof_name == private.professions["Smelting"]:lower() then
			prof_name = private.mining_name:lower()
		end
		for i in pairs(master_list) do
			local prof = master_list[i].profession:lower()

			if prof and prof == prof_name then
				recipe_list[i] = master_list[i]
			end
		end
		SortRecipesByID()
		table.wipe(output)

		for index, id in ipairs(addon.sorted_recipes) do
			RecipeDump(id, false)
		end
		addon:DisplayTextDump(nil, nil, table.concat(output, "\n"))
	end

	function addon:DumpRecipe(id_num)
		table.wipe(output)
		RecipeDump(id_num, true)
		addon:DisplayTextDump(nil, nil, table.concat(output, "\n"))
	end

	function addon:DumpProfession(prof_name)
		if type(prof_name) == "number" then
			prof_name = _G.GetSpellInfo(prof_name)
		end

		local found = false
		prof_name = prof_name:lower()

		local scan_all = prof_name == "all"

		if not scan_all then
			for idx, name in ipairs(ORDERED_PROFESSIONS) do
				if prof_name == name:lower() then
					found = true
					break
				end
			end

			if not found then
				self:Print(L["DATAMINER_NODB_ERROR"])
				return
			end
			ProfessionDump(prof_name)
		else
			for idx, name in ipairs(ORDERED_PROFESSIONS) do
				ProfessionDump(name:lower())
			end
		end
	end

	-------------------------------------------------------------------------------
	--- Dumps the trainers for the specified recipe/profession
	-------------------------------------------------------------------------------
	local trainer_registry = {}
	local sorted_data = {}

	local function ProfessionTrainerDump(prof_name)
		local master_list = LoadAllRecipes()

		if not master_list then
			addon:Print(L["DATAMINE_NODB_ERROR"])
			return
		end
		table.wipe(recipe_list)

		if prof_name == private.professions["Smelting"]:lower() then
			prof_name = private.mining_name:lower()
		end
		for i in pairs(master_list) do
			local prof = master_list[i].profession:lower()

			if prof and prof == prof_name then
				recipe_list[i] = master_list[i]
			end
		end
		SortRecipesByID()
		table.wipe(output)
		table.wipe(trainer_registry)
		table.wipe(sorted_data)

		for index, spell_id in ipairs(addon.sorted_recipes) do
			private.recipe_list[spell_id]:DumpTrainers(trainer_registry)
		end

		for identifier in pairs(trainer_registry) do
			table.insert(sorted_data, identifier)
		end
		table.sort(sorted_data)

		for index, identifier in ipairs(sorted_data) do
			local trainer = private.trainer_list[identifier]
			local trainer_name

			if trainer then
				if trainer.spell_id then
					table.insert(output, ("self:AddTrainer(%s, %s, \"%s\", %s, %s, \"%s\")"):format(identifier, trainer.spell_id, trainer.location, trainer.coord_x, trainer.coord_y, trainer.faction))
				else
					table.insert(output, ("self:AddTrainer(%s, \"%s\", \"%s\", %s, %s, \"%s\")"):format(identifier, trainer.name:gsub("\"", "\\\""), trainer.location, trainer.coord_x, trainer.coord_y, trainer.faction))
				end
			end
		end
		addon:DisplayTextDump(nil, nil, table.concat(output, "\n"))
	end

	function addon:DumpTrainers(prof_name)
		if type(prof_name) == "number" then
			prof_name = _G.GetSpellInfo(prof_name)
		end
		prof_name = prof_name:lower()

		local scan_all = prof_name == "all"

		if scan_all then
			for idx, name in ipairs(ORDERED_PROFESSIONS) do
				ProfessionTrainerDump(name:lower())
			end
		else
			local found = false

			for idx, name in ipairs(ORDERED_PROFESSIONS) do
				if prof_name == name:lower() then
					found = true
					break
				end
			end

			if not found then
				self:Print(L["DATAMINER_NODB_ERROR"])
				return
			end
			ProfessionTrainerDump(prof_name)
		end
	end
end	-- do

local RECIPE_TYPES = {
	-- JC
	["design: "] = true,
	-- LW or Tailoring
	["pattern: "] = true,
	-- Alchemy or Cooking
	["recipe: "] = true,
	-- BS
	["plans: "] = true,
	-- Enchanting
	["formula: "] = true,
	-- Engineering
	["schematic: "] = true,
	-- First Aid
	["manual: "] = true,

	["alchemy: "] = true,
	["blacksmithing: "] = true,
	["cooking: "] = true,
	["enchanting: "] = true,
	["engineering: "] = true,
	["first aid: "] = true,
	["inscription: "] = true,
	["jewelcrafting: "] = true,
	["leatherworking: "] = true,
	["tailoring: "] = true,
}

--- Scans the items on a vendor, determining which recipes are available if any and compares it with the database entries
-- @name AckisRecipeList:ScanVendor
-- @usage AckisRecipeList:ScanVendor()
-- @return Obtains all the vendor information on tradeskill recipes and attempts to compare the current vendor with the internal database
do
	local output = {}
	local RECIPE_ITEM_TO_SPELL_MAP

	function addon:ScanVendor()
		if not _G.UnitExists("target") or _G.UnitIsPlayer("target") or _G.UnitIsEnemy("player", "target") then
			self:Print(L["DATAMINER_VENDOR_NOTTARGETTED"])
			return
		end
		local recipe_list = LoadAllRecipes()		-- Get internal database

		if not recipe_list then
			self:Print(L["DATAMINER_NODB_ERROR"])
			return
		end
		local vendor_name = _G.UnitName("target")
		local vendor_id = tonumber(_G.UnitGUID("target"):sub(-12,-9), 16)
		local added_output = false

		table.wipe(output)

		table.insert(output, ("ARL Version: %s"):format(self.version))
		table.insert(output, L["DATAMINER_VENDOR_INFO"]:format(vendor_name, vendor_id))

		if not RECIPE_ITEM_TO_SPELL_MAP then
			RECIPE_ITEM_TO_SPELL_MAP = {}

			for spell_id, recipe in pairs(private.recipe_list) do
				local recipe_item_id = recipe:RecipeItemID()

				if recipe_item_id then
					RECIPE_ITEM_TO_SPELL_MAP[recipe_item_id] = spell_id
				elseif recipe:HasFilter("common1", "VENDOR") or recipe:HasFilter("common1", "INSTANCE") or recipe:HasFilter("common1", "RAID") or recipe:HasFilter("common1", "MOB_DROP") or recipe:HasFilter("common1", "WORLD_DROP") then
					self:Debug("Recipe %d (%s) is missing a recipe item ID.", spell_id, recipe.name)
				end
			end
		end

		for index = 1, _G.GetMerchantNumItems(), 1 do
			local item_name, _, _, _, supply = _G.GetMerchantItemInfo(index)

			if item_name then
				local match_text = item_name:match("%a+: ")

				if match_text and RECIPE_TYPES[match_text:lower()] then
					local item_id = private.ItemLinkToID(_G.GetMerchantItemLink(index))
					local spell_id = RECIPE_ITEM_TO_SPELL_MAP[item_id]

					if spell_id then
						local scanned_text = addon:TooltipScanRecipe(spell_id, true, true)

						if scanned_text and scanned_text ~= "" then
							added_output = true
							table.insert(output, scanned_text)
						end

						-- Check the database to see if the vendor is listed as an acquire method.
						local recipe = recipe_list[spell_id]
						local acquire_data = recipe and recipe.acquire_data
						local vendor_data = acquire_data and acquire_data[A.VENDOR]
						local rep_data = acquire_data and acquire_data[A.REPUTATION]
						local matching_vendor = false

						if vendor_data then
							for id_num in pairs(vendor_data) do
								if id_num == vendor_id then
									matching_vendor = true
									break
								end
							end
						elseif rep_data then
							for id_num, info in pairs(rep_data) do
								if matching_vendor then
									break
								end

								for rep_level, level_info in pairs(info) do
									for rep_vendor_id in pairs(level_info) do
										if rep_vendor_id == vendor_id then
											matching_vendor = true
										end
									end
								end
							end
						end
						local vendor_entry = private.vendor_list[vendor_id]

						if not vendor_entry then
							table.insert(output, ("%s was not found in the vendor list"):format(vendor_name))
						end

						if matching_vendor and vendor_entry and vendor_entry.item_list then
							local reported_supply = vendor_entry.item_list[spell_id]

							if reported_supply == true and supply > -1 then
								recipe:AddLimitedVendor(vendor_id, supply)
								table.insert(output, ("Limited quantity for \"%s\" (%d) found on vendor %d - listed as unlimited quantity."):format(recipe.name, spell_id, vendor_id))
								added_output = true
							elseif type(reported_supply) ~= "boolean" and supply == -1 then
								recipe:AddVendor(vendor_id)
								table.insert(output, ("Unlimited quantity for \"%s\" (%d) found on vendor %d - listed as limited quantity."):format(recipe.name, spell_id, vendor_id))
								added_output = true
							end

							if not recipe:HasFilter("common1", "VENDOR") then
								recipe:AddFilters(F.VENDOR)
								table.insert(output, ("%d: Vendor flag was not set."):format(spell_id))
								added_output = true
							end
						elseif not matching_vendor then
							if supply > -1 then
								recipe:AddLimitedVendor(vendor_id, supply)
							else
								recipe:AddVendor(vendor_id)
							end

							if not recipe:HasFilter("common1", "VENDOR") then
								recipe:AddFilters(F.VENDOR)
								table.insert(output, ("%d: Vendor flag was not set."):format(spell_id))
							end
							added_output = true
							table.insert(output, ("Vendor ID missing from \"%s\" %d."):format(recipe and recipe.name or _G.UNKNOWN, spell_id))
						end
					else
						for spell_id, recipe in pairs(private.recipe_list) do
							local recipe_type, match_text = (":"):split(item_name, 2)

							if recipe.name == match_text:trim() then
								recipe:SetRecipeItemID(item_id)
							end
						end
						--@debug@
						added_output = true
						table.insert(output, ("Spell ID not found for recipe item %d (%s)"):format(item_id, item_name))
					--@end-debug@
					end
				end
			end
		end

		if added_output then
			self:DisplayTextDump(nil, nil, table.concat(output, "\n"))
		end
		ARLDatamineTT:Hide()
	end
end	-- do

--- Parses all the recipes in the database, and scanning their tooltips.
-- @name AckisRecipeList:TooltipScanDatabase
-- @usage AckisRecipeList:TooltipScanDatabase()
-- @return Entire recipe database has its tooltips scanned.
do
	local output = {}

	function addon:TooltipScanDatabase()
		-- Get internal database
		local recipe_list = LoadAllRecipes()

		if (not recipe_list) then
			self:Print(L["DATAMINER_NODB_ERROR"])
			return
		end
		table.wipe(output)

		-- Parse the entire recipe database
		for i in pairs(recipe_list) do

			local ttscantext = addon:TooltipScanRecipe(i, false, true)
			if (ttscantext) then
				table.insert(output, ttscantext)
			end
		end
		self:DisplayTextDump(nil, nil, table.concat(output, "\n"))
	end
end	-- do
--- Parses a specific recipe in the database, and scanning its tooltip
-- @name AckisRecipeList:TooltipScanRecipe
-- @param spell_id The [[[http://www.wowpedia.org/SpellLink|Spell ID]]] of the recipe being added to the database
-- @param is_vendor Boolean to determine if we're viewing a vendor or not
-- @param is_largescan Boolean to determine if we're doing a large scan
-- @return Recipe has its tooltips scanned


-- Table to store scanned information. Wiped and re-used every scan.
local scan_data = {}

do
	---------------------------------------------------------------------------------------------------------
	----This table, DO_NOT_SCAN, contains itemid's that will not cache on the servers
	---------------------------------------------------------------------------------------------------------

	local DO_NOT_SCAN = {
		-------------------------------------------------------------------------------
		--Leatherworking
		-------------------------------------------------------------------------------
		[35214]	=	true,	[32434]	=	true,	[15769]	=	true,	[32431]	=	true,	[32432]	=	true,
		[35215]	=	true,	[35521]	=	true,	[35520]	=	true,	[35524]	=	true,	[35517]	=	true,
		[35528]	=	true,	[35527]	=	true,	[35523]	=	true,	[35549]	=	true,	[35218]	=	true,
		[35217]	=	true,	[35216]	=	true,	[35546]	=	true,	[35541]	=	true,	[15756]	=	true,
		[15777]	=	true,	[32433]	=	true,	[29729]	=	true,	[29732]	=	true,	[32744]	=	true,
		[15773]	=	true,	[30301]	=	true,	[15745]	=	true,	[35302]	=	true,	[15774]	=	true,

		-------------------------------------------------------------------------------
		--Tailoring
		-------------------------------------------------------------------------------
		[14477]	=	true,	[14485]	=	true,	[30281]	=	true,	[14478]	=	true,	[14500]	=	true,
		[32439]	=	true,	[14479]	=	true,	[32447]	=	true,	[14480]	=	true,	[32437]	=	true,
		[14495]	=	true,	[14505]	=	true,	[35204]	=	true,	[35205]	=	true,	[35206]	=	true,
		[14473]	=	true,	[14488]	=	true,	[14481]	=	true,	[35309]	=	true,	[30280]	=	true,
		[14492]	=	true,	[14491]	=	true,

		-------------------------------------------------------------------------------
		--Jewelcrafting
		-------------------------------------------------------------------------------
		[23130]	=	true,	[23140]	=	true,	[23137]	=	true,	[23131]	=	true,	[23148]	=	true,
		[35538]	=	true,	[35201]	=	true,	[35533]	=	true,	[35200]	=	true,	[23147]	=	true,
		[23135]	=	true,	[35203]	=	true,	[35198]	=	true,	[23152]	=	true,	[23151]	=	true,
		[23141]	=	true,	[28596]	=	true,	[28291]	=	true,	[23153]	=	true,

		-------------------------------------------------------------------------------
		--Alchemy
		-------------------------------------------------------------------------------
		[22925]	=	true,	[13480]	=	true,	[13481]	=	true,	[13493]	=	true,	[35295]	=	true,
		[44568]	=	true,

		-------------------------------------------------------------------------------
		--Cooking
		-------------------------------------------------------------------------------
		[39644]	=	true,

		-------------------------------------------------------------------------------
		--Blacksmithing
		-------------------------------------------------------------------------------
		[32441]	=	true,	[32443]	=	true,	[12687]	=	true,	[12714]	=	true,	[12688]	=	true,
		[35211]	=	true,	[35209]	=	true,	[35210]	=	true,	[12706]	=	true,	[7982]	=	true,
		[12718]	=	true,	[23621]	=	true,	[35208]	=	true,	[12716]	=	true,	[23632]	=	true,
		[23633]	=	true,	[30324]	=	true,	[23637]	=	true,	[31393]	=	true,	[22221]	=	true,
		[12690]	=	true,	[31394]	=	true,	[31395]	=	true,	[23630]	=	true,	[23629]	=	true,
		[7978]	=	true,	[41120]	=	true,	[12717]	=	true,	[22219]	=	true,	[23627]	=	true,

		-------------------------------------------------------------------------------
		--Engineering
		-------------------------------------------------------------------------------
		[35196]	=	true,	[21734]	=	true,	[18292]	=	true,	[21727]	=	true,	[21735]	=	true,
		[16053]	=	true,	[21729]	=	true,	[16047]	=	true,	[21730]	=	true,	[21731]	=	true,
		[21732]	=	true,	[4411]	=	true,	[21733]	=	true,	[21728]	=	true,	[35186]	=	true,
		[18655]	=	true,

		-------------------------------------------------------------------------------
		--Enchanting
		-------------------------------------------------------------------------------
		[16222]	=	true,	[20734]	=	true,	[20729]	=	true,	[20731]	=	true,	[16246]	=	true,
	}

	local output = {}

	function addon:TooltipScanRecipe(spell_id, is_vendor, is_largescan)
		local recipe_list = LoadAllRecipes()

		if not recipe_list then
			self:Print(L["DATAMINER_NODB_ERROR"])
			return
		end
		local recipe = recipe_list[spell_id]

		if not recipe then
			self:Debug("Spell ID %d does not exist in the database.", tonumber(spell_id))
			return
		end
		local recipe_name = recipe.name
		local game_vers = private.game_versions[recipe.genesis]

		table.wipe(output)

		if not game_vers then
			table.insert(output, "No expansion information: " .. tostring(spell_id) .. " " .. recipe_name)
		elseif game_vers > #private.game_version_names then
			table.insert(output, "Expansion information too high: " .. tostring(spell_id) .. " " .. recipe_name)
		end
		local optimal = recipe.optimal_level
		local medium = recipe.medium_level
		local easy = recipe.easy_level
		local trivial = recipe.trivial_level
		local skill_level = recipe.skill_level

		if not optimal then
			table.insert(output, "No skill level information: " .. tostring(spell_id) .. " " .. recipe_name)
		else
			-- Highest level is greater than the skill of the recipe
			if optimal > skill_level then
				table.insert(output, "Skill Level Error (optimal_level > skill_level): " .. tostring(spell_id) .. " " .. recipe_name)
			elseif optimal < skill_level then
				table.insert(output, "Skill Level Error (optimal_level < skill_level): " .. tostring(spell_id) .. " " .. recipe_name)
			end

			-- Level info is messed up
			if optimal > medium or optimal > easy or optimal > trivial or medium > easy or medium > trivial or easy > trivial then
				table.insert(output, "Skill Level Error: " .. tostring(spell_id) .. " " .. recipe_name)
			end
		end
		local recipe_link = _G.GetSpellLink(recipe.spell_id)

		if not recipe_link then
			if recipe.profession ~= private.runeforging_name then		-- Lets hide this output for runeforging.
				self:Printf("Missing spell_link for ID %d (%s).", spell_id, recipe_name)
			end
			return
		end
		ARLDatamineTT:SetOwner(_G.WorldFrame, "ANCHOR_NONE")
		_G.GameTooltip_SetDefaultAnchor(ARLDatamineTT, _G.UIParent)

		ARLDatamineTT:SetHyperlink(recipe_link)

		-- Check to see if this is a recipe tooltip.
		local text = _G["ARLDatamineTTTextLeft1"]:GetText():lower()
		local match_text = text:match("%a+: ")

		if not RECIPE_TYPES[match_text] and not (text:find("smelt") or text:find("sunder") or text:find("shatter")) then
			ARLDatamineTT:Hide()
			return
		end
		local reverse_lookup = GetReverseLookup(recipe_list)

		local recipe_item_id = recipe:RecipeItemID()

		table.wipe(scan_data)

		if recipe_item_id then
			if recipe:HasFilter("common1", "TRAINER") and not recipe:HasFilter("common1", "VENDOR") and not recipe:HasFilter("common1", "INSTANCE") and not recipe:HasFilter("common1", "RAID") and not recipe:HasFilter("common1", "WORLD_DROP") then
				table.insert(output, ("Recipe %d (%s): Has Trainer filter flag, but also has a recipe item (%d)."):format(recipe.spell_id, recipe.name, recipe_item_id))
			elseif not DO_NOT_SCAN[recipe_item_id] then
				local item_name, item_link, item_quality = _G.GetItemInfo(recipe_item_id)

				if item_name then
					if item_quality > 0 then
						scan_data.quality = item_quality

						ARLDatamineTT:SetHyperlink(item_link)
						self:ScanToolTip(recipe_name, recipe_list, reverse_lookup, is_vendor)
					else
						table.insert(output, ("Recipe %d (%s): Recipe item quality is 0 (junk), which probably means it has been removed from the game."):format(recipe.spell_id, recipe.name))
					end
				else
					table.insert(output, ("%s: %d"):format(recipe.name, spell_id))

					if _G.Querier then
						table.insert(output, ("    Recipe item not in cache. To fix: /iq %d"):format(recipe_item_id))
					else
						table.insert(output, "    Recipe item not in cache.")
					end
				end
			end
		elseif not recipe_item_id and not recipe:HasFilter("common1", "RETIRED") then
			-- We are dealing with a recipe that does not have an item to learn it from.
			-- Lets check the recipe flags to see if we have a data error and the item should exist
			if recipe:HasFilter("common1", "VENDOR") or recipe:HasFilter("common1", "INSTANCE") or recipe:HasFilter("common1", "RAID") then
				table.insert(output, ("Recipe %d (%s) is missing a recipe item ID."):format(spell_id, recipe.name))
			elseif recipe:HasFilter("common1", "TRAINER") and recipe.quality ~= private.item_qualities["COMMON"] then
				table.insert(output, ("%s: %d"):format(recipe.name, spell_id))
				table.insert(output, ("    Wrong quality: Q.%s - should be Q.COMMON."):format(private.item_quality_names[recipe.quality]))
			end
		end
		ARLDatamineTT:Hide()

		-- Add the flag scan to the table if it's not nil
		local results = self:PrintScanResults()

		if results then
			table.insert(output, results)
		end

		if is_largescan then
			return table.concat(output, "\n")
		else
			self:Print(table.concat(output, "\n"))
		end
	end
end	-- do

-------------------------------------------------------------------------------
-- Tooltip-scanning code
-------------------------------------------------------------------------------
do
	local SPECIALTY_TEXT = {
		--["requires spellfire tailoring"] = 26797,
		--["requires mooncloth tailoring"] = 26798,
		--["requires shadoweave tailoring"] = 26801,
		--["requires dragonscale leatherworking"] = 10657,
		--["requires elemental leatherworking"] = 10659,
		--["requires tribal leatherworking"] = 10661,
		["requires gnomish engineer"] = 20219,
		["requires goblin engineer"] = 20222,
		--["requires armorsmith"] = 9788,
		--["requires master axesmith"] = 17041,
		--["requires master hammersmith"] = 17040,
		--["requires master swordsmith"] = 17039,
		--["requires weaponsmith"] = 9787,
	}

	local FACTION_TEXT = {
		["thorium brotherhood"] = 98,
		["zandalar tribe"] = 100,
		["argent dawn"] = 96,
		["timbermaw hold"] = 99,
		["cenarion circle"] = 97,
		["the aldor"] = 101,
		["the consortium"] = 105,
		["the scryers"] = 110,
		["the sha'tar"] = 111,
		["the mag'har"] = 108,
		["cenarion expedition"] = 103,
		["honor hold"] = 104,
		["thrallmar"] = 104,
		["the violet eye"] = 114,
		["sporeggar"] = 113,
		["kurenai"] = 108,
		["keepers of time"] = 106,
		["the scale of the sands"] = 109,
		["lower city"] = 107,
		["ashtongue deathsworn"] = 102,
		["alliance vanguard"] = 131,
		["valiance expedition"] = 126,
		["horde expedition"] = 130,
		["the taunka"] = 128,
		["the hand of vengeance"] = 127,
		["explorers' league"] = 125,
		["the kalu'ak"] = 120,
		["shattered sun offensive"] = 112,
		["warsong offensive"] = 129,
		["kirin tor"] = 118,
		["the wyrmrest accord"] = 122,
		["knights of the ebon blade"] = 117,
		["frenzyheart tribe"] = 116,
		["the oracles"] = 121,
		["argent crusade"] = 115,
		["the sons of hodir"] = 119,
	}

	local FACTION_LEVELS = {
		["neutral"] = 0,
		["friendly"] = 1,
		["honored"] = 2,
		["revered"] = 3,
		["exalted"] = 4,
	}

	local CLASS_TYPES = {
		["Death Knight"]	= 21, 	["Druid"]	= 22, 	["Hunter"]	= 23,
		["Mage"]		= 24, 	["Paladin"]	= 25, 	["Priest"]	= 26,
		["Shaman"]		= 27, 	["Rogue"]	= 28, 	["Warlock"]	= 29,
		["Warrior"]		= 30,
	}

	local ORDERED_CLASS_TYPES = {
		[1]	= "Death Knight", 	[2]	= "Druid", 	[3]	= "Hunter",
		[4]	= "Mage", 		[5]	= "Paladin", 	[6]	= "Priest",
		[7]	= "Shaman", 		[8]	= "Rogue", 	[9]	= "Warlock",
		[10]	= "Warrior",
	}

	local ROLE_TYPES = {
		["dps"]		= 51, 	["tank"]	= 52, 	["healer"]	= 53,
		["caster"]	= 54,
	}

	local ORDERED_ROLE_TYPES = {
		[1]	= "dps", 	[2]	= "tank", 	[3]	= "healer",
		[4]	= "caster",
	}

	local ENCHANT_TO_ITEM = {
		["Cloak"]	= "Back",
		["Ring"]	= "Finger",
		["2H Weapon"]	= "Two-Hand",
	}

	local ITEM_TYPES = {
		-- Armor types
		["Cloth"]	= 56, 	["Leather"]	= 57, 	["Mail"]	= 58,
		["Plate"]	= 59, 	["Back"]	= 60, 	["Trinket"]	= 61,
		["Finger"]	= 62, 	["Neck"]	= 63, 	["Shield"]	= 64,

		-- Weapon types
		["One-Hand"]	= 66, 	["Two-Hand"]	= 67, 	["Axe"]		= 68,
		["Sword"]	= 69, 	["Mace"]	= 70, 	["Polearm"]	= 71,
		["Dagger"]	= 72, 	["Staff"]	= 73, 	["Wand"]	= 74,
		["Thrown"]	= 75, 	["Bow"]		= 76, 	["CrossBow"]	= 77,
		["Fist Weapon"]	= 79, 	["Gun"]		= 80,
	}

	local ORDERED_ITEM_TYPES = {
		-- Armor types
		[1]	= "Cloth", 	[2]	= "Leather", 	[3]	= "Mail",
		[4]	= "Plate", 	[5]	= "Back", 	[6]	= "Trinket",
		[7]	= "Finger", 	[8]	= "Neck", 	[9]	= "Shield",

		-- Weapon types
		[11]	= "One-Hand", 	[12]	= "Two-Hand", 	[13]	= "Axe",
		[14]	= "Sword", 	[15]	= "Mace", 	[16]	= "Polearm",
		[17]	= "Dagger", 	[18]	= "Staff", 	[19]	= "Wand",
		[20]	= "Thrown", 	[21]	= "Bow", 	[22]	= "CrossBow",
		[23]	= "Fist Weapon", 	[24]	= "Gun",
	}

	--- Parses the mining tooltip for certain keywords, comparing them with the database flags
	-- @name AckisRecipeList:ScanToolTip
	-- @param name The name of the recipe
	-- @param recipe_list Recipe database
	-- @param reverse_lookup Reverse lookup database
	-- @param is_vendor Boolean to indicate if we're scanning a vendor
	-- @return Scans a tooltip, and outputs the missing or extra filter flags
	function addon:ScanToolTip(name, recipe_list, reverse_lookup, is_vendor)
		scan_data.match_name = name
		scan_data.recipe_list = recipe_list
		scan_data.reverse_lookup = reverse_lookup
		scan_data.is_vendor = is_vendor

		-- Parse all the lines of the tooltip
		for i = 1, ARLDatamineTT:NumLines(), 1 do
			local text_l = _G["ARLDatamineTTTextLeft" .. i]:GetText()
			local text_r = _G["ARLDatamineTTTextRight" .. i]:GetText()
			local text

			if text_r then
				text = ("%s %s"):format(text_l, text_r)
			else
				text = text_l
			end
			text = text:lower()

			-- Check for recipe/item binding
			-- The recipe binding is within the first few lines of the tooltip always
			if text:match("binds when picked up") then
				if (i < 3) then
					scan_data.recipe_bop = true
				else
					scan_data.item_bop = true
				end
			end

			-- Recipe Specialities
			if SPECIALTY_TEXT[text] then
				scan_data.specialty = SPECIALTY_TEXT[text]
			end

			-- Recipe Reputations
			local rep, replevel = text_l:match("Requires (.+) %- (.+)")

			if rep and replevel and FACTION_TEXT[rep] then
				scan_data.repid = FACTION_TEXT[rep]
				scan_data.repidlevel = FACTION_LEVELS[replevel]
			end

			-- Flag so that we don't bother checking for classes if we're sure of the class
			-- AKA +spell hit == caster DPS only no matter what other stats are on it
			-- Saves processing cycles and it won't cause the flags to be overwritten if a non-specific stat is found after
			scan_data.verifiedclass = false

			if not scan_data.verifiedclass then
				-- Certain stats can be considered for a specific role (aka spell hit == caster dps).
				if text:match("strength") and not text:match("strength of the clefthoof") and not text:match("set:") then
					scan_data.dps = true
				elseif text:match("agility") then
					scan_data.dps = true
				elseif text:match("spirit") or text:match("intellect") then
					scan_data.caster = true
					scan_data.healer = true
				elseif text:match("spell power") then
					scan_data.caster = true
					scan_data.healer = true
				elseif text:match("spell crit") then
					scan_data.caster = true
					scan_data.healer = true
				elseif text:match("spell hit") then
					scan_data.caster = true
					scan_data.verifiedclass = true
				elseif text:match("spell penetration") then
					scan_data.caster = true
					scan_data.verifiedclass = true
				elseif text:match("mana per 5 sec.") or text:match("mana every 5 seconds") then
					scan_data.caster = true
					scan_data.healer = true
				elseif text:match("attack power") then
					scan_data.dps = true
				elseif text:match("expertise") then
					scan_data.dps = true
					scan_data.tank = true
				elseif text:match("melee crit") then
					scan_data.dps = true
				elseif text:match("critical hit") then
					scan_data.dps = true
				elseif text:match("weapon damage") then
					scan_data.dps = true
				elseif text:match("ranged crit") then
					scan_data.dps = true
					scan_data.verifiedclass = true
				elseif text:match("melee haste") then
					scan_data.dps = true
				elseif text:match("ranged haste") then
					scan_data.dps = true
					scan_data.verifiedclass = true
				elseif text:match("melee hit") then
					scan_data.dps = true
				elseif text:match("ranged hit") then
					scan_data.dps = true
					scan_data.verifiedclass = true
				elseif text:match("armor pen") then
					scan_data.dps = true
				elseif text:match("feral attack power") then
					scan_data.tank = true
					scan_data.dps = true
				elseif text:match("defense") and not text:match("defenseless") then
					scan_data.tank = true
					scan_data.verifiedclass = true
				elseif text:match("block") then
					scan_data.tank = true
					scan_data.verifiedclass = true
				elseif text:match("parry") then
					scan_data.tank = true
					scan_data.verifiedclass = true
				elseif text:match("dodge") and not text:match("set:") then
					scan_data.tank = true
					scan_data.verifiedclass = true
				end
			end

			-- Classes
			local class_type = text_l:match("Classes: (.+)")

			if class_type then
				for idx, class in ipairs(ORDERED_CLASS_TYPES) do
					if class_type:match(class) then
						scan_data[class] = true
						scan_data.found_class = true
					end
				end
			end

			-- Armor types
			if ITEM_TYPES[text_l] then
				scan_data[text_l] = true
			elseif text_l == "Held In Off-hand" or text_l == "Off Hand" or text_l == "Main Hand" then	-- Special cases.
				scan_data["One-Hand"] = true
			end

			if text_r and ITEM_TYPES[text_r] then
				scan_data[text_r] = true
			end

			-- Enchantment voodoo
			local ench_type, _ = text_l:match("Enchant (.+) %- (.+)")

			if ench_type then
				if ITEM_TYPES[ench_type] then
					scan_data[ench_type] = true
				elseif ITEM_TYPES[ENCHANT_TO_ITEM[ench_type]] then
					scan_data[ENCHANT_TO_ITEM[ench_type]] = true
				elseif ench_type == "Weapon" then		-- Special case.
					scan_data["One-Hand"] = true
					scan_data["Two-Hand"] = true
				end
			end
		end	-- for
	end

	-- Flag data for printing. Wiped and re-used.
	local missing_flags = {}
	local extra_flags = {}
	local output = {}

	local ACQUIRE_TO_FILTER_MAP = {
		[A.MOB_DROP]	= F.MOB_DROP,
		[A.QUEST]	= F.QUEST,
		[A.SEASONAL]	= F.SEASONAL,
		[A.WORLD_DROP]	= F.WORLD_DROP,
	}
	local FILTER_TO_ACQUIRE_MAP

	local OBTAIN_FILTERS = {
		["TRAINER"] = true,
		["VENDOR"] = true,
		["INSTANCE"] = true,
		["RAID"] = true,
		["SEASONAL"] = true,
		["QUEST"] = true,
		["PVP"] = true,
		["WORLD_DROP"] = true,
		["MOB_DROP"] = true,
		["DISC"] = true,
	}

	--- Prints out the results of the tooltip scan.
	-- @name AckisRecipeList:PrintScanResults
	function addon:PrintScanResults()
		if not scan_data.match_name then
			return
		end

		-- Parse the recipe database until we get a match on the name
		local recipe_name = scan_data.match_name:gsub("%a+%?: ","")
		local spell_id = scan_data.reverse_lookup[recipe_name]

		if not spell_id then
			self:Print(recipe_name .. " has no reverse lookup")
			return
		end
		local recipe = scan_data.recipe_list[spell_id]
		local acquire_data = recipe["acquire_data"]

		local FS = private.filter_strings
		local flag_format = "F.%s"

		table.wipe(missing_flags)
		table.wipe(extra_flags)
		table.wipe(output)

		-- If we're a vendor scan,  do some extra checks
		if scan_data.is_vendor then
			-- Check to see if the vendor flag is set
			if not recipe:HasFilter("common1", "VENDOR") then
				table.insert(missing_flags, flag_format:format(FS[F.VENDOR]))
			end

			-- Check to see if we're in a PVP zone
			local subzone_text = _G.GetSubZoneText()

			if (subzone_text == "Wintergrasp Fortress" or subzone_text == "Halaa") and not recipe:HasFilter("common1", "PVP") then
				table.insert(missing_flags, flag_format:format(FS[F.PVP]))
			elseif recipe:HasFilter("common1", "PVP") and not (subzone_text == "Wintergrasp Fortress" or subzone_text == "Halaa") then
				table.insert(extra_flags, flag_format:format(FS[F.PVP]))
			end
		end

		-- -- If we've picked up at least one class flag
		if scan_data.found_class then
			for k, v in ipairs(ORDERED_CLASS_TYPES) do
				if scan_data[v] and not recipe:HasFilter("class1", FS[CLASS_TYPES[v]]) then
					table.insert(missing_flags, flag_format:format(FS[CLASS_TYPES[v]]))
				elseif not scan_data[v] and recipe:HasFilter("class1", FS[CLASS_TYPES[v]]) then
					table.insert(extra_flags, flag_format:format(FS[CLASS_TYPES[v]]))
				end
			end
		end

		if scan_data.item_bop and not recipe:HasFilter("common1", "IBOP") then
			table.insert(missing_flags, flag_format:format(FS[F.IBOP]))

			if recipe:HasFilter("common1", "IBOE") then
				table.insert(extra_flags, flag_format:format(FS[F.IBOE]))
			end

			if recipe:HasFilter("common1", "IBOA") then
				table.insert(extra_flags, flag_format:format(FS[F.IBOA]))
			end
		elseif not recipe:HasFilter("common1", "IBOE") and not scan_data.item_bop then
			table.insert(missing_flags, flag_format:format(FS[F.IBOE]))

			if recipe:HasFilter("common1", "IBOP") then
				table.insert(extra_flags, flag_format:format(FS[F.IBOP]))
			end

			if recipe:HasFilter("common1", "IBOA") then
				table.insert(extra_flags, flag_format:format(FS[F.IBOA]))
			end
		end

		if scan_data.recipe_bop and not recipe:HasFilter("common1", "RBOP") then
			table.insert(missing_flags, flag_format:format(FS[F.RBOP]))

			if recipe:HasFilter("common1", "RBOE") then
				table.insert(extra_flags, flag_format:format(FS[F.RBOE]))
			end

			if recipe:HasFilter("common1", "RBOA") then
				table.insert(extra_flags, flag_format:format(FS[F.RBOA]))
			end

		elseif not recipe:HasFilter("common1", "TRAINER") and not recipe:HasFilter("common1", "RBOE") and not scan_data.recipe_bop then
			table.insert(missing_flags, flag_format:format(FS[F.RBOE]))

			if recipe:HasFilter("common1", "RBOP") then
				table.insert(extra_flags, flag_format:format(FS[F.RBOP]))
			end

			if recipe:HasFilter("common1", "RBOA") then
				table.insert(extra_flags, flag_format:format(FS[F.RBOA]))
			end
		end

		for k, v in ipairs(ORDERED_ROLE_TYPES) do
			local role_string = FS[ROLE_TYPES[v]]

			if scan_data[v] and not recipe:HasFilter("common1", role_string) then
				table.insert(missing_flags, flag_format:format(role_string))
			elseif not scan_data[v] and recipe:HasFilter("common1", role_string) then
				table.insert(extra_flags, flag_format:format(role_string))
			end
		end

		for k, v in ipairs(ORDERED_ITEM_TYPES) do
			if scan_data[v] and not recipe:HasFilter("item1", FS[ITEM_TYPES[v]]) then
				table.insert(missing_flags, flag_format:format(FS[ITEM_TYPES[v]]))
			elseif not scan_data[v] and recipe:HasFilter("item1", FS[ITEM_TYPES[v]]) then
				table.insert(extra_flags, flag_format:format(FS[ITEM_TYPES[v]]))
			end
		end

		-- Reputations
		local repid = scan_data.repid
		local found_problem = false

		if repid and not recipe:HasFilter("reputation1", FS[repid]) and not recipe:HasFilter("reputation2", FS[repid]) then
			table.insert(missing_flags, repid)

			local rep_data = acquire_data[A.REPUTATION]

			if rep_data then
				for rep_id, rep_info in pairs(rep_data) do
					for rep_level, level_info in pairs(rep_info) do
						if rep_level ~= scan_data.repidlevel then
							table.insert(output, "    Wrong reputation level.")
						end
					end
				end
			end
		end

		-- Make sure the recipe's filter flags match with its acquire types.
		if not FILTER_TO_ACQUIRE_MAP then
			FILTER_TO_ACQUIRE_MAP = {}

			for k, v in pairs(ACQUIRE_TO_FILTER_MAP) do
				FILTER_TO_ACQUIRE_MAP[v] = k
			end
		end

		for acquire_type in pairs(acquire_data) do
			local flag = ACQUIRE_TO_FILTER_MAP[acquire_type]

			if flag and not recipe:HasFilter("common1", FS[flag]) then
				table.insert(missing_flags, flag_format:format(FS[flag]))
			end
		end

		if (acquire_data[A.VENDOR] or acquire_data[A.REPUTATION]) and not recipe:HasFilter("common1", "VENDOR") then
			table.insert(missing_flags, flag_format:format(FS[F.VENDOR]))
		end

		if recipe:HasFilter("common1", "VENDOR") and not (acquire_data[A.VENDOR] or acquire_data[A.REPUTATION]) then
			table.insert(extra_flags, flag_format:format(FS[F.VENDOR]))
		end

		if acquire_data[A.TRAINER] and not recipe:HasFilter("common1", "TRAINER") then
			table.insert(missing_flags, flag_format:format(FS[F.TRAINER]))
		end

		if recipe:HasFilter("common1", "TRAINER") and not acquire_data[A.TRAINER] and not acquire_data[A.CUSTOM] then
			table.insert(extra_flags, flag_format:format(FS[F.TRAINER]))
		end

		for flag, acquire_type in pairs(FILTER_TO_ACQUIRE_MAP) do
			if recipe:HasFilter("common1", FS[flag]) and not acquire_data[acquire_type] then
				table.insert(extra_flags, flag_format:format(FS[flag]))
			end
		end

		if #missing_flags > 0 or #extra_flags > 0 then
			found_problem = true

			-- Add a string of the missing flag numbers
			if #missing_flags > 0 then
				table.insert(output, "    Missing flags: " .. table.concat(missing_flags, ", "))
			end

			-- Add a string of the extra flag numbers
			if #extra_flags > 0 then
				table.insert(output, "    Extra flags: " .. table.concat(extra_flags, ", "))
			end
			local found_type = false

			for k, v in ipairs(ORDERED_ITEM_TYPES) do
				if scan_data[v] then
					found_type = true
					break
				end
			end

			if not found_type then
				table.insert(output, "    Missing: item type flag")
			end
		end

		-- Check to see if we have a horde/alliance flag,  all recipes must have one of these
		if not recipe:HasFilter("common1", "ALLIANCE") and not recipe:HasFilter("common1", "HORDE") then
			found_problem = true
			table.insert(output, "    Horde or Alliance not selected.")
		end

		-- Check to see if we have an obtain method flag,  all recipes must have at least one of these
		if not recipe:HasFilter("common1", "RETIRED") then
			local matching_filter = false

			for filter in pairs(OBTAIN_FILTERS) do
				if recipe:HasFilter("common1", filter) then
					matching_filter = true
					break
				end
			end

			if not matching_filter then
				found_problem = true
				table.insert(output, "    No obtain flag.")
			end
		end

		-- Check for recipe binding information,  all recipes must have one of these
		if not recipe:HasFilter("common1", "RBOE") and not recipe:HasFilter("common1", "RBOP") and not recipe:HasFilter("common1", "RBOA") then
			found_problem = true
			table.insert(output, "    No recipe binding information.")
		end

		-- Check for item binding information,  all recipes must have one of these
		if not recipe:HasFilter("common1", "IBOE") and not recipe:HasFilter("common1", "IBOP") and not recipe:HasFilter("common1", "IBOA") then
			found_problem = true
			table.insert(output, "    No item binding information.")
		end

		-- We need to code this better.  Some items (aka bags) won't have a role at all.
		-- Check for player role flags
		if not scan_data.tank and not scan_data.healer and not scan_data.caster and not scan_data.dps and not NO_ROLE_FLAG[spell_id] then
			found_problem = true
			table.insert(output, "    No player role flag.")
		end

		if scan_data.specialty then
			if not recipe.specialty then
				found_problem = true
				table.insert(output, ("    Missing Specialty: %s"):format(scan_data.specialty))
			elseif recipe.specialty ~= scan_data.specialty then
				table.insert(output, ("    Wrong Specialty: %s - should be %s "):format(recipe.specialty,scan_data.specialty))
			end
		elseif recipe.specialty then
			found_problem = true
			table.insert(output, ("    Extra Specialty: %s"):format(recipe.specialty))
		end

		if scan_data.quality and scan_data.quality ~= recipe.quality then
			local QS = private.item_quality_names

			found_problem = true
			table.insert(output, ("    Wrong quality: Q.%s - should be Q.%s."):format(QS[recipe.quality], QS[scan_data.quality]))
		end

		if found_problem then
			table.insert(output, 1, ("%s: <a href=\"http://www.wowhead.com/?spell=%d\">%d</a>"):format(recipe_name,spell_id,spell_id))
			return table.concat(output, "\n")
		else
			return
		end
	end
end

-------------------------------------------------------------------------------
-- Look up table of spell IDs for recipes which do not have a player flag
-- BASICALLY A TEMPORARY STORAGE FOR IDS, SO WE CAN SEE CLEANER SCANS AND WHAT NOT,
-- WE'LL GO BACK HERE LATER DOWN THE ROAD.
-------------------------------------------------------------------------------
NO_ROLE_FLAG = {
	--------------------------------------------------------------------------------------------
	-----ASSORTED CRAP
	--------------------------------------------------------------------------------------------
	[30344]	=	true,			[30341]	=	true,			[32814]	=	true,			[23066]	=	true,
	[26421]	=	true,			[36955]	=	true,			[19788]	=	true,			[23129]	=	true,
	[26422]	=	true,			[12715]	=	true,			[12899]	=	true,			[56459]	=	true,
	[30307]	=	true,			[26423]	=	true,			[3918]	=	true,			[23067]	=	true,
	[30308]	=	true,			[3953]	=	true,			[15255]	=	true,			[26424]	=	true,
	[30548]	=	true,			[44157]	=	true,			[56462]	=	true,			[19567]	=	true,
	[30552]	=	true,			[23068]	=	true,			[44155]	=	true,			[28327]	=	true,
	[26425]	=	true,			[56461]	=	true,			[68067]	=	true,			[15633]	=	true,
	[23096]	=	true,			[12589]	=	true,			[26442]	=	true,			[26426]	=	true,
	[67920]	=	true,			[9273]	=	true,			[3926]	=	true,			[6458]	=	true,
	[19793]	=	true,			[55252]	=	true,			[9271]	=	true,			[26427]	=	true,
	[26443]	=	true,			[30551]	=	true,			[23486]	=	true,			[3922]	=	true,
	[3924]	=	true,			[12590]	=	true,			[3928]	=	true,			[3942]	=	true,
	[26428]	=	true,			[3952]	=	true,			[22704]	=	true,			[12902]	=	true,
	[30569]	=	true,			[15628]	=	true,			[12895]	=	true,			[21940]	=	true,
	[56349]	=	true,			[12584]	=	true,			[56477]	=	true,			[30348]	=	true,
	[26416]	=	true,			[53281]	=	true,			[23507]	=	true,			[12075]	=	true,
	[12079]	=	true,			[26746]	=	true,			[56000]	=	true,

	-----------------------------------------------------------------------------------------
	---JEWELCRAFTING
	-----------------------------------------------------------------------------------------
	[55401]	=	true,	[53995]	=	true,	[66432]	=	true,	[25255]	=	true,
	[66497]	=	true,	[53996]	=	true,	[56074]	=	true,	[56202]	=	true,
	[66434]	=	true,	[32801]	=	true,	[28948]	=	true,	[53997]	=	true,
	[39963]	=	true,	[32866]	=	true,	[66501]	=	true,	[39452]	=	true,
	[53934]	=	true,	[66502]	=	true,	[55405]	=	true,	[58954]	=	true,
	[56205]	=	true,	[37855]	=	true,	[38175]	=	true,	[25305]	=	true,
	[25321]	=	true,	[66505]	=	true,	[54000]	=	true,	[39742]	=	true,
	[56206]	=	true,	[66506]	=	true,	[32869]	=	true,	[54001]	=	true,
	[56079]	=	true,	[32259]	=	true,	[32870]	=	true,	[56208]	=	true,
	[32807]	=	true,	[32871]	=	true,	[26873]	=	true,	[31061]	=	true,
	[32872]	=	true,	[42591]	=	true,	[46779]	=	true,	[56530]	=	true,
	[42592]	=	true,	[31062]	=	true,	[56083]	=	true,	[32874]	=	true,
	[56531]	=	true,	[31063]	=	true,	[56085]	=	true,	[38503]	=	true,
	[56086]	=	true,	[28938]	=	true,	[38504]	=	true,	[31064]	=	true,
	[31096]	=	true,	[55384]	=	true,	[25278]	=	true,	[68253]	=	true,
	[43493]	=	true,	[26925]	=	true,	[31065]	=	true,	[46403]	=	true,
	[53852]	=	true,	[53916]	=	true,	[39722]	=	true,	[25615]	=	true,
	[28924]	=	true,	[26926]	=	true,	[53853]	=	true,	[36526]	=	true,
	[31098]	=	true,	[55388]	=	true,	[46405]	=	true,	[53854]	=	true,
	[39724]	=	true,	[55389]	=	true,	[26927]	=	true,	[31051]	=	true,
	[53919]	=	true,	[39725]	=	true,	[55390]	=	true,	[53856]	=	true,
	[53920]	=	true,	[53952]	=	true,	[26880]	=	true,	[53857]	=	true,
	[31052]	=	true,	[34069]	=	true,	[25490]	=	true,	[55393]	=	true,
	[39451]	=	true,	[53956]	=	true,	[44794]	=	true,	[36524]	=	true,
	[55395]	=	true,	[38068]	=	true,	[28944]	=	true,	[53957]	=	true,
	[31066]	=	true,	[31082]	=	true,	[66428]	=	true,	[26909]	=	true,
	[55396]	=	true,	[31097]	=	true,	[25284]	=	true,	[56084]	=	true,
	[62941]	=	true,	[66431]	=	true,	[53894]	=	true,	[53958]	=	true,
	[58146]	=	true,	[31099]	=	true,	[47053]	=	true,	[31067]	=	true,
	[28917]	=	true,	[26903]	=	true,	[36525]	=	true,	[66503]	=	true,
	[56197]	=	true,	[47054]	=	true,	[53961]	=	true,	[39715]	=	true,
	[31092]	=	true,	[53960]	=	true,	[31077]	=	true,	[31101]	=	true,
	[39719]	=	true,	[55399]	=	true,	[31113]	=	true,	[32808]	=	true,
	[53917]	=	true,	[63743]	=	true,	[39720]	=	true,	[39721]	=	true,
	[42590]	=	true,	[58149]	=	true,	[56199]	=	true,	[47056]	=	true,
	[28950]	=	true,	[47280]	=	true,	[32809]	=	true,	[31072]	=	true,
	[25318]	=	true,	[66429]	=	true,	[62242]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	---COOKING
	---------------------------------------------------------------------------------------
	[62050] =	true,	[22761]	=	true,	[62051]	=	true,	[8607]	=	true,	[18238]	=	true,
	[6413]	=	true,	[6417]	=	true,	[42296]	=	true,	[45557]	=	true,	[6501]	=	true,
	[45558]	=	true,	[18239]	=	true,	[7752]	=	true,	[7828]	=	true,	[45560]	=	true,
	[64358]	=	true,	[57421]	=	true,	[45561]	=	true,	[13028]	=	true,	[2543]	=	true,
	[2545]	=	true,	[25659]	=	true,	[58512]	=	true,	[45565]	=	true,	[42305]	=	true,
	[45566] =	true,	[62350]	=	true,	[7753]	=	true,	[45695]	=	true,	[9513]	=	true,
	[18244]	=	true,	[20626]	=	true,	[45569]	=	true,	[43779]	=	true,	[18245]	=	true,
	[45571]	=	true,	[18246]	=	true,	[37836]	=	true,	[57433]	=	true,	[20916]	=	true,
	[58521]	=	true,	[18247]	=	true,	[57435]	=	true,	[7754]	=	true,	[53056]	=	true,
	[58523]	=	true,	[57437]	=	true,	[57438]	=	true,	[58525]	=	true,	[45570]	=	true,
	[2538]	=	true,	[2540]	=	true,	[2548]	=	true,	[33290]	=	true,	[45562]	=	true,
	[15906]	=	true,	[18241]	=	true,	[45559]	=	true,	[45551]	=	true,	[57443]	=	true,
	[58527]	=	true,	[43758]	=	true,	[58528]	=	true,	[8238]	=	true,	[7751]	=	true,
	[7755]	=	true,	[43761]	=	true,	[7827]	=	true,	[45552]	=	true,	[45553]	=	true,
	[66038]	=	true,	[66034]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	---BLACKSMITHING
	---------------------------------------------------------------------------------------
	[10015]	=	true,	[55202]	=	true,	[16726]	=	true,	[24399]	=	true,
	[15293]	=	true,	[32655]	=	true,	[3320]	=	true,	[40033]	=	true,
	[34545]	=	true,	[61010]	=	true,	[16639]	=	true,	[3115]	=	true,
	[3116]	=	true,	[3117]	=	true,	[16648]	=	true,	[40034]	=	true,
	[9920]	=	true,	[9928]	=	true,	[29558]	=	true,	[55839]	=	true,
	[9964]	=	true,	[7818]	=	true,	[55732]	=	true,	[29694]	=	true,
	[3326]	=	true,	[9950]	=	true,	[59405]	=	true,	[12260]	=	true,
	[16983]	=	true,	[16991]	=	true,	[23650]	=	true,	[16640]	=	true,
	[2741]	=	true,	[3513]	=	true,	[3497]	=	true,	[8768]	=	true,
	[19666]	=	true,	[2662]	=	true,	[2663]	=	true,	[20201]	=	true,
	[16664]	=	true,	[15294]	=	true,	[3496]	=	true,	[16645]	=	true,
	[29569]	=	true,	[2737]	=	true,	[14380]	=	true,	[16992]	=	true,
	[36125]	=	true,	[19667]	=	true,	[22757]	=	true,	[16665]	=	true,
	[59406]	=	true,	[2738]	=	true,	[2739]	=	true,	[2740]	=	true,
	[24913]	=	true,	[9933]	=	true,	[20873]	=	true,	[36126]	=	true,
	[40035]	=	true,	[8880]	=	true,	[23636]	=	true,	[3292]	=	true,
	[3293]	=	true,	[21161]	=	true,	[32656]	=	true,	[19668]	=	true,
	[9921]	=	true,	[7222]	=	true,	[3319]	=	true,	[15295]	=	true,
	[20874]	=	true,	[20890]	=	true,	[3337]	=	true,	[34546]	=	true,
	[16970]	=	true,	[16978]	=	true,	[61008]	=	true,	[7224]	=	true,
	[11454]	=	true,	[19669]	=	true,	[55656]	=	true,	[16667]	=	true,
	[16731]	=	true,	[61009]	=	true,	[9926]	=	true,	[16984]	=	true,
	[21913]	=	true,	[40036]	=	true,	[9974]	=	true,	[32657]	=	true,
	[32285]	=	true,	[23638]	=	true,	[10011]	=	true,	[36131]	=	true,
	[27830]	=	true,	[32284]	=	true,	[16732]	=	true,	[15292]	=	true,
	[15296]	=	true,	[38478]	=	true,	[20876]	=	true,	[38475]	=	true,
	[23653]	=	true,	[3325]	=	true,	[14379]	=	true,	[29729]	=	true,
	[2661]	=	true,	[29728]	=	true,	[16655]	=	true,	[16993]	=	true,
	[3491]	=	true,	[3494]	=	true,	[3501]	=	true,	[9959]	=	true,
	[9983]	=	true,	[36262]	=	true,	[10003]	=	true,	[10007]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	----INSCRIPTION
	---------------------------------------------------------------------------------------
	[58315]	=	true,	[58331]	=	true,	[58347]	=	true,	[56974]	=	true,	[56990]	=	true,
	[64256]	=	true,	[64304]	=	true,	[57166]	=	true,	[57709]	=	true,	[57214]	=	true,
	[57230]	=	true,	[50603]	=	true,	[57262]	=	true,	[59338]	=	true,	[58332]	=	true,
	[56959]	=	true,	[56975]	=	true,	[56991]	=	true,	[57007]	=	true,	[57023]	=	true,
	[53462]	=	true,	[64257]	=	true,	[64273]	=	true,	[64289]	=	true,	[57151]	=	true,
	[57167]	=	true,	[57183]	=	true,	[57710]	=	true,	[57215]	=	true,	[57247]	=	true,
	[50620]	=	true,	[58301]	=	true,	[59339]	=	true,	[58333]	=	true,	[59387]	=	true,
	[52840]	=	true,	[59499]	=	true,	[56960]	=	true,	[56976]	=	true,	[57008]	=	true,
	[57024]	=	true,	[64258]	=	true,	[64274]	=	true,	[57168]	=	true,	[57184]	=	true,
	[61288]	=	true,	[57216]	=	true,	[57232]	=	true,	[58286]	=	true,	[58302]	=	true,
	[59340]	=	true,	[48114]	=	true,	[64051]	=	true,	[59484]	=	true,	[59500]	=	true,
	[56961]	=	true,	[56977]	=	true,	[57009]	=	true,	[57025]	=	true,	[61177]	=	true,
	[64259]	=	true,	[57121]	=	true,	[64291]	=	true,	[57153]	=	true,	[57169]	=	true,
	[57185]	=	true,	[57712]	=	true,	[57217]	=	true,	[57233]	=	true,	[58287]	=	true,
	[58303]	=	true,	[58319]	=	true,	[56946]	=	true,	[56978]	=	true,	[56994]	=	true,
	[57010]	=	true,	[57026]	=	true,	[64260]	=	true,	[57122]	=	true,	[57154]	=	true,
	[57170]	=	true,	[57186]	=	true,	[57713]	=	true,	[57218]	=	true,	[57234]	=	true,
	[57266]	=	true,	[59326]	=	true,	[58320]	=	true,	[58336]	=	true,	[59486]	=	true,
	[59502]	=	true,	[56963]	=	true,	[56995]	=	true,	[57011]	=	true,	[57027]	=	true,
	[64261]	=	true,	[64277]	=	true,	[57155]	=	true,	[57187]	=	true,	[57714]	=	true,
	[57219]	=	true,	[57235]	=	true,	[58289]	=	true,	[58305]	=	true,	[58321]	=	true,
	[58337]	=	true,	[69385]	=	true,	[57243]	=	true,	[64314]	=	true,	[64313]	=	true,
	[56958]	=	true,	[59487]	=	true,	[59503]	=	true,	[58288]	=	true,	[56980]	=	true,
	[56996]	=	true,	[57012]	=	true,	[57028]	=	true,	[59501]	=	true,	[56948]	=	true,
	[57264]	=	true,	[64246]	=	true,	[64262]	=	true,	[57124]	=	true,	[64294]	=	true,
	[57156]	=	true,	[57172]	=	true,	[57188]	=	true,	[57715]	=	true,	[57220]	=	true,
	[57236]	=	true,	[57268]	=	true,	[58306]	=	true,	[58322]	=	true,	[58338]	=	true,
	[48247]	=	true,	[57133]	=	true,	[57270]	=	true,	[57131]	=	true,	[57129]	=	true,
	[50604]	=	true,	[59488]	=	true,	[59504]	=	true,	[56965]	=	true,	[56981]	=	true,
	[56997]	=	true,	[57013]	=	true,	[57029]	=	true,	[64280]	=	true,	[57114]	=	true,
	[64286]	=	true,	[58299]	=	true,	[57125]	=	true,	[64295]	=	true,	[64311]	=	true,
	[57164]	=	true,	[57189]	=	true,	[57716]	=	true,	[57221]	=	true,	[57237]	=	true,
	[57269]	=	true,	[58307]	=	true,	[58323]	=	true,	[58339]	=	true,	[64307]	=	true,
	[57119]	=	true,	[57246]	=	true,	[68166]	=	true,	[64282]	=	true,	[57250]	=	true,
	[59489]	=	true,	[56957]	=	true,	[56982]	=	true,	[56998]	=	true,	[57014]	=	true,
	[57117]	=	true,	[64305]	=	true,	[61677]	=	true,	[52843]	=	true,	[57126]	=	true,
	[64296]	=	true,	[57158]	=	true,	[64310]	=	true,	[57190]	=	true,	[56956]	=	true,
	[57238]	=	true,	[60336]	=	true,	[58308]	=	true,	[58324]	=	true,	[58340]	=	true,
	[64315]	=	true,	[56949]	=	true,	[56950]	=	true,	[64308]	=	true,	[56955]	=	true,
	[59490]	=	true,	[59315]	=	true,	[56983]	=	true,	[56999]	=	true,	[64267]	=	true,
	[57031]	=	true,	[56954]	=	true,	[64276]	=	true,	[57249]	=	true,	[64249]	=	true,
	[56953]	=	true,	[57127]	=	true,	[64297]	=	true,	[57159]	=	true,	[64275]	=	true,
	[57191]	=	true,	[57207]	=	true,	[57223]	=	true,	[57239]	=	true,	[50612]	=	true,
	[60337]	=	true,	[57208]	=	true,	[58325]	=	true,	[48121]	=	true,	[56952]	=	true,
	[56947]	=	true,	[56951]	=	true,	[64268]	=	true,	[57123]	=	true,	[59475]	=	true,
	[59491]	=	true,	[56968]	=	true,	[56984]	=	true,	[57000]	=	true,	[48248]	=	true,
	[58565]	=	true,	[58317]	=	true,	[64266]	=	true,	[57252]	=	true,	[64250]	=	true,
	[57112]	=	true,	[57128]	=	true,	[64298]	=	true,	[57160]	=	true,	[58316]	=	true,
	[57703]	=	true,	[57719]	=	true,	[57224]	=	true,	[57240]	=	true,	[57272]	=	true,
	[58310]	=	true,	[58326]	=	true,	[58342]	=	true,	[57201]	=	true,	[56945]	=	true,
	[57200]	=	true,	[56944]	=	true,	[57711]	=	true,	[56985]	=	true,	[57001]	=	true,
	[57199]	=	true,	[57033]	=	true,	[56943]	=	true,	[57198]	=	true,	[64251]	=	true,
	[57113]	=	true,	[64283]	=	true,	[64299]	=	true,	[57161]	=	true,	[57197]	=	true,
	[57704]	=	true,	[57209]	=	true,	[57225]	=	true,	[57241]	=	true,	[50614]	=	true,
	[57273]	=	true,	[58311]	=	true,	[58327]	=	true,	[58343]	=	true,	[52738]	=	true,
	[57196]	=	true,	[64278]	=	true,	[57195]	=	true,	[58318]	=	true,	[64284]	=	true,
	[57006]	=	true,	[64316]	=	true,	[56986]	=	true,	[57002]	=	true,	[59560]	=	true,
	[57034]	=	true,	[58341]	=	true,	[57192]	=	true,	[64252]	=	true,	[67600]	=	true,
	[57130]	=	true,	[64300]	=	true,	[57162]	=	true,	[57244]	=	true,	[57194]	=	true,
	[57210]	=	true,	[57226]	=	true,	[50599]	=	true,	[57258]	=	true,	[58296]	=	true,
	[58312]	=	true,	[58328]	=	true,	[58344]	=	true,	[52739]	=	true,	[58298]	=	true,
	[57274]	=	true,	[57265]	=	true,	[57251]	=	true,	[59478]	=	true,	[56971]	=	true,
	[56987]	=	true,	[57003]	=	true,	[57019]	=	true,	[57035]	=	true,	[57259]	=	true,
	[57263]	=	true,	[57271]	=	true,	[64253]	=	true,	[57115]	=	true,	[64285]	=	true,
	[57242]	=	true,	[57163]	=	true,	[57120]	=	true,	[57706]	=	true,	[57211]	=	true,
	[57227]	=	true,	[50600]	=	true,	[50616]	=	true,	[58297]	=	true,	[58313]	=	true,
	[58329]	=	true,	[58345]	=	true,	[50602]	=	true,	[57248]	=	true,	[59559]	=	true,
	[57157]	=	true,	[57257]	=	true,	[64309]	=	true,	[64317]	=	true,	[56972]	=	true,
	[56988]	=	true,	[57004]	=	true,	[57020]	=	true,	[57036]	=	true,	[62162]	=	true,
	[57030]	=	true,	[64254]	=	true,	[57116]	=	true,	[57132]	=	true,	[64302]	=	true,
	[64318]	=	true,	[64270]	=	true,	[57707]	=	true,	[57212]	=	true,	[57228]	=	true,
	[50601]	=	true,	[57260]	=	true,	[57276]	=	true,	[58314]	=	true,	[58330]	=	true,
	[58346]	=	true,	[45382]	=	true,	[57267]	=	true,	[57275]	=	true,	[64312]	=	true,
	[64279]	=	true,	[50598]	=	true,	[59480]	=	true,	[59496]	=	true,	[56973]	=	true,
	[56989]	=	true,	[57005]	=	true,	[57021]	=	true,	[50619]	=	true,	[50618]	=	true,
	[65245]	=	true,	[50617]	=	true,	[64255]	=	true,	[64271]	=	true,	[64287]	=	true,
	[64303]	=	true,	[57165]	=	true,	[57181]	=	true,	[57708]	=	true,	[57213]	=	true,
	[57229]	=	true,	[57245]	=	true,	[57261]	=	true,	[57277]	=	true,	[57253]	=	true,
	[71015]	=	true,	[71101]	=	true,	[71102]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	----ENCHANTING
	---------------------------------------------------------------------------------------
	[46578]	=	true,	[25125]	=	true,	[13612]	=	true,	[13620]	=	true,	[13628]	=	true,
	[13640]	=	true,	[13644]	=	true,	[13648]	=	true,	[59625]	=	true,	[13700]	=	true,
	[17181]	=	true,	[27920]	=	true,	[27960]	=	true,	[28016]	=	true,	[45765]	=	true,
	[14810]	=	true,	[63746]	=	true,	[13836]	=	true,	[20008]	=	true,	[20032]	=	true,
	[13868]	=	true,	[13421]	=	true,	[13948]	=	true,	[27905]	=	true,	[27945]	=	true,
	[13501]	=	true,	[7786]	=	true,	[7788]	=	true,	[13529]	=	true,	[32664]	=	true,
	[44506]	=	true,	[25127]	=	true,	[20025]	=	true,	[20033]	=	true,	[13617]	=	true,
	[64579]	=	true,	[60619]	=	true,	[13657]	=	true,	[13693]	=	true,	[27914]	=	true,
	[44555]	=	true,	[27954]	=	true,	[27962]	=	true,	[14807]	=	true,	[32665]	=	true,
	[7421]	=	true,	[13817]	=	true,	[25072]	=	true,	[44492]	=	true,	[44524]	=	true,
	[7443]	=	true,	[44556]	=	true,	[25128]	=	true,	[20026]	=	true,	[7457]	=	true,
	[13378]	=	true,	[34001]	=	true,	[13917]	=	true,	[13933]	=	true,	[13937]	=	true,
	[13941]	=	true,	[44621]	=	true,	[28003]	=	true,	[28027]	=	true,	[13522]	=	true,
	[13538]	=	true,	[25081]	=	true,	[44494]	=	true,	[20011]	=	true,	[25129]	=	true,
	[44590]	=	true,	[47672]	=	true,	[20051]	=	true,	[13622]	=	true,	[13626]	=	true,
	[69412]	=	true,	[60623]	=	true,	[44383]	=	true,	[13698]	=	true,	[13702]	=	true,
	[23804]	=	true,	[44623]	=	true,	[28004]	=	true,	[28028]	=	true,	[14293]	=	true,
	[32667]	=	true,	[13822]	=	true,	[25082]	=	true,	[44576]	=	true,	[20028]	=	true,
	[20036]	=	true,	[13890]	=	true,	[13898]	=	true,	[60609]	=	true,	[59619]	=	true,
	[47898]	=	true,	[7745]	=	true,	[27957]	=	true,	[13503]	=	true,	[34006]	=	true,
	[7793]	=	true,	[7795]	=	true,	[59636]	=	true,	[25083]	=	true,	[20029]	=	true,
	[13631]	=	true,	[13655]	=	true,	[7861]	=	true,	[7863]	=	true,	[62256]	=	true,
	[13695]	=	true,	[13858]	=	true,	[44483]	=	true,	[27968]	=	true,	[7857]	=	true,
	[27967]	=	true,	[42615]	=	true,	[27958]	=	true,	[42613]	=	true,	[25084]	=	true,
	[20017]	=	true,	[33992]	=	true,	[34008]	=	true,	[13663]	=	true,	[60653]	=	true,
	[44528]	=	true,	[14809]	=	true,	[27961]	=	true,	[47901]	=	true,	[7418]	=	true,
	[7420]	=	true,	[44488]	=	true,	[7426]	=	true,	[44616]	=	true,	[13841]	=	true,
	[44596]	=	true,	[17180]	=	true,	[7454]	=	true,	[33993]	=	true,	[34009]	=	true,
	[27950]	=	true,	[20031]	=	true,	[13915]	=	true,	[47900]	=	true,	[13943]	=	true,
	[13947]	=	true,	[13945]	=	true,	[13464]	=	true,	[27927]	=	true,	[7771]	=	true,
	[20014]	=	true,	[20030]	=	true,	[27947]	=	true,	[33994]	=	true,	[28022]	=	true,
	[60692]	=	true,	[25130]	=	true,	[34005]	=	true,	[13794]	=	true,	[7748]	=	true,
	[44588]	=	true,	[15596]	=	true,	[7776]	=	true,	[44584]	=	true,	[13607]	=	true,
	[13653]	=	true,	[20020]	=	true,	[70524]	=	true,	[71692]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	---TAILORING
	---------------------------------------------------------------------------------------
	[12055]	=	true,	[12059]	=	true,	[12071]	=	true,	[46131]	=	true,	[23664]	=	true,
	[31433]	=	true,	[31441]	=	true,	[7624]	=	true,	[26403]	=	true,	[24902]	=	true,
	[22866]	=	true,	[56001]	=	true,	[18411]	=	true,	[18419]	=	true,	[18451]	=	true,
	[28208]	=	true,	[6686]	=	true,	[8766]	=	true,	[23665]	=	true,	[8786]	=	true,
	[26747]	=	true,	[56002]	=	true,	[26763]	=	true,	[26779]	=	true,	[31434]	=	true,
	[31450]	=	true,	[60969]	=	true,	[28480]	=	true,	[22867]	=	true,	[56003]	=	true,
	[18404]	=	true,	[18412]	=	true,	[18420]	=	true,	[12044]	=	true,	[63924]	=	true,
	[12056]	=	true,	[12064]	=	true,	[12080]	=	true,	[12084]	=	true,	[23666]	=	true,
	[56004]	=	true,	[26780]	=	true,	[31459]	=	true,	[7892]	=	true,	[60971]	=	true,
	[28481]	=	true,	[22868]	=	true,	[20848]	=	true,	[56005]	=	true,	[18405]	=	true,
	[19435]	=	true,	[26086]	=	true,	[18437]	=	true,	[18453]	=	true,	[27659]	=	true,
	[28210]	=	true,	[40021]	=	true,	[23667]	=	true,	[26773]	=	true,	[26781]	=	true,
	[26759]	=	true,	[8774]	=	true,	[31460]	=	true,	[24903]	=	true,	[3755]	=	true,
	[37882]	=	true,	[3757]	=	true,	[3758]	=	true,	[50194]	=	true,	[18446]	=	true,
	[6692]	=	true,	[28482]	=	true,	[22869]	=	true,	[18439]	=	true,	[20849]	=	true,
	[18440]	=	true,	[2389]	=	true,	[56007]	=	true,	[18455]	=	true,	[6521]	=	true,
	[18445]	=	true,	[18406]	=	true,	[18414]	=	true,	[18422]	=	true,	[12045]	=	true,
	[36318]	=	true,	[18454]	=	true,	[27660]	=	true,	[24091]	=	true,	[12065]	=	true,
	[12069]	=	true,	[12077]	=	true,	[12081]	=	true,	[12085]	=	true,	[27724]	=	true,
	[12093]	=	true,	[40060]	=	true,	[26087]	=	true,	[26749]	=	true,	[31373]	=	true,
	[26750]	=	true,	[26782]	=	true,	[28205]	=	true,	[28209]	=	true,	[36686]	=	true,
	[3813]	=	true,	[2394]	=	true,	[7629]	=	true,	[18438]	=	true,	[7633]	=	true,
	[40023]	=	true,	[49677]	=	true,	[26407]	=	true,	[18452]	=	true,	[7643]	=	true,
	[22870]	=	true,	[26755]	=	true,	[22902]	=	true,	[3869]	=	true,	[55993]	=	true,
	[8789]	=	true,	[3839]	=	true,	[3841]	=	true,	[3844]	=	true,	[18407]	=	true,
	[18415]	=	true,	[3847]	=	true,	[3848]	=	true,	[3851]	=	true,	[3852]	=	true,
	[24092]	=	true,	[3854]	=	true,	[3856]	=	true,	[3857]	=	true,	[8760]	=	true,
	[27725]	=	true,	[8776]	=	true,	[8780]	=	true,	[8784]	=	true,	[3865]	=	true,
	[55994]	=	true,	[3868]	=	true,	[26783]	=	true,	[3871]	=	true,	[3872]	=	true,
	[3873]	=	true,	[31438]	=	true,	[22759]	=	true,	[12091]	=	true,	[8804]	=	true,
	[8772]	=	true,	[18560]	=	true,	[18447]	=	true,	[44950]	=	true,	[60993]	=	true,
	[55899]	=	true,	[55898]	=	true,	[55995]	=	true,	[2385]	=	true,	[21945]	=	true,
	[6688]	=	true,	[12066]	=	true,	[18416]	=	true,	[8465]	=	true,	[12046]	=	true,
	[18448]	=	true,	[3915]	=	true,	[24093]	=	true,	[8489]	=	true,	[2386]	=	true,
	[12078]	=	true,	[12082]	=	true,	[60994]	=	true,	[55900]	=	true,	[2392]	=	true,
	[2393]	=	true,	[23662]	=	true,	[2396]	=	true,	[55996]	=	true,	[2399]	=	true,
	[26784]	=	true,	[2402]	=	true,	[2403]	=	true,	[2406]	=	true,	[31431]	=	true,
	[3864]	=	true,	[8782]	=	true,	[37884]	=	true,	[37883]	=	true,	[26751]	=	true,
	[50647]	=	true,	[8802]	=	true,	[8467]	=	true,	[7893]	=	true,	[40020]	=	true,
	[41208]	=	true,	[22813]	=	true,	[41207]	=	true,	[37873]	=	true,	[2387]	=	true,
	[55997]	=	true,	[26085]	=	true,	[8799]	=	true,	[27658]	=	true,	[8483]	=	true,
	[3914]	=	true,	[18401]	=	true,	[56006]	=	true,	[18441]	=	true,	[18449]	=	true,
	[28207]	=	true,	[55769]	=	true,	[18413]	=	true,	[18421]	=	true,	[46129]	=	true,
	[2963]	=	true,	[2964]	=	true,	[12061]	=	true,	[12086]	=	true,	[23663]	=	true,
	[26745]	=	true,	[55998]	=	true,	[3863]	=	true,	[8764]	=	true,	[31440]	=	true,
	[31448]	=	true,	[12089]	=	true,	[6695]	=	true,	[40024]	=	true,	[60990]	=	true,
	[50644]	=	true,	[8793]	=	true,	[46130]	=	true,	[24901]	=	true,	[3870]	=	true,
	[31437]	=	true,	[44958]	=	true,	[55999]	=	true,	[3845]	=	true,	[6693]	=	true,
	[3866]	=	true,	[18456]	=	true,	[18410]	=	true,	[18418]	=	true,	[2397]	=	true,
	[18434]	=	true,	[18450]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	----LEATHERWORKING
	---------------------------------------------------------------------------------------
	[9198]	=	true,	[23704]	=	true,	[60996]	=	true,	[35549]	=	true,	[22921]	=	true,
	[50958]	=	true,	[10509]	=	true,	[10525]	=	true,	[19053]	=	true,	[19085]	=	true,
	[19101]	=	true,	[2149]	=	true,	[36349]	=	true,	[2153]	=	true,	[60997]	=	true,
	[2159]	=	true,	[2163]	=	true,	[2165]	=	true,	[35582]	=	true,	[50959]	=	true,
	[46132]	=	true,	[23705]	=	true,	[60998]	=	true,	[22922]	=	true,	[46133]	=	true,
	[24121]	=	true,	[19054]	=	true,	[19070]	=	true,	[19086]	=	true,	[19102]	=	true,
	[32465]	=	true,	[32481]	=	true,	[22331]	=	true,	[35520]	=	true,	[35584]	=	true,
	[9207]	=	true,	[6661]	=	true,	[46134]	=	true,	[23706]	=	true,	[61000]	=	true,
	[35521]	=	true,	[35585]	=	true,	[50962]	=	true,	[10518]	=	true,	[39997]	=	true,
	[24122]	=	true,	[19055]	=	true,	[19087]	=	true,	[19103]	=	true,	[32466]	=	true,
	[32482]	=	true,	[36353]	=	true,	[35522]	=	true,	[35554]	=	true,	[50963]	=	true,
	[44953]	=	true,	[46136]	=	true,	[23707]	=	true,	[61002]	=	true,	[35523]	=	true,
	[35555]	=	true,	[35587]	=	true,	[50964]	=	true,	[46137]	=	true,	[24123]	=	true,
	[19072]	=	true,	[19104]	=	true,	[9064]	=	true,	[9072]	=	true,	[69386]	=	true,
	[32499]	=	true,	[36355]	=	true,	[7133]	=	true,	[35524]	=	true,	[35588]	=	true,
	[7153]	=	true,	[9208]	=	true,	[46138]	=	true,	[23708]	=	true,	[69388]	=	true,
	[35525]	=	true,	[35557]	=	true,	[10487]	=	true,	[10511]	=	true,	[46139]	=	true,
	[24124]	=	true,	[19073]	=	true,	[19089]	=	true,	[32468]	=	true,	[32500]	=	true,
	[10647]	=	true,	[28472]	=	true,	[35526]	=	true,	[35558]	=	true,	[45117]	=	true,
	[60622]	=	true,	[23709]	=	true,	[35527]	=	true,	[3774]	=	true,	[3778]	=	true,
	[3780]	=	true,	[40003]	=	true,	[24125]	=	true,	[19058]	=	true,	[19074]	=	true,
	[32485]	=	true,	[32501]	=	true,	[36359]	=	true,	[3816]	=	true,	[3818]	=	true,
	[28473]	=	true,	[35528]	=	true,	[35560]	=	true,	[9193]	=	true,	[40004]	=	true,
	[23710]	=	true,	[8322]	=	true,	[35529]	=	true,	[35561]	=	true,	[50970]	=	true,
	[2881]	=	true,	[10520]	=	true,	[40005]	=	true,	[10544]	=	true,	[10552]	=	true,
	[10560]	=	true,	[19091]	=	true,	[19107]	=	true,	[32454]	=	true,	[32502]	=	true,
	[28474]	=	true,	[35530]	=	true,	[50971]	=	true,	[62448]	=	true,	[7953]	=	true,
	[41157]	=	true,	[36074]	=	true,	[24846]	=	true,	[35531]	=	true,	[22928]	=	true,
	[28219]	=	true,	[41158]	=	true,	[36075]	=	true,	[32487]	=	true,	[32503]	=	true,
	[7126]	=	true,	[9146]	=	true,	[35532]	=	true,	[35564]	=	true,	[9194]	=	true,
	[9202]	=	true,	[24655]	=	true,	[36076]	=	true,	[24847]	=	true,	[35533]	=	true,
	[5244]	=	true,	[10529]	=	true,	[28220]	=	true,	[19093]	=	true,	[32456]	=	true,
	[52733]	=	true,	[2158]	=	true,	[2160]	=	true,	[2162]	=	true,	[2166]	=	true,
	[24848]	=	true,	[35535]	=	true,	[35567]	=	true,	[28221]	=	true,	[19094]	=	true,
	[44359]	=	true,	[57690]	=	true,	[32457]	=	true,	[32473]	=	true,	[32489]	=	true,
	[9147]	=	true,	[35536]	=	true,	[35568]	=	true,	[9195]	=	true,	[41163]	=	true,
	[6703]	=	true,	[24849]	=	true,	[20853]	=	true,	[10482]	=	true,	[10490]	=	true,
	[28222]	=	true,	[10546]	=	true,	[10554]	=	true,	[41164]	=	true,	[10570]	=	true,
	[19095]	=	true,	[57692]	=	true,	[32458]	=	true,	[10650]	=	true,	[35538]	=	true,
	[42731]	=	true,	[24850]	=	true,	[20854]	=	true,	[44970]	=	true,	[28223]	=	true,
	[19048]	=	true,	[19064]	=	true,	[19080]	=	true,	[57694]	=	true,	[9148]	=	true,
	[35540]	=	true,	[35572]	=	true,	[24851]	=	true,	[20855]	=	true,	[45100]	=	true,
	[10531]	=	true,	[28224]	=	true,	[57696]	=	true,	[10619]	=	true,	[19081]	=	true,
	[22727]	=	true,	[35539]	=	true,	[19079]	=	true,	[10566]	=	true,	[19065]	=	true,
	[10574]	=	true,	[19097]	=	true,	[60647]	=	true,	[3753]	=	true,	[9065]	=	true,
	[44343]	=	true,	[3763]	=	true,	[3767]	=	true,	[3773]	=	true,	[3775]	=	true,
	[3777]	=	true,	[3779]	=	true,	[32455]	=	true,	[24940]	=	true,	[19050]	=	true,
	[19082]	=	true,	[23190]	=	true,	[32461]	=	true,	[60999]	=	true,	[3817]	=	true,
	[44344]	=	true,	[9149]	=	true,	[35544]	=	true,	[9197]	=	true,	[19077]	=	true,
	[9060]	=	true,	[19076]	=	true,	[35573]	=	true,	[40001]	=	true,	[19066]	=	true,
	[19090]	=	true,	[19098]	=	true,	[22711]	=	true,	[57699]	=	true,	[9059]	=	true,
	[32480]	=	true,	[64661]	=	true,	[10562]	=	true,	[40002]	=	true,	[50936]	=	true,
	[6705]	=	true,	[9058]	=	true,	[24703]	=	true,	[22923]	=	true,	[60645]	=	true,
	[35577]	=	true,	[2152]	=	true,	[10556]	=	true,	[10572]	=	true,	[44770]	=	true,
	[36077]	=	true,	[19059]	=	true,	[19075]	=	true,	[35580]	=	true,	[20648]	=	true,
	[2169]	=	true,	[60643]	=	true,	[19088]	=	true,	[6702]	=	true,	[6704]	=	true,
	[35543]	=	true,	[7149]	=	true,	[36078]	=	true,	[36079]	=	true,	[23703]	=	true,
	[35534]	=	true,	[57701]	=	true,	[46135]	=	true,	[19047]	=	true,	[20649]	=	true,
	[40006]	=	true,	[3765]	=	true,	[41156]	=	true,	[3771]	=	true,	[50956]	=	true,
	[19061]	=	true,	[20650]	=	true,	[32467]	=	true,	[35537]	=	true,	[22926]	=	true,
	[4096]	=	true,	[19062]	=	true,	[44768]	=	true,	[35576]	=	true,	[19063]	=	true,
	[9062]	=	true,	[9070]	=	true,	[32495]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	-----ALCHEMY
	---------------------------------------------------------------------------------------
	[53898]	=	true,	[28579]	=	true,	[17566]	=	true,	[53771]	=	true,	[7256]	=	true,
	[53899]	=	true,	[11452]	=	true,	[11460]	=	true,	[11468]	=	true,	[3170]	=	true,
	[3172]	=	true,	[3174]	=	true,	[3176]	=	true,	[53836]	=	true,	[53900]	=	true,
	[28564]	=	true,	[28580]	=	true,	[54220]	=	true,	[17551]	=	true,	[53773]	=	true,
	[53837]	=	true,	[62213]	=	true,	[54221]	=	true,	[53774]	=	true,	[53838]	=	true,
	[6617]	=	true,	[53902]	=	true,	[28581]	=	true,	[2331]	=	true,	[2335]	=	true,
	[2337]	=	true,	[53775]	=	true,	[53839]	=	true,	[11453]	=	true,	[7836]	=	true,
	[24266]	=	true,	[41500]	=	true,	[53904]	=	true,	[53936]	=	true,	[28566]	=	true,
	[28582]	=	true,	[3452]	=	true,	[3454]	=	true,	[33732]	=	true,	[17553]	=	true,
	[22732]	=	true,	[53777]	=	true,	[53905]	=	true,	[53937]	=	true,	[33733]	=	true,
	[62409]	=	true,	[25146]	=	true,	[41502]	=	true,	[53938]	=	true,	[28551]	=	true,
	[28567]	=	true,	[28583]	=	true,	[62410]	=	true,	[7181]	=	true,	[17570]	=	true,
	[17634]	=	true,	[53779]	=	true,	[7257]	=	true,	[53939]	=	true,	[11478]	=	true,
	[17187]	=	true,	[53812]	=	true,	[28552]	=	true,	[28568]	=	true,	[28584]	=	true,
	[60366]	=	true,	[57425]	=	true,	[17635]	=	true,	[53781]	=	true,	[60367]	=	true,
	[4508]	=	true,	[53782]	=	true,	[24365]	=	true,	[6618]	=	true,	[53942]	=	true,
	[28569]	=	true,	[28585]	=	true,	[29688]	=	true,	[57427]	=	true,	[17556]	=	true,
	[17572]	=	true,	[17636]	=	true,	[53783]	=	true,	[11479]	=	true,	[7837]	=	true,
	[7841]	=	true,	[53784]	=	true,	[24366]	=	true,	[53848]	=	true,	[28554]	=	true,
	[28570]	=	true,	[28586]	=	true,	[58868]	=	true,	[33741]	=	true,	[24367]	=	true,
	[28555]	=	true,	[28571]	=	true,	[17574]	=	true,	[17638]	=	true,	[7258]	=	true,
	[11448]	=	true,	[11456]	=	true,	[11464]	=	true,	[11480]	=	true,	[3171]	=	true,
	[3173]	=	true,	[3175]	=	true,	[24368]	=	true,	[28572]	=	true,	[28588]	=	true,
	[45061]	=	true,	[66658]	=	true,	[17559]	=	true,	[17575]	=	true,	[66659]	=	true,
	[66660]	=	true,	[63732]	=	true,	[28573]	=	true,	[66662]	=	true,	[17560]	=	true,
	[2330]	=	true,	[2332]	=	true,	[2334]	=	true,	[66663]	=	true,	[11457]	=	true,
	[11465]	=	true,	[11473]	=	true,	[66664]	=	true,	[3449]	=	true,	[3451]	=	true,
	[3453]	=	true,	[17561]	=	true,	[17577]	=	true,	[28543]	=	true,	[28575]	=	true,
	[7179]	=	true,	[17562]	=	true,	[17578]	=	true,	[7255]	=	true,	[7259]	=	true,
	[11458]	=	true,	[11466]	=	true,	[38962]	=	true,	[53776]	=	true,	[12609]	=	true,
	[53780]	=	true,	[60893]	=	true,	[58871]	=	true,	[3448]	=	true,	[3450]	=	true,
	[3447]	=	true,	[4942]	=	true,	[28576]	=	true,	[15833]	=	true,	[17576]	=	true,
	[41503]	=	true,	[60350]	=	true,	[41501]	=	true,	[17563]	=	true,	[42736]	=	true,
	[54213]	=	true,	[41458]	=	true,	[6624]	=	true,	[39636]	=	true,	[28577]	=	true,
	[32765]	=	true,	[38070]	=	true,	[17564]	=	true,	[17580]	=	true,	[53895]	=	true,
	[11451]	=	true,	[39637]	=	true,	[28546]	=	true,	[28562]	=	true,	[28578]	=	true,
	[60354]	=	true,	[32766]	=	true,	[17565]	=	true,	[22808]	=	true,	[39639]	=	true,
	[60355]	=	true,	[56519]	=	true,
	---------------------------------------------------------------------------------------

	---------------------------------------------------------------------------------------
	----ENGINEERING
	---------------------------------------------------------------------------------------
	[23081]	=	true,	[12586]	=	true,	[12594]	=	true,	[12622]	=	true,	[30347]	=	true,
	[44391]	=	true,	[30547]	=	true,	[56464]	=	true,	[12754]	=	true,	[12758]	=	true,
	[23489]	=	true,	[23082]	=	true,	[8243]	=	true,	[9269]	=	true,	[30316]	=	true,
	[30332]	=	true,	[12906]	=	true,	[8339]	=	true,	[26420]	=	true,	[56514]	=	true,
	[39971]	=	true,	[12599]	=	true,	[12603]	=	true,	[12607]	=	true,	[43676]	=	true,
	[12619]	=	true,	[54998]	=	true,	[30349]	=	true,	[56468]	=	true,	[12755]	=	true,
	[12759]	=	true,	[63750]	=	true,	[39973]	=	true,	[56465]	=	true,	[56469]	=	true,
	[30318]	=	true,	[30334]	=	true,	[55016]	=	true,	[12903]	=	true,	[54793]	=	true,
	[19795]	=	true,	[8895]	=	true,	[19819]	=	true,	[30558]	=	true,	[39895]	=	true,
	[23069]	=	true,	[23077]	=	true,	[12596]	=	true,	[30303]	=	true,	[56471]	=	true,
	[12624]	=	true,	[19796]	=	true,	[56472]	=	true,	[12760]	=	true,	[63770]	=	true,
	[23070]	=	true,	[23078]	=	true,	[61471]	=	true,	[30304]	=	true,	[30312]	=	true,
	[12908]	=	true,	[12597]	=	true,	[3930]	=	true,	[24356]	=	true,	[67839]	=	true,
	[67326]	=	true,	[56474]	=	true,	[30560]	=	true,	[30568]	=	true,	[30314]	=	true,
	[3929]	=	true,	[56475]	=	true,	[19830]	=	true,	[3946]	=	true,	[54736]	=	true,
	[30563]	=	true,	[24357]	=	true,	[30337]	=	true,	[12591]	=	true,	[19814]	=	true,
	[60866]	=	true,	[12716]	=	true,	[23071]	=	true,	[23079]	=	true,	[12585]	=	true,
	[3923]	=	true,	[3925]	=	true,	[30305]	=	true,	[12621]	=	true,	[30329]	=	true,
	[3931]	=	true,	[3932]	=	true,	[3933]	=	true,	[3936]	=	true,	[3937]	=	true,
	[3938]	=	true,	[3939]	=	true,	[3941]	=	true,	[56473]	=	true,	[3944]	=	true,
	[3945]	=	true,	[3947]	=	true,	[54999]	=	true,	[3949]	=	true,	[3950]	=	true,
	[26417]	=	true,	[12717]	=	true,	[3954]	=	true,	[3955]	=	true,	[3957]	=	true,
	[3958]	=	true,	[3961]	=	true,	[3962]	=	true,	[3963]	=	true,	[3965]	=	true,
	[3966]	=	true,	[3967]	=	true,	[3968]	=	true,	[3969]	=	true,	[3971]	=	true,
	[3972]	=	true,	[3973]	=	true,	[7430]	=	true,	[3977]	=	true,	[3978]	=	true,
	[3979]	=	true,	[19790]	=	true,	[23080]	=	true,	[12620]	=	true,	[30309]	=	true,
	[30346]	=	true,	[12905]	=	true,	[41307]	=	true,	[8334]	=	true,	[56460]	=	true,
	[56476]	=	true,	[12718]	=	true,	[26418]	=	true,	[19791]	=	true,	[3960]	=	true,
	[19815]	=	true,	[13240]	=	true,	[19831]	=	true,	[30570]	=	true,	[19799]	=	true,
	[30306]	=	true,	[30310]	=	true,	[26011]	=	true,	[36954]	=	true,	[3919]	=	true,
	[3920]	=	true,	[19800]	=	true,	[12617]	=	true,	[30311]	=	true,	[56463]	=	true,
	[72952]	=	true,	[72953]	=	true,
	---------------------------------------------------------------------------------------
}