Quantcast

Trying to resolve a pause of the WOW Client whenever a BagSync search is done.

Xruptor [10-22-16 - 12:52]
Trying to resolve a pause of the WOW Client whenever a BagSync search is done.
-Apparently the LibItemSearch-1.2 library is causing a long pause every time a search string is given to it.  It only seems to happen when there are large amounts of queries being tossed at it.
-The LibItemSearch-1.2 library also doesn't seem to cache search routines like the old LibItemSearch-1.0 used to do properly.  So even a refresh or a search of the same item causes the BagSync Search window to pause the WOW Client for a brief period.
-The old LibItemSearch-1.0 seems to work and although it causes the pause it's very short compared to the new LibItemSearch-1.2 version.  It also breezes through searches that have already been performed.  I'm going to continue the old LibItemSearch-1.0 under a new name and give this a try.
Filename
BagSync.lua
BagSync.toc
libs/CustomSearch-1.0/.DS_Store
libs/CustomSearch-1.0/CustomSearch-1.0.lua
libs/CustomSearch-1.0/README.md
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/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.lua
libs/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.toc
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
modules/search.lua
diff --git a/BagSync.lua b/BagSync.lua
index c456345..8299abe 100644
--- a/BagSync.lua
+++ b/BagSync.lua
@@ -13,12 +13,6 @@ local BSYC = select(2, ...) --grab the addon namespace
 BSYC = LibStub("AceAddon-3.0"):NewAddon(BSYC, "BagSync", "AceEvent-3.0", "AceConsole-3.0")
 local L = LibStub("AceLocale-3.0"):GetLocale("BagSync", true)

-local strsub, strsplit, strlower, strmatch, strtrim, gsub, strrep = string.sub, string.split, string.lower, string.match, string.trim, string.gsub, string.rep
-local format, tonumber, tostring, tostringall = string.format, tonumber, tostring, tostringall
-local tsort, tinsert, unpack = table.sort, table.insert, unpack
-local select, pairs, next, type = select, pairs, next, type
-local error, assert = error, assert
-
 local debugf = tekDebug and tekDebug:GetFrame("BagSync")

 function BSYC:Debug(...)
diff --git a/BagSync.toc b/BagSync.toc
index 8f30958..01fb258 100644
--- a/BagSync.toc
+++ b/BagSync.toc
@@ -14,9 +14,7 @@ libs\AceConfig-3.0\AceConfig-3.0.xml
 libs\AceLocale-3.0\AceLocale-3.0.xml
 libs\AceConsole-3.0\AceConsole-3.0.xml
 libs\AceEvent-3.0\AceEvent-3.0.xml
-libs\Unfit-1.0\Unfit-1.0.lua
-libs\CustomSearch-1.0\CustomSearch-1.0.lua
-libs\LibItemSearch-1.2\LibItemSearch-1.2.lua
+libs\LibItemSearchGrid-1.0\LibItemSearchGrid-1.0.lua
 libs\LibDataBroker-1.1\LibDataBroker-1.1.lua

 widgets\BagSyncInteractiveLabel.lua
diff --git a/libs/CustomSearch-1.0/.DS_Store b/libs/CustomSearch-1.0/.DS_Store
deleted file mode 100644
index b95bdac..0000000
Binary files a/libs/CustomSearch-1.0/.DS_Store and /dev/null differ
diff --git a/libs/CustomSearch-1.0/CustomSearch-1.0.lua b/libs/CustomSearch-1.0/CustomSearch-1.0.lua
deleted file mode 100644
index f8d4455..0000000
--- a/libs/CustomSearch-1.0/CustomSearch-1.0.lua
+++ /dev/null
@@ -1,202 +0,0 @@
---[[
-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
deleted file mode 100644
index 2b8dad3..0000000
--- a/libs/CustomSearch-1.0/README.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# 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/LibItemSearch-1.2/.DS_Store b/libs/LibItemSearch-1.2/.DS_Store
deleted file mode 100644
index 126778d..0000000
Binary files a/libs/LibItemSearch-1.2/.DS_Store and /dev/null differ
diff --git a/libs/LibItemSearch-1.2/LibItemSearch-1.2.lua b/libs/LibItemSearch-1.2/LibItemSearch-1.2.lua
deleted file mode 100644
index a754bf8..0000000
--- a/libs/LibItemSearch-1.2/LibItemSearch-1.2.lua
+++ /dev/null
@@ -1,276 +0,0 @@
---[[
-	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
deleted file mode 100644
index 3d148de..0000000
--- a/libs/LibItemSearch-1.2/LibItemSearch-1.2.toc
+++ /dev/null
@@ -1,8 +0,0 @@
-## 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
deleted file mode 100644
index 5c88ae3..0000000
--- a/libs/LibItemSearch-1.2/README.markdown
+++ /dev/null
@@ -1,5 +0,0 @@
-### 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/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.lua b/libs/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.lua
new file mode 100644
index 0000000..19cf942
--- /dev/null
+++ b/libs/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.lua
@@ -0,0 +1,525 @@
+--[[
+	NOTE: This is an updated/continuation of Tullers original LibItemSearch-1.0 code.  Since there already is a LibItemSearch-1.2, this library was renamed in order to prevent
+	confusion from any future updates to the updated LibItemSearch-1.2 code by Jaliborc.  That way this code can be updated seperatly from LibItemSearch-1.2
+	Original source credit goes to Jaliborc (João Libório), Tuller, Yewbacca (Equipment Set Searching) for the work on the original LibItemSearch-1.0 code.
+
+	ItemSearch
+		An item text search engine of some sort
+
+	Grammar:
+		<search> 			:=	<intersect search>
+		<intersect search> 	:=	<union search> & <union search> ; <union search>
+		<union search>		:=	<negatable search>  | <negatable search> ; <negatable search>
+		<negatable search> 	:=	!<primitive search> ; <primitive search>
+		<primitive search>	:=	<tooltip search> ; <quality search> ; <type search> ; <text search>
+		<tooltip search>	:=  bop ; boa ; bou ; boe ; quest
+		<quality search>	:=	q<op><text> ; q<op><digit>
+		<ilvl search>		:=	ilvl<op><number>
+		<type search>		:=	t:<text>
+		<text search>		:=	<text>
+		<item set search>	:=	s:<setname> (setname can be * for all sets)
+		<op>				:=  : | = | == | != | ~= | < | > | <= | >=
+--]]
+
+local Lib = LibStub:NewLibrary('LibItemSearchGrid-1.0', 1)
+if not Lib then
+  return
+else
+  Lib.searchTypes = Lib.searchTypes or {}
+end
+
+
+--[[ Locals ]]--
+
+local tonumber, select, split = tonumber, select, strsplit
+local function useful(a) -- check if the search has a decent size
+  return a and #a >= 1
+end
+
+local function compare(op, a, b)
+  if op == '<=' then
+    return a <= b
+  end
+
+  if op == '<' then
+    return a < b
+  end
+
+  if op == '>' then
+    return a > b
+  end
+
+  if op == '>=' then
+    return a >= b
+  end
+
+  return a == b
+end
+
+local function match(search, ...)
+  for i = 1, select('#', ...) do
+    local text = select(i, ...)
+    if text and text:lower():find(search) then
+      return true
+    end
+  end
+  return false
+end
+
+
+--[[ User API ]]--
+
+function Lib:Find(itemLink, search)
+	if not useful(search) then
+		return true
+	end
+
+	if not itemLink then
+		return false
+	end
+
+  return self:FindUnionSearch(itemLink, split('\124', search:lower()))
+end
+
+
+--[[ Top-Layer Processing ]]--
+
+-- union search: <search>&<search>
+function Lib:FindUnionSearch(item, ...)
+	for i = 1, select('#', ...) do
+		local search = select(i, ...)
+		if useful(search) and self:FindIntersectSearch(item, split('\038', search)) then
+      		return true
+		end
+	end
+end
+
+
+-- intersect search: <search>|<search>
+function Lib:FindIntersectSearch(item, ...)
+	for i = 1, select('#', ...) do
+		local search = select(i, ...)
+		if useful(search) and not self:FindNegatableSearch(item, search) then
+        	return false
+		end
+	end
+	return true
+end
+
+
+-- negated search: !<search>
+function Lib:FindNegatableSearch(item, search)
+  local negatedSearch = search:match('^[!~][%s]*(.+)$')
+  if negatedSearch then
+    return not self:FindTypedSearch(item, negatedSearch)
+  end
+  return self:FindTypedSearch(item, search, true)
+end
+
+
+--[[
+     Search Types:
+      easly defined search types
+
+      A typed search object should look like the following:
+        {
+          string id
+            unique identifier for the search type,
+
+          string searchCapture = function canSearch(self, search)
+            returns a capture if the given search matches this typed search
+
+          bool isMatch = function findItem(self, itemLink, searchCapture)
+            returns true if <itemLink> is in the search defined by <searchCapture>
+          }
+--]]
+
+function Lib:RegisterTypedSearch(object)
+	self.searchTypes[object.id] = object
+end
+
+function Lib:GetTypedSearches()
+	return pairs(self.searchTypes)
+end
+
+function Lib:GetTypedSearch(id)
+	return self.searchTypes[id]
+end
+
+function Lib:FindTypedSearch(item, search, default)
+  if not useful(search) then
+    return default
+  end
+
+  local tag, rest = search:match('^[%s]*(%w+):(.*)$')
+  if tag then
+    if useful(rest) then
+      search = rest
+    else
+      return default
+    end
+  end
+
+  local operator, search = search:match('^[%s]*([%>%<%=]*)[%s]*(.*)$')
+  if useful(search) then
+    operator = useful(operator) and operator
+  else
+    return default
+  end
+
+  if tag then
+    tag = '^' .. tag
+    for id, searchType in self:GetTypedSearches() do
+      if searchType.tags then
+        for _, value in pairs(searchType.tags) do
+          if value:find(tag) then
+            return self:UseTypedSearch(searchType, item, operator, search)
+          end
+        end
+      end
+    end
+  else
+    for id, searchType in self:GetTypedSearches() do
+      if not searchType.onlyTags and self:UseTypedSearch(searchType, item, operator, search) then
+        return true
+      end
+    end
+    return false
+  end
+
+  return default
+end
+
+function Lib:UseTypedSearch(searchType, item, operator, search)
+  local capture1, capture2, capture3 = searchType:canSearch(operator, search)
+  if capture1 then
+    if searchType:findItem(item, operator, capture1, capture2, capture3) then
+      return true
+    end
+  end
+end
+
+
+--[[ Item name ]]--
+
+Lib:RegisterTypedSearch{
+  id = 'itemName',
+  tags = {'n', 'name'},
+
+	canSearch = function(self, operator, search)
+		return not operator and search
+	end,
+
+	findItem = function(self, item, _, search)
+		local name = item:match('%[(.-)%]')
+		return match(search, name)
+	end
+}
+
+
+--[[ Item type, subtype and equiploc ]]--
+
+Lib:RegisterTypedSearch{
+	id = 'itemType',
+	tags = {'t', 'type', 'slot'},
+
+	canSearch = function(self, operator, search)
+		return not operator and search
+	end,
+
+	findItem = function(self, item, _, search)
+		local type, subType, _, equipSlot = select(6, GetItemInfo(item))
+		return match(search, type, subType, _G[equipSlot])
+	end
+}
+
+
+--[[ Item quality ]]--
+
+local qualities = {}
+for i = 0, #ITEM_QUALITY_COLORS do
+  qualities[i] = _G['ITEM_QUALITY' .. i .. '_DESC']:lower()
+end
+
+Lib:RegisterTypedSearch{
+	id = 'itemQuality',
+	tags = {'q', 'quality'},
+
+	canSearch = function(self, _, search)
+		for i, name in pairs(qualities) do
+		  if name:find(search) then
+			return i
+		  end
+		end
+	end,
+
+	findItem = function(self, link, operator, num)
+		local quality = select(3, GetItemInfo(link))
+		return compare(operator, quality, num)
+	end,
+}
+
+
+--[[ Item level ]]--
+
+Lib:RegisterTypedSearch{
+	id = 'itemLevel',
+	tags = {'l', 'level', 'lvl'},
+
+	canSearch = function(self, _, search)
+		return tonumber(search)
+	end,
+
+	findItem = function(self, link, operator, num)
+		local lvl = select(4, GetItemInfo(link))
+		if lvl then
+			return compare(operator, lvl, num)
+		end
+	end,
+}
+
+
+--[[ Tooltip searches ]]--
+
+local tooltipCache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end})
+local tooltipScanner = _G['LibItemSearchTooltipScanner'] or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
+
+local function link_FindSearchInTooltip(itemLink, search)
+	local itemID = itemLink:match('item:(%d+)')
+	if not itemID then
+		return
+	end
+
+	local cachedResult = tooltipCache[search][itemID]
+	if cachedResult ~= nil then
+		return cachedResult
+	end
+
+	tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE')
+	tooltipScanner:SetHyperlink(itemLink)
+
+	local result = false
+	if tooltipScanner:NumLines() > 1 and _G[tooltipScanner:GetName() .. 'TextLeft2']:GetText() == search then
+		result = true
+	elseif tooltipScanner:NumLines() > 2 and _G[tooltipScanner:GetName() .. 'TextLeft3']:GetText() == search then
+		result = true
+	end
+
+	tooltipCache[search][itemID] = result
+	return result
+end
+
+
+Lib:RegisterTypedSearch{
+	id = 'bindType',
+
+	canSearch = function(self, _, search)
+		return self.keywords[search]
+	end,
+
+	findItem = function(self, itemLink, _, search)
+		return search and link_FindSearchInTooltip(itemLink, search)
+	end,
+
+	keywords = {
+    		['soulbound'] = ITEM_BIND_ON_PICKUP,
+    		['bound'] = ITEM_BIND_ON_PICKUP,
+		['boe'] = ITEM_BIND_ON_EQUIP,
+		['bop'] = ITEM_BIND_ON_PICKUP,
+		['bou'] = ITEM_BIND_ON_USE,
+		['quest'] = ITEM_BIND_QUEST,
+		['boa'] = ITEM_BIND_TO_BNETACCOUNT
+	}
+}
+
+Lib:RegisterTypedSearch{
+	id = 'tooltip',
+	tags = {'tt', 'tip', 'tooltip'},
+	onlyTags = true,
+
+	canSearch = function(self, _, search)
+		return search
+	end,
+
+	findItem = function(self, link, _, search)
+		tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE')
+		tooltipScanner:SetHyperlink(link)
+
+		for i = 1, tooltipScanner:NumLines() do
+			local text =  _G[tooltipScanner:GetName() .. 'TextLeft' .. i]:GetText():lower()
+
+			if text:find(search) then
+				return true
+			end
+		end
+
+		return false
+	end,
+}
+
+Lib:RegisterTypedSearch{
+	id = 'classRestriction',
+	tags = {'c', 'class'},
+
+	canSearch = function(self, _, search)
+		return search
+	end,
+
+	findItem = function(self, link, _, search)
+		if link:find("battlepet") then return false end
+
+		local itemID = link:match('item:(%d+)')
+		if not itemID then
+			return
+		end
+
+		local cachedResult = tooltipCache[search][itemID]
+		if cachedResult ~= nil then
+			return cachedResult
+		end
+
+		tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE')
+		tooltipScanner:SetHyperlink(link)
+
+		local result = false
+
+		local pattern = string.gsub(ITEM_CLASSES_ALLOWED:lower(), "%%s", "(.+)")
+
+		for i = 1, tooltipScanner:NumLines() do
+			local text =  _G[tooltipScanner:GetName() .. 'TextLeft' .. i]:GetText():lower()
+			local textChk = string.find(text, pattern)
+
+			if textChk and tostring(text):find(search) then
+				result = true
+			end
+		end
+
+		tooltipCache[search][itemID] = result
+		return result
+	end,
+}
+
+--[[ Equipment sets ]]--
+
+--Placeholder variables; will be replaced with references to the addon-appropriate handlers at runtime
+local ES_FindSets, ES_CheckItem
+
+--Helper: Global Pattern Matching Function (matches ANY set name if search is *, or the EXACT set name if exactMatch is true, or any set name STARTING with the provided search terms if exactMatch is false (this means it will not match in middle of strings). all equipment set searches below use this function to FIRST try to find a set with the EXACT name entered, and if that fails they'll look for all sets that START with the search term, using recursive calls.
+local function ES_TrySetName(setName, search, exactMatch)
+	return (search == '*') or (exactMatch and setName:lower() == search) or (not exactMatch and setName:lower():sub(1,strlen(search)) == search)
+end
+
+--Addon Support: ItemRack
+if IsAddOnLoaded('ItemRack') then
+	function ES_FindSets(setList, search, exactMatch)
+		for setName, _ in pairs(ItemRackUser.Sets) do
+			if ES_TrySetName(setName, search, exactMatch) then
+				if (search ~= '*') or (search == '*' and setName:sub(1,1) ~= '~') then --note: this additional tilde check skips internal ItemRack sets when doing a global set search (internal sets are prefixed with tilde, such as ~Unequip, and they contain temporary data that should not be part of a global search)
+					table.insert(setList, setName)
+				end
+			end
+		end
+		if (search ~= '*') and exactMatch and #setList == 0 then --if we just finished an exact, non-global (not "*"), name match search and still have no results, try one more time with partial ("starts with") set name matching instead
+			ES_FindSets(setList, search, false)
+		end
+	end
+
+	local irSameID = (ItemRack and ItemRack.SameID or nil) --set up local reference for speed if they're an ItemRack user
+	function ES_CheckItem(itemLink, setList)
+		local itemID = string.match(itemLink or '','item:(%-?%d+)') or 0 --grab the baseID of the item we are searching for (we don't need the full itemString, since we'll only be doing a loose baseID comparison below)
+
+		for _, setName in pairs(setList) do
+			for _, irItemData in pairs(ItemRackUser.Sets[setName].equip) do --note: do not change this to ipairs() or it will abort scanning at empty slots in a set
+				--[[ commented out due to libItemSearch lacking a "best match before generic match" priority matching system, so we'll have to go for "generic match" only (below), which matches items that have the same base ItemID as items from the set, as ItemRack cannot guarantee that the stored ItemString will be valid anymore (if the user has modified the item since last saving the set)
+				if itemString == irItemData then -- strict match: perform a strict match to check if this is the *exact* same item (same gems, enchants, etc)
+					return true
+				end]]--
+
+				if irSameID(itemID, irItemData) then --loose match: use ItemRack's built-in "Base ItemID" comparison function to allow us to match any items that have the same base itemID (disregarding strict matching of gems, enchants, etc); due to libItemSearch limitations it's the best compromise and guarantees to always highlight the correct items even if we may catch some extras/duplicates that weren't part of the set
+					return true
+				end
+			end
+		end
+
+		return false
+	end
+
+--Addon Support: Wardrobe
+elseif IsAddOnLoaded('Wardrobe') then
+	function ES_FindSets(setList, search, exactMatch)
+		for _, waOutfit in ipairs(Wardrobe.CurrentConfig.Outfit) do
+			if ES_TrySetName(waOutfit.OutfitName, search, exactMatch) then
+				table.insert(setList, waOutfit) --insert an actual reference to the matching set's data table, instead of just storing the /name/ of the set. we do this due to how Wardrobe works (all sets are in a numerically indexed table and storing the table offset would therefore be unreliable)
+			end
+		end
+		if (search ~= '*') and exactMatch and #setList == 0 then --if we just finished an exact, non-global (not "*"), name match search and still have no results, try one more time with partial ("starts with") set name matching instead
+			ES_FindSets(setList, search, false)
+		end
+	end
+
+	function ES_CheckItem(itemLink, setList)
+		local itemID = tonumber(string.match(itemLink or '','item:(%-?%d+)') or 0) --grab the baseID of the item we are searching for (we don't need the full itemString, since we'll only be doing a loose baseID comparison below)
+
+		for _, waOutfit in pairs(setList) do
+			for _, waItemData in pairs(waOutfit.Item) do
+				if (waItemData.IsSlotUsed == 1) and (waItemData.ItemID == itemID) then --loose match: compare the current item's baseID to the baseID of the set item
+					return true
+				end
+			end
+		end
+
+		return false
+	end
+
+--Last Resort: Blizzard Equipment Manager
+else
+	function ES_FindSets(setList, search, exactMatch)
+		for i = 1, GetNumEquipmentSets() do
+			local setName = GetEquipmentSetInfo(i)
+			if ES_TrySetName(setName, search, exactMatch) then
+				table.insert(setList, setName)
+			end
+		end
+		if (search ~= '*') and exactMatch and #setList == 0 then --if we just finished an exact, non-global (not "*"), name match search and still have no results, try one more time with partial ("starts with") set name matching instead
+			ES_FindSets(setList, search, false)
+		end
+	end
+
+	function ES_CheckItem(itemLink, setList)
+		local itemID = tonumber(string.match(itemLink or '','item:(%-?%d+)') or 0) --grab the baseID of the item we are searching for (we don't need the full itemString, since we'll only be doing a loose baseID comparison below)
+
+		for _, setName in pairs(setList) do
+			local bzSetItemIDs = GetEquipmentSetItemIDs(setName)
+			for _, bzItemID in pairs(bzSetItemIDs) do --note: do not change this to ipairs() or it will abort scanning at empty slots in a set
+				if itemID == bzItemID then --loose match: compare the current item's baseID to the baseID of the set item
+					return true
+				end
+			end
+		end
+
+		return false
+	end
+end
+
+Lib:RegisterTypedSearch{
+	id = 'equipmentSet',
+	tags = {'s', 'set'},
+
+	canSearch = function(self, operator, search)
+		return not operator and search
+	end,
+
+	findItem = function(self, itemLink, _, search)
+		--this is an item-set search and we know that the only items that can possibly match will be *equippable* items, so we'll short-circuit the response for non-equippable items to speed up searches.
+		if not IsEquippableItem(itemLink) then return false end
+
+		--default to matching *all* equipment sets if no set name has been provided yet
+		if search == '' then search = '*' end
+
+		--generate a list of all equipment sets whose names begin with the search term (or a single set if an exact set name match is found), then look for our item in those equipment sets
+		local setList = {}
+		ES_FindSets(setList, search, true)
+		if #setList == 0 then return false end
+		return ES_CheckItem(itemLink, setList)
+	end,
+}
\ No newline at end of file
diff --git a/libs/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.toc b/libs/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.toc
new file mode 100644
index 0000000..f8994ad
--- /dev/null
+++ b/libs/LibItemSearchGrid-1.0/LibItemSearchGrid-1.0.toc
@@ -0,0 +1,7 @@
+## Interface: 70000
+## Title: LibItemSearchGrid-1.0
+## Notes: An updated item search library based on LibItemSearch-1.0
+## OptionalDeps: LibStub, ItemRack, Wardrobe
+## Author: Xruptor, Jaliborc (João Libório), Tuller, Yewbacca (Equipment Set Searching)
+## LoadOnDemand: 1
+LibItemSearchGrid-1.0.lua
\ No newline at end of file
diff --git a/libs/Unfit-1.0/.gitignore b/libs/Unfit-1.0/.gitignore
deleted file mode 100644
index ae649c2..0000000
--- a/libs/Unfit-1.0/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.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
deleted file mode 100644
index 9bf56c7..0000000
--- a/libs/Unfit-1.0/License.url
+++ /dev/null
@@ -1,2 +0,0 @@
-[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
deleted file mode 100644
index 8449256..0000000
--- a/libs/Unfit-1.0/Tests.lua
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644
index 0f668a9..0000000
--- a/libs/Unfit-1.0/Unfit-1.0.lua
+++ /dev/null
@@ -1,127 +0,0 @@
---[[
-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
deleted file mode 100644
index 997ec52..0000000
--- a/libs/Unfit-1.0/Unfit-1.0.toc
+++ /dev/null
@@ -1,8 +0,0 @@
-## 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
diff --git a/modules/search.lua b/modules/search.lua
index 620b0e6..4d5294d 100644
--- a/modules/search.lua
+++ b/modules/search.lua
@@ -4,37 +4,7 @@ local Search = BSYC:NewModule("Search")

 local L = LibStub("AceLocale-3.0"):GetLocale("BagSync", true)
 local AceGUI = LibStub("AceGUI-3.0")
-local customSearch = LibStub('CustomSearch-1.0')
-local ItemSearch = LibStub("LibItemSearch-1.2")
-
-local scanner = LibItemSearchTooltipScanner or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
-
---add classes to the LibItemSearch-1.2
-ItemSearch.Filters.class = {
-	tags = {'c', 'class'},
-
-	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)
-
-			local pattern = string.gsub(ITEM_CLASSES_ALLOWED:lower(), "%%s", "(.+)")
-
-			for i = 1, scanner:NumLines() do
-				local text =  _G[scanner:GetName() .. 'TextLeft' .. i]:GetText():lower()
-				local textChk = string.find(text, pattern)
-
-				if textChk and customSearch:Find(search, _G[scanner:GetName() .. 'TextLeft' .. i]:GetText()) then
-					return true
-				end
-			end
-		end
-	end
-}
+local ItemSearch = LibStub('LibItemSearchGrid-1.0')

 function Search:OnEnable()

@@ -157,7 +127,7 @@ end

 function Search:DoSearch(searchStr)
 	local searchStr = searchStr or self.searchbar:GetText()
-	searchStr = searchStr:lower()
+	searchStr = searchStr:lower() --always make sure everything is lowercase when doing searches

 	local searchTable = {}
 	local tempList = {}
@@ -216,7 +186,7 @@ function Search:DoSearch(searchStr)
 												tempList[dblink] = dName
 												count = count + 1
 											--we found a match
-											elseif not playerSearch and not tempList[dblink] and ItemSearch:Matches(dItemLink, searchStr) then
+											elseif not playerSearch and not tempList[dblink] and ItemSearch:Find(dItemLink, searchStr) then
 												table.insert(searchTable, { name=dName, link=dItemLink, rarity=dRarity, texture=dTexture } )
 												tempList[dblink] = dName
 												count = count + 1
@@ -258,7 +228,7 @@ function Search:DoSearch(searchStr)
 											tempList[dblink] = dName
 											count = count + 1
 										--we found a match
-										elseif not playerSearch and not tempList[dblink] and ItemSearch:Matches(dItemLink, searchStr) then
+										elseif not playerSearch and not tempList[dblink] and ItemSearch:Find(dItemLink, searchStr) then
 											table.insert(searchTable, { name=dName, link=dItemLink, rarity=dRarity, texture=dTexture } )
 											tempList[dblink] = dName
 											count = count + 1