Quantcast

Okay for right not, forget using submodules on Git.

Xruptor [09-16-16 - 18:00]
Okay for right not, forget using submodules on Git.
-I'll use hardcopies until I can resolve issues with it in the future.  Don't want to deal with WOWInterface packager right now.
-I'll use pkgmeta for curse though.
Filename
.pkgmeta
libs/CustomSearch-1.0
libs/CustomSearch-1.0/.DS_Store
libs/CustomSearch-1.0/CustomSearch-1.0.lua
libs/CustomSearch-1.0/README.md
libs/LibDataBroker-1.1
libs/LibDataBroker-1.1/LibDataBroker-1.1.lua
libs/LibDataBroker-1.1/README.textile
libs/LibItemSearch-1.2
libs/LibItemSearch-1.2/.DS_Store
libs/LibItemSearch-1.2/LibItemSearch-1.2.lua
libs/LibItemSearch-1.2/LibItemSearch-1.2.toc
libs/LibItemSearch-1.2/README.markdown
libs/Unfit-1.0
libs/Unfit-1.0/.gitignore
libs/Unfit-1.0/License.url
libs/Unfit-1.0/Tests.lua
libs/Unfit-1.0/Unfit-1.0.lua
libs/Unfit-1.0/Unfit-1.0.toc
diff --git a/.pkgmeta b/.pkgmeta
new file mode 100644
index 0000000..6fd9bde
--- /dev/null
+++ b/.pkgmeta
@@ -0,0 +1,7 @@
+package-as: BagSync
+
+externals:
+    libs/CustomSearch-1.0: https://github.com/Jaliborc/CustomSearch-1.0.git
+    libs/LibDataBroker-1.1: https://github.com/tekkub/libdatabroker-1-1.git
+    libs/LibItemSearch-1.2: https://github.com/Jaliborc/LibItemSearch-1.2.git
+    libs/Unfit-1.0: https://github.com/Jaliborc/Unfit-1.0.git
diff --git a/libs/CustomSearch-1.0 b/libs/CustomSearch-1.0
deleted file mode 160000
index fe0d78b..0000000
--- a/libs/CustomSearch-1.0
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit fe0d78b4249eab4b2338126deb443777533831de
diff --git a/libs/CustomSearch-1.0/.DS_Store b/libs/CustomSearch-1.0/.DS_Store
new file mode 100644
index 0000000..b95bdac
Binary files /dev/null and b/libs/CustomSearch-1.0/.DS_Store differ
diff --git a/libs/CustomSearch-1.0/CustomSearch-1.0.lua b/libs/CustomSearch-1.0/CustomSearch-1.0.lua
new file mode 100644
index 0000000..f8d4455
--- /dev/null
+++ b/libs/CustomSearch-1.0/CustomSearch-1.0.lua
@@ -0,0 +1,202 @@
+--[[
+Copyright 2013 João Cardoso
+CustomSearch is distributed under the terms of the GNU General Public License (Version 3).
+As a special exception, the copyright holders of this library give you permission to embed it
+with independent modules to produce an addon, regardless of the license terms of these
+independent modules, and to copy and distribute the resulting software under terms of your
+choice, provided that you also meet, for each embedded independent module, the terms and
+conditions of the license of that module. Permission is not granted to modify this library.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the library. If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
+
+This file is part of CustomSearch.
+--]]
+
+local Lib = LibStub:NewLibrary('CustomSearch-1.0', 9)
+if not Lib then
+	return
+end
+
+
+--[[ Parsing ]]--
+
+function Lib:Matches(object, search, filters)
+	if object then
+		self.filters = filters
+		self.object = object
+
+		return self:MatchAll(search or '')
+	end
+end
+
+function Lib:MatchAll(search)
+	for phrase in self:Clean(search):gmatch('[^&]+') do
+		if not self:MatchAny(phrase) then
+      		return
+		end
+	end
+
+	return true
+end
+
+function Lib:MatchAny(search)
+	for phrase in search:gmatch('[^|]+') do
+		if self:Match(phrase) then
+        	return true
+		end
+	end
+end
+
+function Lib:Match(search)
+	local tag, rest = search:match('^%s*(%S+):(.*)$')
+	if tag then
+		tag = '^' .. tag
+		search = rest
+	end
+
+	local words = search:gmatch('%S+')
+	local failed
+
+	for word in words do
+		if word == self.OR then
+			if failed then
+				failed = false
+			else
+				break
+			end
+
+		else
+			local negate, rest = word:match('^([!~]=*)(.*)$')
+			if negate or word == self.NOT_MATCH then
+				word = rest and rest ~= '' and rest or words() or ''
+				negate = -1
+			else
+				negate = 1
+			end
+
+			local operator, rest = word:match('^(=*[<>]=*)(.*)$')
+			if operator then
+				word = rest ~= '' and rest or words()
+			end
+
+			local result = self:Filter(tag, operator, word) and 1 or -1
+			if result * negate ~= 1 then
+				failed = true
+			end
+		end
+	end
+
+	return not failed
+end
+
+
+--[[ Filtering ]]--
+
+function Lib:Filter(tag, operator, search)
+	if not search then
+		return true
+	end
+
+	if tag then
+		for _, filter in pairs(self.filters) do
+			for _, value in pairs(filter.tags or {}) do
+				if value:find(tag) then
+					return self:UseFilter(filter, operator, search)
+				end
+			end
+		end
+	else
+		for _, filter in pairs(self.filters) do
+			if not filter.onlyTags and self:UseFilter(filter, operator, search) then
+				return true
+			end
+		end
+	end
+end
+
+function Lib:UseFilter(filter, operator, search)
+	local data = {filter:canSearch(operator, search, self.object)}
+	if data[1] then
+		return filter:match(self.object, operator, unpack(data))
+	end
+end
+
+
+--[[ Utilities ]]--
+
+function Lib:Find(search, ...)
+	for i = 1, select('#', ...) do
+		local text = select(i, ...)
+		if text and self:Clean(text):find(search) then
+			return true
+		end
+	end
+end
+
+function Lib:Clean(string)
+	string = string:lower()
+	string = string:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', function(c) return '%'..c end)
+
+	for accent, char in pairs(self.ACCENTS) do
+		string = string:gsub(accent, char)
+	end
+
+	return string
+end
+
+function Lib:Compare(op, a, b)
+	if op then
+		if op:find('<') then
+			 if op:find('=') then
+			 	return a <= b
+			 end
+
+			 return a < b
+		end
+
+		if op:find('>')then
+			if op:find('=') then
+			 	return a >= b
+			end
+
+			return a > b
+		end
+	end
+
+	return a == b
+end
+
+
+--[[ Localization ]]--
+
+do
+	local no = {enUS = 'Not', frFR = 'Pas', deDE = 'Nicht'}
+	local accents = {
+		a = {'à','â','ã','å'},
+		e = {'è','é','ê','ê','ë'},
+		i = {'ì', 'í', 'î', 'ï'},
+		o = {'ó','ò','ô','õ'},
+		u = {'ù', 'ú', 'û', 'ü'},
+		c = {'ç'}, n = {'ñ'}
+	}
+
+	Lib.ACCENTS = {}
+	for char, accents in pairs(accents) do
+		for _, accent in ipairs(accents) do
+			Lib.ACCENTS[accent] = char
+		end
+	end
+
+	Lib.OR = Lib:Clean(JUST_OR)
+	Lib.NOT = no[GetLocale()] or NO
+	Lib.NOT_MATCH = Lib:Clean(Lib.NOT)
+	setmetatable(Lib, {__call = Lib.Matches})
+end
+
+return Lib
\ No newline at end of file
diff --git a/libs/CustomSearch-1.0/README.md b/libs/CustomSearch-1.0/README.md
new file mode 100644
index 0000000..2b8dad3
--- /dev/null
+++ b/libs/CustomSearch-1.0/README.md
@@ -0,0 +1,69 @@
+# CustomSearch-1.0
+Framework for building search engines in lua. Handles most of the heavy work for you, such as concept separation,
+non ascii character support, logical operators and user criteria selection.
+
+### API Overview
+|Name|Description|
+|:--|:--|
+| :Matches(article, search, filters) | Returns wether the given `article` matches the `search` query using the `filters` structure as the criteria. |
+| :Find(search, field1, field2, ...) | Returns wether the `search` string is present on any of the string `fields` provided.  |
+| :Compare(operator, a, b) | Returns an inequality operation between `a` and `b`, where `operator` is the string representation of the operation. |
+
+### Filters Specification
+The `filters` data structure allows you to easly build a search engine of your own.
+`filters` is a set of filter objects. Each filter is akin to an independent criteria of the engine:
+if any filter approves the `article` for a given `search` query, the `article` is approved.
+
+For an object to be a filter, it must implement the following fields:
+
+|Name|Description|
+|:--|:--|
+| :canSearch(operator, search, article) | Returns wether the filter can process this query. If not `.match` will not be called and this filter will not be considered for the query. Can return any number of arguments. |
+| :match(article, operator, data1, data2, ...) | Returns wether this filter approves the `article` for a given query. 'data1', 'data2', etc are the return arguments of :canSearch. |
+| .tags | Optional. Array of identifiers that can be placed at the beggining of a `search` query to perform a `:Match` using only this filter. |
+
+### Examples
+    local Lib = LibStub('CustomSearch-1.0')
+
+    Lib:Find('(João)', 'Roses are red', 'Violets are (jóaô)', 'Wait that was wrong') -- true
+    Lib:Find('banana', 'Roses are red', 'Violets are jóaô', 'Wait that was wrong') -- false
+
+    Lib:Compare('<', 3, 4) -- true
+    Lib:Compare('>', 3, 4) -- false
+    Lib:Compare('>=', 5, 5) -- true
+
+    local Filters = {
+      isBanana = {
+        tags = {'b', 'ba'},
+
+        canSearch = function(self, operator, search)
+          return true
+        end,
+
+        match = function(self, article, operator, search)
+          return Lib:Find(article, 'banana')
+        end
+      },
+
+      searchingApple = {
+        tags = {'a', 'app'},
+
+        canSearch = function(self, operator, search)
+          if not operator then
+            return search
+          end
+        end,
+
+        match = function(self, article, operator, search)
+          return Lib:Find(search, 'apple')
+        end
+      }
+    }
+
+    Lib:Match('Banana', '', Filters) -- true
+    Lib:Match('', 'Apple', Filters) -- true
+    Lib:Match('', '> Apple', Filters) -- false
+    Lib:Match('Apple', 'Banana', Filters) -- false
+    Lib:Match('', 'b:Apple', Filters) -- false
+    Lib:Match('', 'a:Apple', Filters) -- true
+
diff --git a/libs/LibDataBroker-1.1 b/libs/LibDataBroker-1.1
deleted file mode 160000
index 1a63ede..0000000
--- a/libs/LibDataBroker-1.1
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 1a63ede0248c11aa1ee415187c1f9c9489ce3e02
diff --git a/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua b/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua
new file mode 100644
index 0000000..f47c0cd
--- /dev/null
+++ b/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua
@@ -0,0 +1,90 @@
+
+assert(LibStub, "LibDataBroker-1.1 requires LibStub")
+assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
+
+local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
+if not lib then return end
+oldminor = oldminor or 0
+
+
+lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
+lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
+local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
+
+if oldminor < 2 then
+	lib.domt = {
+		__metatable = "access denied",
+		__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
+	}
+end
+
+if oldminor < 3 then
+	lib.domt.__newindex = function(self, key, value)
+		if not attributestorage[self] then attributestorage[self] = {} end
+		if attributestorage[self][key] == value then return end
+		attributestorage[self][key] = value
+		local name = namestorage[self]
+		if not name then return end
+		callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
+		callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
+		callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
+		callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
+	end
+end
+
+if oldminor < 2 then
+	function lib:NewDataObject(name, dataobj)
+		if self.proxystorage[name] then return end
+
+		if dataobj then
+			assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
+			self.attributestorage[dataobj] = {}
+			for i,v in pairs(dataobj) do
+				self.attributestorage[dataobj][i] = v
+				dataobj[i] = nil
+			end
+		end
+		dataobj = setmetatable(dataobj or {}, self.domt)
+		self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
+		self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
+		return dataobj
+	end
+end
+
+if oldminor < 1 then
+	function lib:DataObjectIterator()
+		return pairs(self.proxystorage)
+	end
+
+	function lib:GetDataObjectByName(dataobjectname)
+		return self.proxystorage[dataobjectname]
+	end
+
+	function lib:GetNameByDataObject(dataobject)
+		return self.namestorage[dataobject]
+	end
+end
+
+if oldminor < 4 then
+	local next = pairs(attributestorage)
+	function lib:pairs(dataobject_or_name)
+		local t = type(dataobject_or_name)
+		assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
+
+		local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+		assert(attributestorage[dataobj], "Data object not found")
+
+		return next, attributestorage[dataobj], nil
+	end
+
+	local ipairs_iter = ipairs(attributestorage)
+	function lib:ipairs(dataobject_or_name)
+		local t = type(dataobject_or_name)
+		assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
+
+		local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+		assert(attributestorage[dataobj], "Data object not found")
+
+		return ipairs_iter, attributestorage[dataobj], 0
+	end
+end
diff --git a/libs/LibDataBroker-1.1/README.textile b/libs/LibDataBroker-1.1/README.textile
new file mode 100644
index 0000000..ef16fed
--- /dev/null
+++ b/libs/LibDataBroker-1.1/README.textile
@@ -0,0 +1,13 @@
+LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons.
+LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon.
+Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data.
+LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons.
+Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them.
+
+Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table.
+
+h2. Links
+
+* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api
+* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications
+* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb
diff --git a/libs/LibItemSearch-1.2 b/libs/LibItemSearch-1.2
deleted file mode 160000
index 50231da..0000000
--- a/libs/LibItemSearch-1.2
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 50231da80984e21f894f3ced0bea4480907f632f
diff --git a/libs/LibItemSearch-1.2/.DS_Store b/libs/LibItemSearch-1.2/.DS_Store
new file mode 100644
index 0000000..126778d
Binary files /dev/null and b/libs/LibItemSearch-1.2/.DS_Store differ
diff --git a/libs/LibItemSearch-1.2/LibItemSearch-1.2.lua b/libs/LibItemSearch-1.2/LibItemSearch-1.2.lua
new file mode 100644
index 0000000..a754bf8
--- /dev/null
+++ b/libs/LibItemSearch-1.2/LibItemSearch-1.2.lua
@@ -0,0 +1,276 @@
+--[[
+	ItemSearch
+		An item text search engine of some sort
+--]]
+
+local Search = LibStub('CustomSearch-1.0')
+local Unfit = LibStub('Unfit-1.0')
+local Lib = LibStub:NewLibrary('LibItemSearch-1.2', 13)
+if Lib then
+	Lib.Filters = {}
+else
+	return
+end
+
+
+--[[ User API ]]--
+
+function Lib:Matches(link, search)
+	return Search(link, search, self.Filters)
+end
+
+function Lib:Tooltip(link, search)
+	return link and self.Filters.tip:match(link, nil, search)
+end
+
+function Lib:TooltipPhrase(link, search)
+	return link and self.Filters.tipPhrases:match(link, nil, search)
+end
+
+function Lib:InSet(link, search)
+	if IsEquippableItem(link) then
+		local id = tonumber(link:match('item:(%-?%d+)'))
+		return self:BelongsToSet(id, (search or ''):lower())
+	end
+end
+
+
+--[[ Basics ]]--
+
+Lib.Filters.name = {
+  	tags = {'n', 'name'},
+
+	canSearch = function(self, operator, search)
+		return not operator and search
+	end,
+
+	match = function(self, item, _, search)
+		local name = item:match('%[(.-)%]')
+		return Search:Find(search, name)
+	end
+}
+
+Lib.Filters.type = {
+	tags = {'t', 'type', 's', 'slot'},
+
+	canSearch = function(self, operator, search)
+		return not operator and search
+	end,
+
+	match = function(self, item, _, search)
+		local type, subType, _, equipSlot = select(6, GetItemInfo(item))
+		return Search:Find(search, type, subType, _G[equipSlot])
+	end
+}
+
+Lib.Filters.level = {
+	tags = {'l', 'level', 'lvl', 'ilvl'},
+
+	canSearch = function(self, _, search)
+		return tonumber(search)
+	end,
+
+	match = function(self, link, operator, num)
+		local lvl = select(4, GetItemInfo(link))
+		if lvl then
+			return Search:Compare(operator, lvl, num)
+		end
+	end
+}
+
+Lib.Filters.requiredlevel = {
+	tags = {'r', 'req', 'rl', 'reql', 'reqlvl'},
+
+	canSearch = function(self, _, search)
+		return tonumber(search)
+	end,
+
+	match = function(self, link, operator, num)
+		local lvl = select(5, GetItemInfo(link))
+		if lvl then
+			return Search:Compare(operator, lvl, num)
+		end
+	end
+}
+
+
+--[[ Quality ]]--
+
+local qualities = {}
+for i = 0, #ITEM_QUALITY_COLORS do
+	qualities[i] = _G['ITEM_QUALITY' .. i .. '_DESC']:lower()
+end
+
+Lib.Filters.quality = {
+	tags = {'q', 'quality'},
+
+	canSearch = function(self, _, search)
+		for i, name in pairs(qualities) do
+		  if name:find(search) then
+			return i
+		  end
+		end
+	end,
+
+	match = function(self, link, operator, num)
+		local quality = link:sub(1, 9) == 'battlepet' and tonumber(link:match('%d+:%d+:(%d+)')) or select(3, GetItemInfo(link))
+		return Search:Compare(operator, quality, num)
+	end,
+}
+
+
+--[[ Usable ]]--
+
+Lib.Filters.usable = {
+	tags = {},
+
+	canSearch = function(self, operator, search)
+		return not operator and search == 'usable'
+	end,
+
+	match = function(self, link)
+		if not Unfit:IsItemUnusable(link) then
+			local lvl = select(5, GetItemInfo(link))
+			return lvl and (lvl == 0 or lvl > UnitLevel('player'))
+		end
+	end
+}
+
+
+--[[ Tooltip Searches ]]--
+
+local scanner = LibItemSearchTooltipScanner or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
+
+Lib.Filters.tip = {
+	tags = {'tt', 'tip', 'tooltip'},
+	onlyTags = true,
+
+	canSearch = function(self, _, search)
+		return search
+	end,
+
+	match = function(self, link, _, search)
+		if link:find('item:') then
+			scanner:SetOwner(UIParent, 'ANCHOR_NONE')
+			scanner:SetHyperlink(link)
+
+			for i = 1, scanner:NumLines() do
+				if Search:Find(search, _G[scanner:GetName() .. 'TextLeft' .. i]:GetText()) then
+					return true
+				end
+			end
+		end
+	end
+}
+
+Lib.Filters.tipPhrases = {
+	canSearch = function(self, _, search)
+		return self.keywords[search]
+	end,
+
+	match = function(self, link, _, search)
+		local id = link:match('item:(%d+)')
+		if not id then
+			return
+		end
+
+		local cached = self.cache[search][id]
+		if cached ~= nil then
+			return cached
+		end
+
+		scanner:SetOwner(UIParent, 'ANCHOR_NONE')
+		scanner:SetHyperlink(link)
+
+		local matches = false
+		for i = 1, scanner:NumLines() do
+			if search == _G['LibItemSearchTooltipScannerTextLeft' .. i]:GetText() then
+				matches = true
+				break
+			end
+		end
+
+		self.cache[search][id] = matches
+		return matches
+	end,
+
+	cache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end}),
+	keywords = {
+    	[ITEM_SOULBOUND:lower()] = ITEM_BIND_ON_PICKUP,
+    	['bound'] = ITEM_BIND_ON_PICKUP,
+    	['bop'] = ITEM_BIND_ON_PICKUP,
+		['boe'] = ITEM_BIND_ON_EQUIP,
+		['bou'] = ITEM_BIND_ON_USE,
+		['boa'] = ITEM_BIND_TO_BNETACCOUNT,
+		[GetItemClassInfo(LE_ITEM_CLASS_QUESTITEM):lower()] = ITEM_BIND_QUEST,
+		[QUESTS_LABEL:lower()] = ITEM_BIND_QUEST,
+		[TOY:lower()] = TOY,
+		[MINIMAP_TRACKING_VENDOR_REAGENT:lower()] = PROFESSIONS_USED_IN_COOKING,
+		['reagent'] = PROFESSIONS_USED_IN_COOKING,
+		['crafting'] = PROFESSIONS_USED_IN_COOKING,
+		['naval'] = 'naval equipment',
+		['follower'] = 'follower',
+		['followe'] = 'follower',
+		['follow'] = 'follower',
+	}
+}
+
+
+--[[ Equipment Sets ]]--
+
+if IsAddOnLoaded('ItemRack') then
+	local sameID = ItemRack.SameID
+
+	function Lib:BelongsToSet(id, search)
+		for name, set in pairs(ItemRackUser.Sets) do
+			if name:sub(1,1) ~= '' and Search:Find(search, name) then
+				for _, item in pairs(set.equip) do
+					if sameID(id, item) then
+						return true
+					end
+				end
+			end
+		end
+	end
+
+elseif IsAddOnLoaded('Wardrobe') then
+	function Lib:BelongsToSet(id, search)
+		for _, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do
+			local name = outfit.OutfitName
+			if Search:Find(search, name) then
+				for _, item in pairs(outfit.Item) do
+					if item.IsSlotUsed == 1 and item.ItemID == id then
+						return true
+					end
+				end
+			end
+		end
+	end
+
+else
+	function Lib:BelongsToSet(id, search)
+		for i = 1, GetNumEquipmentSets() do
+			local name = GetEquipmentSetInfo(i)
+			if Search:Find(search, name) then
+				local items = GetEquipmentSetItemIDs(name)
+				for _, item in pairs(items) do
+					if id == item then
+						return true
+					end
+				end
+			end
+		end
+	end
+end
+
+Lib.Filters.sets = {
+	tags = {'s', 'set'},
+
+	canSearch = function(self, operator, search)
+		return not operator and search
+	end,
+
+	match = function(self, link, _, search)
+		return Lib:InSet(link, search)
+	end,
+}
\ No newline at end of file
diff --git a/libs/LibItemSearch-1.2/LibItemSearch-1.2.toc b/libs/LibItemSearch-1.2/LibItemSearch-1.2.toc
new file mode 100644
index 0000000..3d148de
--- /dev/null
+++ b/libs/LibItemSearch-1.2/LibItemSearch-1.2.toc
@@ -0,0 +1,8 @@
+## Interface: 70000
+## Title: LibItemSearch
+## Notes: An item search library
+## OptionalDeps: LibStub, Unfit-1.0, CustomSearch-1.0, ItemRack, Wardrobe
+## Author: Jaliborc (João Cardoso), Tuller, Yewbacca
+## LoadOnDemand: 1
+
+LibItemSearch-1.2.lua
\ No newline at end of file
diff --git a/libs/LibItemSearch-1.2/README.markdown b/libs/LibItemSearch-1.2/README.markdown
new file mode 100644
index 0000000..5c88ae3
--- /dev/null
+++ b/libs/LibItemSearch-1.2/README.markdown
@@ -0,0 +1,5 @@
+### A search engine for World of Warcraft items
+
+For information regarding the search syntax, see [this page](https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax).
+
+Requires [LibStub](http://www.wowace.com/addons/libstub/) and [CustomSearch](https://github.com/Jaliborc/CustomSearch-1.0).
\ No newline at end of file
diff --git a/libs/Unfit-1.0 b/libs/Unfit-1.0
deleted file mode 160000
index d769a30..0000000
--- a/libs/Unfit-1.0
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit d769a3050a9c2c2f84a88a4cf12cb0135993df52
diff --git a/libs/Unfit-1.0/.gitignore b/libs/Unfit-1.0/.gitignore
new file mode 100644
index 0000000..ae649c2
--- /dev/null
+++ b/libs/Unfit-1.0/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store*
+Icon?
\ No newline at end of file
diff --git a/libs/Unfit-1.0/License.url b/libs/Unfit-1.0/License.url
new file mode 100644
index 0000000..9bf56c7
--- /dev/null
+++ b/libs/Unfit-1.0/License.url
@@ -0,0 +1,2 @@
+[InternetShortcut]
+URL=http://www.gnu.org/licenses/gpl-3.0.txt
diff --git a/libs/Unfit-1.0/Tests.lua b/libs/Unfit-1.0/Tests.lua
new file mode 100644
index 0000000..8449256
--- /dev/null
+++ b/libs/Unfit-1.0/Tests.lua
@@ -0,0 +1,14 @@
+if not WoWUnit then
+	return
+end
+
+local Tests = WoWUnit('Unfit', 'PLAYER_LOGIN', 'GET_ITEM_INFO_RECEIVED')
+local Replace, IsFalse, IsTrue = WoWUnit.Replace, WoWUnit.IsFalse, WoWUnit.IsTrue
+local Unfit = LibStub('Unfit-1.0')
+
+function Tests:Leather()
+	Replace(Unfit.unusable, 'Leather', true)
+
+	IsFalse(Unfit:IsItemUnusable(2318)) -- light leather
+	IsTrue(Unfit:IsItemUnusable(6085)) -- leather chest
+end
\ No newline at end of file
diff --git a/libs/Unfit-1.0/Unfit-1.0.lua b/libs/Unfit-1.0/Unfit-1.0.lua
new file mode 100644
index 0000000..0f668a9
--- /dev/null
+++ b/libs/Unfit-1.0/Unfit-1.0.lua
@@ -0,0 +1,127 @@
+--[[
+Copyright 2011-2015 João Cardoso
+Unfit is distributed under the terms of the GNU General Public License (Version 3).
+As a special exception, the copyright holders of this library give you permission to embed it
+with independent modules to produce an addon, regardless of the license terms of these
+independent modules, and to copy and distribute the resulting software under terms of your
+choice, provided that you also meet, for each embedded independent module, the terms and
+conditions of the license of that module. Permission is not granted to modify this library.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the library. If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
+
+This file is part of Unfit.
+--]]
+
+local Lib = LibStub:NewLibrary('Unfit-1.0', 9)
+if not Lib then
+	return
+end
+
+
+--[[ Data ]]--
+
+do
+	local _, Class = UnitClass('player')
+	local Unusable
+
+	if Class == 'DEATHKNIGHT' then
+		Unusable = { -- weapon, armor, dual-wield
+			{LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_STAFF,LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_DAGGER, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_SHIELD}
+		}
+	elseif Class == 'DEMONHUNTER' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_STAFF, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
+		}
+	elseif Class == 'DRUID' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_SWORD1H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
+			true
+		}
+	elseif Class == 'HUNTER' then
+		Unusable = {
+			{LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
+		}
+	elseif Class == 'MAGE' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW},
+			{LE_ITEM_ARMOR_LEATHER, LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
+			true
+		}
+	elseif Class == 'MONK' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_DAGGER, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
+		}
+	elseif Class == 'PALADIN' then
+		Unusable = {
+			{LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_STAFF, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_DAGGER, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
+			{},
+			true
+		}
+	elseif Class == 'PRIEST' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD1H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW},
+			{LE_ITEM_ARMOR_LEATHER, LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
+			true
+		}
+	elseif Class == 'ROGUE' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_STAFF, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD}
+		}
+	elseif Class == 'SHAMAN' then
+		Unusable = {
+			{LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD1H, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW, LE_ITEM_WEAPON_WAND},
+			{LE_ITEM_ARMOR_PLATEM}
+		}
+	elseif Class == 'WARLOCK' then
+		Unusable = {
+			{LE_ITEM_WEAPON_AXE1H, LE_ITEM_WEAPON_AXE2H, LE_ITEM_WEAPON_BOWS, LE_ITEM_WEAPON_GUNS, LE_ITEM_WEAPON_MACE1H, LE_ITEM_WEAPON_MACE2H, LE_ITEM_WEAPON_POLEARM, LE_ITEM_WEAPON_SWORD2H, LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_UNARMED, LE_ITEM_WEAPON_THROWN, LE_ITEM_WEAPON_CROSSBOW},
+			{LE_ITEM_ARMOR_LEATHER, LE_ITEM_ARMOR_MAIL, LE_ITEM_ARMOR_PLATE, LE_ITEM_ARMOR_SHIELD},
+			true
+		}
+	elseif Class == 'WARRIOR' then
+		Unusable = {{LE_ITEM_WEAPON_WARGLAIVE, LE_ITEM_WEAPON_WAND}, {}}
+	else
+		Unusable = {{}, {}}
+	end
+
+
+	Lib.unusable = {}
+	Lib.cannotDual = Unusable[3]
+
+	for i, class in ipairs({LE_ITEM_CLASS_WEAPON, LE_ITEM_CLASS_ARMOR}) do
+		local list = {}
+		for _, subclass in ipairs(Unusable[i]) do
+			list[subclass] = true
+		end
+
+		Lib.unusable[class] = list
+	end
+end
+
+
+--[[ API ]]--
+
+function Lib:IsItemUnusable(...)
+	if ... then
+		local slot, _,_, class, subclass = select(9, GetItemInfo(...))
+		return Lib:IsClassUnusable(class, subclass, slot)
+	end
+end
+
+function Lib:IsClassUnusable(class, subclass, slot)
+	if class and subclass and Lib.unusable[class] then
+		return slot ~= '' and Lib.unusable[class][subclass] or slot == 'INVTYPE_WEAPONOFFHAND' and Lib.cannotDual
+	end
+end
diff --git a/libs/Unfit-1.0/Unfit-1.0.toc b/libs/Unfit-1.0/Unfit-1.0.toc
new file mode 100644
index 0000000..997ec52
--- /dev/null
+++ b/libs/Unfit-1.0/Unfit-1.0.toc
@@ -0,0 +1,8 @@
+## Interface: 50400
+## Title: Unfit-1.0
+## Notes: Determines which items are usable or not for the player's class.
+## Author: João Cardoso (Jaliborc)
+## OptionalDeps: LibStub
+## X-Category: Library
+
+Unfit-1.0.lua
\ No newline at end of file