local MAJOR_VERSION = "1.0"
local MINOR_VERSION = tonumber(string.sub("$Revision: 2221 $", 12, -3))

if FuBarPlugin and FuBarPlugin.versions[MAJOR_VERSION] and FuBarPlugin.versions[MAJOR_VERSION].minor >= MINOR_VERSION then
	return
end

local loc = {
	ARGUMENT_SHOWICON = "showIcon",
	ARGUMENT_SHOWTEXT = "showText",
	
	TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Toggle whether to show the icon.",
	TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Toggle whether to show text.",
	TEXT_SCROLL_UP = "Scroll up",
	TEXT_SCROLL_DOWN = "Scroll down",
	TEXT_HINT = "Hint",
	
	MENU_SHOW_ICON = "Show icon",
	MENU_SHOW_TEXT = "Show text",
	MENU_SHOW_COLORED_TEXT = "Show colored text",
	MENU_DETACH_TOOLTIP = "Detach tooltip",
	MENU_LOCK_TOOLTIP = "Lock tooltip",
	MENU_IN_CENTER = "In center",
	MENU_ON_RIGHT_SIDE = "On right side",
	MENU_HIDE = "Hide",
	MENU_DISABLE = "Disable",
	MENU_ABOUT = "About",
	MENU_SIZE = "Size",
	
	MAP_ONOFF = {[0]="|cffff0000Off|r",[1]="|cff00ff00On|r"},
	
	PATTERN_MERGE_WITH_CHILD = "Merge with %s",
	PATTERN_SWITCH_TO_CHILD = "Switch to %s",
}

if GetLocale() == "deDE" then
	loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Iconanzeige umschalten."
	loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Textanzeige umschalten."
	loc.TEXT_SCROLL_UP = "Hochscrollen"
	loc.TEXT_SCROLL_DOWN = "Herunterscrollen"
	loc.TEXT_HINT = "Hinweis"
	
	loc.MENU_SHOW_ICON = "Zeige Icon"
	loc.MENU_SHOW_TEXT = "Zeige Text"
	loc.MENU_SHOW_COLORED_TEXT = "Farbigen Text anzeigen"
	loc.MENU_DETACH_TOOLTIP = "Tooltip l\195\182sen"
	loc.MENU_LOCK_TOOLTIP = "Tooltip verankern"
	loc.MENU_IN_CENTER = "In der Mitte anzeigen"
	loc.MENU_ON_RIGHT_SIDE = "Auf rechter Seite anzeigen"
	loc.MENU_HIDE = "Ausblenden"
	loc.MENU_DISABLE = "Deaktivieren"
	loc.MENU_ABOUT = "\195\156ber"
	loc.MENU_SIZE = "Gr\195\182\195\159e"
	
	loc.MAP_ONOFF[0] = "|cffff0000Aus|r"
	loc.MAP_ONOFF[1] = "|cff00ff00An|r"
	
	loc.PATTERN_MERGE_WITH_CHILD = "Mit %s verbinden"
	loc.PATTERN_SWITCH_TO_CHILD = "Zu %s wechseln"
	
elseif GetLocale() == "frFR" then
	loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Bascule la dissimulation ou l'affichage de l'icone."
	loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Bascule la dissimulation ou l'affichage du text."
--	loc.TEXT_SCROLL_UP = "Scroll up", -- CHECK
--	loc.TEXT_SCROLL_DOWN = "Scroll down", -- CHECK
	loc.TEXT_HINT = "Conseil"
	
	loc.MENU_SHOW_ICON = "Afficher l'icon"
	loc.MENU_SHOW_TEXT = "Afficher le text"
--	loc.MENU_SHOW_COLORED_TEXT = "Show colored text" -- CHECK
--	loc.MENU_DETACH_TOOLTIP = "Detach tooltip" -- CHECK
--	loc.MENU_LOCK_TOOLTIP = "Lock tooltip" -- CHECK
--	loc.MENU_IN_CENTER = "In center" -- CHECK
--	loc.MENU_ON_RIGHT_SIDE = "On right side" -- CHECK
	loc.MENU_HIDE = "Dissimule"
	loc.MENU_DISABLE = "Desactive"
	loc.MENU_ABOUT = "A propos"
--	loc.MENU_SIZE = "Size" -- CHECK
	
--	loc.MAP_ONOFF[0] = "|cffff0000Off|r" -- CHECK
--	loc.MAP_ONOFF[1] = "|cff00ff00On|r" -- CHECK
	
	loc.PATTERN_MERGE_WITH_CHILD = "Fusione avec %s"
	loc.PATTERN_SWITCH_TO_CHILD = "Echange avec %s"
end

-------------IRIEL'S-STUB-CODE--------------
local stub = {};

-- Instance replacement method, replace contents of old with that of new
function stub:ReplaceInstance(old, new)
   for k,v in pairs(old) do old[k]=nil; end
   for k,v in pairs(new) do old[k]=v; end
end

-- Get a new copy of the stub
function stub:NewStub()
  local newStub = {};
  self:ReplaceInstance(newStub, self);
  newStub.lastVersion = '';
  newStub.versions = {};
  return newStub;
end

-- Get instance version
function stub:GetInstance(version)
   if (not version) then version = self.lastVersion; end
   local versionData = self.versions[version];
   if (not versionData) then
	  message("Cannot find library instance with version '" 
			  .. version .. "'");
	  return;
   end
   return versionData.instance;
end

-- Register new instance
function stub:Register(newInstance)
   local version,minor = newInstance:GetLibraryVersion();
   self.lastVersion = version;
   local versionData = self.versions[version];
   if (not versionData) then
	  -- This one is new!
	  versionData = { instance = newInstance,
		 minor = minor,
		 old = {} 
	  };
	  self.versions[version] = versionData;
	  newInstance:LibActivate(self);
	  return newInstance;
   end
   if (minor <= versionData.minor) then
	  -- This one is already obsolete
	  if (newInstance.LibDiscard) then
		 newInstance:LibDiscard();
	  end
	  return versionData.instance;
   end
   -- This is an update
   local oldInstance = versionData.instance;
   local oldList = versionData.old;
   versionData.instance = newInstance;
   versionData.minor = minor;
   local skipCopy = newInstance:LibActivate(self, oldInstance, oldList);
   table.insert(oldList, oldInstance);
   if (not skipCopy) then
	  for i, old in ipairs(oldList) do
		 self:ReplaceInstance(old, newInstance);
	  end
   end
   return newInstance;
end

-- Bind stub to global scope if it's not already there
if (not FuBarPlugin or not FuBarPlugin.Register) then
   FuBarPlugin = stub:NewStub();
end

if (not FuBarTooltip or not FuBarTooltip.Register) then
   FuBarTooltip = stub:NewStub();
end

-- Nil stub for garbage collection
stub = nil;
-----------END-IRIEL'S-STUB-CODE------------

-- FuBarPlugin 1.0
do
	local compost = CompostLib:GetInstance('compost-1')
	local metro = Metrognome:GetInstance('1')
	
	local epsilon = 1e-5
	
	local function inheritDefaults(t, defaults)
		if not defaults then
			return
		end
		for k,v in pairs(defaults) do
			if type(v) == "table" then
				if type(t[k]) ~= "table" then
					t[k] = {}
				end
				inheritDefaults(t[k], v)
			elseif t[k] == v then
				t[k] = nil
			end
		end
		for k,v in pairs(t) do
			if v == TRUE and defaults[k] == true then
				t[k] = nil
			elseif v == true and defaults[k] == TRUE then
				t[k] = nil
			end
		end
		setmetatable(t, { __index = defaults })
	end
	
	local function VersionToNumber(version)
		if version == nil then
			return 0
		elseif type(version) == "number" then
			return version
		end
		local num = 0
		local place = 1
		string.gsub(version, "(%d+)", function (w)
			num = num + tonumber(w) * math.pow(10, place * 2)
			if place > 0 then
				place = place - 1
			else
				place = place - 2
			end
		end)
		return num
	end
	
	local lib = AceAddon:new()
	
	function lib:assert(condition, message)
		if not condition then
			local stack = debugstack()
			local first = string.gsub(stack, "\n.*", "")
			local file = string.gsub(first, "^(.*\\.*)%.lua:%d+: .*", "%1")
			local dir = string.gsub(file, "^(.*)\\.*", "%1")
			if not message then
				local _,_,second = string.find(stack, "\n(.-)\n")
				message = "assertion failed! " .. second
			end
			if self:GetTitle() then
				message = self:GetTitle() .. ": " .. message
			end
			local i = 1
			for s in string.gfind(stack, "\n(.-)\n") do
				i = i + 1
				if not string.find(s, dir .. "\\.*%.lua:%d+:") then
					error(message, i)
					return
				end
			end
			error(message, 2)
			return
		end
		return condition
	end
	
	function lib:_OnAceProfileLoaded()
		if self.db then
			local t = self.db._table
			if not t.profiles then
				t.profiles = {}
			end
			if not t.profiles[self.profilePath[2]] then
				t.profiles[self.profilePath[2]] = {}
			end
			if self.data ~= self.db._table.profiles[self.profilePath[2]] then
				self.data = self.db._table.profiles[self.profilePath[2]]
			else
				return
			end
		else
			if not FuBarDB.pluginDB[self:GetTitle()] then
				FuBarDB.pluginDB[self:GetTitle()] = {}
			end
			if not FuBarDB.pluginDB[self:GetTitle()].profiles then
				FuBarDB.pluginDB[self:GetTitle()].profiles = {}
			end
			if not FuBarDB.pluginDB[self:GetTitle()].profiles[FuBar.profilePath[2]] then
				FuBarDB.pluginDB[self:GetTitle()].profiles[FuBar.profilePath[2]] = {}
			end
			if self.data ~= FuBarDB.pluginDB[self:GetTitle()].profiles[FuBar.profilePath[2]] then
				self.data = FuBarDB.pluginDB[self:GetTitle()].profiles[FuBar.profilePath[2]]
			else
				return
			end
		end
		inheritDefaults(self.data, self.defaults)
		
		if self.OnAceProfileLoaded then
			self:OnAceProfileLoaded()
		end
			
		self.data.version = self.version
		
		self:Update()
	end
	
	function lib:GetTitle()
		local _,_,title = string.find(self.name, "FuBar %- (.+)")
		if not title then
			title = self.name
		end
		return title
	end
	
	function lib:DisableHideWithoutStandby()
		self.hideWithoutStandby = false
		if not self._hideWithoutStandbyEnabled then
			return
		end
		self._hideWithoutStandbyEnabled = false
		for index, value in self.cmd.options do
			if value.method == "_ToggleVisible" then
				table.remove(self.cmd.options, index)
				break
			end
		end
		
		self._ToggleVisible = nil
		
		self.Report = self._Report
		self._Report = nil
		
		if self.data.hidden then
			self:DisableAddon()
		end
		self.data.hidden = nil
	end
	
	function lib:EnableHideWithoutStandby()
		self.hideWithoutStandby = true
		if self._hideWithoutStandbyEnabled then 
			return
		end
		self._hideWithoutStandbyEnabled = true
		table.insert(self.cmd.options, {
			option = loc.ARGUMENT_VISIBLE,
			desc = loc.TEXT_TOGGLE_VISIBILITY,
			method = "_ToggleVisible"
		})
		
		function self:_ToggleVisible()
			if self.data.hidden then
				self:Show()
			else
				self:Hide()
			end
			self.cmd:status(loc.ARGUMENT_VISIBLE, not self.data.hidden and 1 or 0, loc.MAP_ONOFF)
		end
		
		if self.Report then
			self._Report = self.Report
			function self:Report()
				self:_Report()
				ace:print(" - ", format(ACE_CMD_REPORT_LINE, loc.ARGUMENT_VISIBLE, loc.MAP_ONOFF[not self.data.hidden and 1 or 0]))
			end
		else
			function self:Report()
				local report = compost and compost:Acquire(
					compost:AcquireHash(
						'text', loc.ARGUMENT_VISIBLE,
						'val', not self.data.hidden and 1 or 0,
						'map', loc.MAP_ONOFF
					)
				) or {{
					text = loc.ARGUMENT_VISIBLE,
					val = not self.data.hidden and 1 or 0,
					map = loc.MAP_ONOFF
				}}
				self.cmd:report(report)
				if compost then
					compost:Reclaim(report, 1)
				end
			end
		end
	end
	
	function lib:IsTextColored()
		if self.data then
			return not self.data.uncolored
		else
			return true
		end
	end
	
	function lib:ToggleTextColored(loud)
		self.data.uncolored = not self.data.uncolored or nil
		if loud then
			self.cmd:status(loc.ARGUMENT_COLOR, not self.data.uncolored and 1 or 0, loc.MAP_ONOFF)
		end
		self:UpdateText()
		return not self.data.uncolored
	end
	
	function lib:Update()
		self:UpdateData()
		self:UpdateText()
		self:UpdateTooltip()
	end
	
	function lib:Show(panelId)
		if self:IsLoadOnDemand() and FuBar then
			if not FuBar.fullData.loadOnDemand then
				FuBar.fullData.loadOnDemand = {}
			end
			if not FuBar.fullData.loadOnDemand[self.folderName] then
				FuBar.fullData.loadOnDemand[self.folderName] = {}
			end
			FuBar.fullData.loadOnDemand[self.folderName].disabled = nil
		end
		if panelId ~= false then
			self.data.hidden = nil
		end
		if self.disabled then
			self.panelIdTmp = panelId
			self:EnableAddon()
			self.panelIdTmp = nil
			if not self.db then
				self.data.disabled = nil
			end
		else
			if panelId == 0 or not FuBar then
				self:Hide()
			else
				FuBar:ShowPlugin(self, panelId or self.panelIdTmp)
				self:Update()
			end
		end
	end
	
	function lib:Hide()
		if self.hideWithoutStandby then
			self.data.hidden = true
		end
		if not self.hideWithoutStandby then
			if not self.overrideTooltip and not self.cannotDetachTooltip and self:IsTooltipDetached() and self.data.detachedTooltip.detached then
				self:ReattachTooltip()
				self.data.detachedTooltip.detached = true
			end
			if not self.db then
				self.data.disabled = true
			end
			self:DisableAddon()
			if self:IsLoadOnDemand() and FuBar then
				FuBar.fullData.loadOnDemand[self.folderName].disabled = true
			end
		end
		if self.panel then
			self.panel:RemovePlugin(self)
		end
		self.frame:Hide()
	end
	
	function lib:AddImpliedMenuOptions(level)
		if not level then
			level = 1
		end
		
		local info = compost:Acquire()
		
		if self.hasIcon and not self.hasNoText then
			UIDropDownMenu_AddButton(compost:RecycleHash(info,
				'text', loc.MENU_SHOW_ICON,
				'func', function()
					self:ToggleIconShown()
				end,
				'checked', self:IsIconShown(),
				'keepShownOnClick', true
			), level)
		end
		
		if not self.cannotHideText and self.hasIcon then
			UIDropDownMenu_AddButton(compost:RecycleHash(info,
				'text', loc.MENU_SHOW_TEXT,
				'func', function()
					self:ToggleTextShown()
				end,
				'checked', self:IsTextShown(),
				'keepShownOnClick', true
			), level)
		end
		
		if not self.userDefinedFrame and not self.hasNoText and not self.hasNoColor then
			UIDropDownMenu_AddButton(compost:RecycleHash(info,
				'text', loc.MENU_SHOW_COLORED_TEXT,
				'func', function()
					self:ToggleTextColored()
				end,
				'checked', self:IsTextColored(),
				'keepShownOnClick', true
			), level)
		end
		
		if not self.overrideTooltip and not self.cannotDetachTooltip then
			UIDropDownMenu_AddButton(compost:RecycleHash(info,
				'text', loc.MENU_DETACH_TOOLTIP,
				'func', function()
					if self:IsTooltipDetached() then
						self:ReattachTooltip()
					else
						self:DetachTooltip()
					end
				end,
				'checked', self:IsTooltipDetached(),
				'keepShownOnClick', true
			), level)
			
			UIDropDownMenu_AddButton(compost:RecycleHash(info,
				'text', loc.MENU_LOCK_TOOLTIP,
				'func', function()
					self.tooltip:EnableMouse(self.tooltip.locked)
					self.tooltip.locked = not self.tooltip.locked
					self.data.detachedTooltip.locked = self.tooltip.locked or nil
					self:UpdateTooltip()
				end,
				'checked', self.tooltip.locked,
				'disabled', not self:IsTooltipDetached(),
				'keepShownOnClick', true
			), level)
		end
		
		UIDropDownMenu_AddButton(compost:RecycleHash(info,
			'text', loc.MENU_IN_CENTER,
			'func', function()
				if self.panel:GetPluginSide(self) == "CENTER" then
					self.panel:SetPluginSide(self, "LEFT")
				else
					self.panel:SetPluginSide(self, "CENTER")
				end
			end,
			'checked', self.panel:GetPluginSide(self) == "CENTER"
		), level)
		
		UIDropDownMenu_AddButton(compost:RecycleHash(info,
			'text', loc.MENU_ON_RIGHT_SIDE,
			'func', function()
				if self.panel:GetPluginSide(self) == "RIGHT" then
					self.panel:SetPluginSide(self, "LEFT")
				else
					self.panel:SetPluginSide(self, "RIGHT")
				end
			end,
			'checked', self.panel:GetPluginSide(self) == "RIGHT"
		), level)
		
		if self.hideWithoutStandby then
			UIDropDownMenu_AddButton(compost:RecycleHash(info,
				'text', loc.MENU_HIDE,
				'func', function()
					self:Hide()
				end
			), level)
		end
		
		UIDropDownMenu_AddButton(compost:RecycleHash(info,
			'text', loc.MENU_DISABLE,
			'func', function()
				self:DisableAddon()
			end
		), level)
		
		FuBarUtils.AddSpacerDropDownMenu(level)
		
		UIDropDownMenu_AddButton(compost:RecycleHash(info,
			'text', loc.MENU_ABOUT,
			'func', function()
				self.cmd:DisplayAddonInfo()
			end
		), level)
		
		compost:Reclaim(info)
	end
	
	function lib:SetIcon(path)
		self:assert(self.hasIcon, "Cannot set icon unless self.hasIcon is set. (" .. self:GetTitle() .. ")")
		if not self.iconFrame then
			return
		end
		if type(path) ~= "string" then
			path = "Interface\\AddOns\\" .. self.folderName .. "\\icon"
		end
		if string.sub(path, 1, 16) == "Interface\\Icons\\" then
			self.iconFrame:SetTexCoord(0.05, 0.95, 0.05, 0.95)
		else
			self.iconFrame:SetTexCoord(0, 1, 0, 1)
		end
		self.iconFrame:SetTexture(path)
	end
	
	function lib:GetIcon()
		if self.hasIcon then
			return self.iconFrame:GetTexture()
		end
	end
	
	function lib:CheckWidth(force)
		if (self.iconFrame and self.iconFrame:IsShown()) or (self.textFrame and self.textFrame:IsShown()) then
			if self.data and not self:IsIconShown() then
				self.iconFrame:SetWidth(epsilon)
			end
			local width
			if not self.hasNoText then
				self.textFrame:SetHeight(0)
				self.textFrame:SetWidth(500)
				width = self.textFrame:GetStringWidth() + 1
				self.textFrame:SetWidth(width)
				self.textFrame:SetHeight(self.textFrame:GetHeight())
			end
			if self.hasNoText or not self.textFrame:IsShown() then
				self.frame:SetWidth(self.iconFrame:GetWidth())
				if self.panel and self.panel:GetPluginSide(self) == "CENTER" then
					self.panel:UpdateCenteredPosition()
				end
			elseif force or not self.textWidth or self.textWidth < width or self.textWidth - 8 > width then
				self.textWidth = width
				self.textFrame:SetWidth(width)
				if self.iconFrame and self.iconFrame:IsShown() then
					self.frame:SetWidth(width + self.iconFrame:GetWidth())
				else
					self.frame:SetWidth(width)
				end
				if self.panel and self.panel:GetPluginSide(self) == "CENTER" then
					self.panel:UpdateCenteredPosition()
				end
			end
		end
	end
	
	function lib:SetText(text)
		if not self.textFrame then
			return
		end
		self:assert(not self.hasNoText, "Cannot set text if self.hasNoText has been set. (" .. self:GetTitle() .. ")")
		self:assert(text, "You must provide a value for text, even if it is blank. (" .. self:GetTitle() .. ")")
		if text == "" then
			if self.hasIcon then
				self:ShowIcon()
			else
				text = self:GetTitle()
			end
		end
		if not self:IsTextColored() then
			text = string.gsub(text, "|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
		end
		self.textFrame:SetText(text)
		self:CheckWidth()
	end
	
	function lib:GetText()
		self:assert(self.textFrame, "Cannot get text without a self.textFrame (" .. self:GetTitle() .. ")")
		if not self.hasNoText then
			return self.textFrame:GetText() or ""
		end
	end
	
	function lib:IsIconShown()
		if not self.hasIcon then
			return false
		elseif self.hasNoText then
			return true
		elseif not self.data then
			return true
		elseif not self.data.showIcon then
			return true
		else
			return (self.data.showIcon == 1 or self.data.showIcon == true) and true or false
		end
	end
	
	function lib:ToggleIconShown(loud)
		self:assert(self.iconFrame, "Cannot toggle icon without a self.iconFrame (" .. self:GetTitle() .. ")")
		self:assert(self.hasIcon, "Cannot show icon unless self.hasIcon is set. (" .. self:GetTitle() .. ")")
		self:assert(not self.hasNoText, "Cannot hide icon if self.hasNoText is set. (" .. self:GetTitle() .. ")")
		self:assert(self.textFrame, "Cannot hide icon if self.textFrame is not set. (" .. self:GetTitle() .. ")")
		self:assert(self.iconFrame, "Cannot hide icon if self.iconFrame is not set. (" .. self:GetTitle() .. ")")
		local value = not self:IsIconShown()
		self.data.showIcon = value and 1 or 0
		if loud then
			self.cmd:status(loc.ARGUMENT_SHOWICON, value and 1 or 0, loc.MAP_ONOFF)
		end
		if value then
			if self.textFrame:IsShown() and self.textFrame:GetText() == self:GetTitle() then
				self.textFrame:Hide()
				self.textFrame:SetText("")
			end
			self.iconFrame:Show()
			self.iconFrame:SetWidth(self.iconFrame:GetHeight())
		else
			if not self.textFrame:IsShown() or not self.textFrame:GetText() then
				self.textFrame:Show()
				self.textFrame:SetText(self:GetTitle())
			end
			self.iconFrame:Hide()
			self.iconFrame:SetWidth(epsilon)
		end
		self:CheckWidth(true)
		return value
	end
	
	function lib:ShowIcon()
		if not self:IsIconShown() then
			self:ToggleIconShown()
		end
	end
	
	function lib:HideIcon()
		if self:IsIconShown() then
			self:ToggleIconShown()
		end
	end
	
	function lib:IsTextShown()
		if not self.hasIcon then
			return false
		elseif self.hasNoText then
			return false
		elseif not self.data then
			return true
		elseif not self.data.showText then
			return true
		else
			return (self.data.showText == 1 or self.data.showText == true) and true or false
		end
	end
	
	function lib:ToggleTextShown(loud)
		self:assert(not self.cannotHideText, "Cannot hide text unless self.cannotHideText is unset. (" .. self:GetTitle() .. ")")
		self:assert(self.hasIcon, "Cannot show text unless self.hasIcon is set. (" .. self:GetTitle() .. ")")
		self:assert(not self.hasNoText, "Cannot hide text if self.hasNoText is set. (" .. self:GetTitle() .. ")")
		self:assert(self.textFrame, "Cannot hide text if self.textFrame is not set. (" .. self:GetTitle() .. ")")
		self:assert(self.iconFrame, "Cannot hide text if self.iconFrame is not set. (" .. self:GetTitle() .. ")")
		local value = not self:IsTextShown()
		self.data.showText = value and 1 or 0
		if loud then
			self.cmd:status(loc.ARGUMENT_SHOWTEXT, value and 1 or 0, loc.MAP_ONOFF)
		end
		if value then
			self.textFrame:Show()
			self:UpdateText()
		else
			self.textFrame:SetText("")
			self.textFrame:SetWidth(epsilon)
			self.textFrame:Hide()
			if not self:IsIconShown() then
				DropDownList1:Hide()
			end
			self:ShowIcon()
		end
		self:CheckWidth(true)
		return value
	end
	
	function lib:ShowText()
		if not self:IsTextShown() then
			self:ToggleTextShown()
		end
	end
	
	function lib:HideText()
		if self:IsTextShown() then
			self:ToggleTextShown()
		end
	end
	
	function lib:OpenChildFrame(child)
		self:assert(child, "Expected frame, received nil. (" .. self:GetTitle() .. ")")
		if self.lastChildFrame then
			self.lastChildFrame:Hide()
		end
		self.lastChildFrame = child
		local frame = self.frame
		local width, height = GetScreenWidth(), GetScreenHeight()
		local anchor
		if frame:GetLeft() <= width/2 then
			anchor = "LEFT"
		else
			anchor = "RIGHT"
		end
		child:ClearAllPoints()
		if frame:GetTop() <= height/2 then
			child:SetPoint("BOTTOM" .. anchor, frame, "TOP" .. anchor)
			local left = child:GetLeft()
			child:ClearAllPoints()
			child:SetPoint("LEFT", UIParent, "LEFT", left, 0)
			child:SetPoint("BOTTOM", frame, "TOP")
		else
			child:SetPoint("TOP" .. anchor, frame, "BOTTOM" .. anchor)
			local left = child:GetLeft()
			child:ClearAllPoints()
			child:SetPoint("LEFT", UIParent, "LEFT", left, 0)
			child:SetPoint("TOP", frame, "BOTTOM")
		end
		child:Show()
	end
	
	function lib:StopOnUpdate()
		metro:Stop(self:GetTitle())
	end
	
	function lib:StartOnUpdate()
		self:assert(self.OnUpdate, "Cannot start OnUpdate without OnUpdate existing. (" .. self:GetTitle() .. ")")
		metro:Start(self:GetTitle())
	end
	
	function lib:HookIntoPlugin(mother, style)
		if self.hookedPlugin then
			self:debug("Cannot hook into a plugin while already hooked into another.")
			return false
		end
		if not mother or type(mother) ~= "table" or getmetatable(mother).__index ~= getmetatable(self).__index then
			self:debug("Cannot hook into given plugin.")
			return false
		end
		local showTitle = false
		if style then
			local a, b = string.find(style, "_TITLE")
			if a and b then
				showTitle = true
				style = string.sub(style, 1, a - 1) .. string.sub(style, b + 1)
			end
		end
		if style ~= "INLINE" and style ~= "SWITCH" and style ~= "SWITCHTEXT" then
			style = "INLINE"
		end
		local child = self
		local merged = false
		local current = "MOTHER"
		local mother__UpdateTooltip = mother._UpdateTooltip
		local child_UpdateTooltip = child.UpdateTooltip
		local mother_UpdateText = mother.UpdateText
		local child_UpdateText = child.UpdateText
		local child_Show = child.Show
		local mother_funcs = {}
		local mother_MenuSettings = mother.MenuSettings
		local manualStandby = false
		local motherIcon = mother:GetIcon()
		local childIcon = child:GetIcon()
		local merge, unmerge, switch
		switch = function()
			if current == "MOTHER" then
				self.data["switch." .. mother:GetTitle()] = "CHILD"
				current = "CHILD"
				getmetatable(self).__index.SetIcon(mother, childIcon)
			else
				self.data["switch." .. mother:GetTitle()] = "MOTHER"
				current = "MOTHER"
				getmetatable(self).__index.SetIcon(mother, motherIcon)
			end
			mother:UpdateText()
			mother:UpdateTooltip()
			HideDropDownMenu(1)
		end
		function self:SwitchPluginHook()
			switch()
		end
		function self:IsCurrentPluginHookSwitch()
			return current ~= "MOTHER"
		end
		merge = function()
			merged = true
			self.data["merge." .. mother:GetTitle()] = 1
			if style == "INLINE" or style == "SWITCHTEXT" then
				function mother:_UpdateTooltip()
					mother__UpdateTooltip(mother)
					if showTitle and not mother:IsTooltipDetached() then
						mother.tooltip:AddBlankLine(nil)
						mother.tooltip:AddLine(nil, child:GetTitle(), nil, nil, nil, false, "CENTER", FuBarTooltip:GetHeaderFontObject())
						mother.tooltip.preventNextBlank = true
					end
					child.tooltip = mother.tooltip
					child:_UpdateTooltip()
				end
			elseif style == "SWITCH" then
				function mother:_UpdateTooltip()
					if current == "MOTHER" then
						mother__UpdateTooltip(mother)
					else
						mother.tooltip:SetTitle(child:GetTitle())
						child.tooltip = mother.tooltip
						child:_UpdateTooltip()
					end
				end
			end
			function child:UpdateTooltip()
				mother:UpdateTooltip()
			end
			
			local text
			if style == "INLINE" then
				function mother:SetText(t)
					text = t
				end
				function child:SetText(t)
					if text == "" or not text then
						text = t
					else
						text = text .. " " .. t
					end
				end
			elseif style == "SWITCH" or style == "SWITCHTEXT" then
				function mother:SetText(t)
					if current == "MOTHER" then
						text = t
					end
				end
				function child:SetText(t)
					if current ~= "MOTHER" then
						text = t
					end
				end
			end
			
			if style == "INLINE" then
				function mother:UpdateText()
					text = ""
					if mother_UpdateText then
						mother_UpdateText(mother)
					end
					if child_UpdateText then
						child_UpdateText(child)
					end
					getmetatable(self).__index.SetText(mother, text)
					text = nil
				end
			elseif style == "SWITCH" or style == "SWITCHTEXT" then
				function mother:UpdateText()
					text = ""
					if current == "MOTHER" and mother_UpdateText then
						mother_UpdateText(mother)
					end
					if current ~= "MOTHER" and child_UpdateText then
						child_UpdateText(child)
					end
					getmetatable(self).__index.SetText(mother, text)
					text = nil
				end
			end
			child.UpdateText = mother.UpdateText
			
			for _,name in onClickTypes do
				local name = name
				mother_funcs[name] = mother[name]
				local child_func = child[name]
				if style == "INLINE" then
					if mother_funcs[name] and child_func then
						mother[name] = function(self, alpha)
							mother_funcs[name](mother, alpha)
							child_func(child, alpha)
						end
					elseif child_func then
						mother[name] = child_func
					end
				elseif style == "SWITCH" or style == "SWITCHTEXT" then
					mother[name] = function(self, alpha)
						if current == "MOTHER" and mother_funcs[name] ~= "nil" then
							mother_funcs[name](mother, alpha)
						elseif current ~= "MOTHER" and child_func then
							child_func(child, alpha)
						end
					end
				end
				if not mother_funcs[name] then
					mother_funcs[name] = "nil"
				end
			end
			
			if style == "SWITCH" or style == "SWITCHTEXT" then
				function mother:SetIcon(path)
					motherIcon = path
					getmetatable(self).__index.SetIcon(mother, path)
				end
				function child:SetIcon(path)
					childIcon = path
					getmetatable(self).__index.SetIcon(mother, path)
				end
			end
			
			function child:Show()
				unmerge()
				
				child_Show(self)
			end
			
			if not child.hideWithoutStandby then
				manualStandby = true
				child:EnableHideWithoutStandby()
			end
			child:Hide()
			
			mother:UpdateText()
			mother:UpdateTooltip()
		end
		unmerge = function()
			merged = false
			self.data["merge." .. mother:GetTitle()] = 0
			mother._UpdateTooltip = mother__UpdateTooltip
			child.UpdateTooltip = child_UpdateTooltip
			mother.SetText = nil
			child.SetText = nil
			mother.SetIcon = nil
			child.SetIcon = nil
			mother.UpdateText = mother_UpdateText
			child.UpdateText = child_UpdateText
			for name,func in pairs(mother_funcs) do
				if func == "nil" then
					mother[name] = nil
				else
					mother[name] = func
				end
			end
			child.Show = child_Show
			if manualStandby then
				child:DisableHideWithoutStandby()
				manualStandby = false
			end
			mother:SetIcon(motherIcon)
			mother:UpdateText()
			mother:UpdateTooltip()
			child:Show()
		end
		
		function mother:MenuSettings(level, value)
			if level == 1 then
				local info = compost:AcquireHash(
					'text', format(loc.PATTERN_MERGE_WITH_CHILD, child:GetTitle()),
					'func', function()
						if merged then
							unmerge()
						else
							if child.disabled then
								child:EnableAddon()
							end
							merge()
						end
					end,
					'checked', merged,
					'hasArrow', merged and (style == "SWITCH" or style == "SWITCHTEXT"),
					'value', child:GetTitle()
				)
				UIDropDownMenu_AddButton(info, level)
				compost:Reclaim(info)
			elseif level == 2 and value == child:GetTitle() then
				local info = compost:AcquireHash(
					'text', format(loc.PATTERN_SWITCH_TO_CHILD, child:GetTitle()),
					'func', switch,
					'checked', current ~= "MOTHER",
					'keepShownOnClick', true
				)
				UIDropDownMenu_AddButton(info, level)
				compost:Reclaim(info)
			end
			if merged then
				if (style ~= "SWITCH" or (style == "SWITCH" and current == "MOTHER")) and mother_MenuSettings then
					if level == 1 then
						FuBarUtils.AddSpacerDropDownMenu(level)
					end
					mother_MenuSettings(mother, level, value)
				end
				if (style ~= "SWITCH" or (style == "SWITCH" and current == "CHILD")) and child.MenuSettings then
					if level == 1 then
						FuBarUtils.AddSpacerDropDownMenu(level)
					end
					child:MenuSettings(level, value)
				end
			else
				if mother_MenuSettings then
					if level == 1 then
						FuBarUtils.AddSpacerDropDownMenu(level)
					end
					mother_MenuSettings(mother, level, value)
				end
			end
		end
		if not self.data["merge." .. mother:GetTitle()] then
			self.data["merge." .. mother:GetTitle()] = 1
		end
		if (style == "SWITCH" or style == "SWITCHTEXT") and not self.data["switch." .. mother:GetTitle()] then
			self.data["switch." .. mother:GetTitle()] = "MOTHER"
		end
		if self.data["merge." .. mother:GetTitle()] == 1 then
			merge()
		end
		if style == "SWITCH" or style == "SWITCHTEXT" then
			if self.data["switch." .. mother:GetTitle()] == "MOTHER" then
				self.data["switch." .. mother:GetTitle()] = "CHILD"
			else
				self.data["switch." .. mother:GetTitle()] = "MOTHER"
			end
			current = self.data["switch." .. mother:GetTitle()]
			switch()
		end
		self.hookedPlugin = mother
		return true
	end
	
	function lib:IsTooltipDetached()
		return self.tooltip ~= FuBarTooltipFrame
	end
	
	function lib:DetachTooltip()
		if not self:IsTooltipDetached() then
			self.tooltip = FuBarTooltip:AcquireDetached(self.frame)
			self:UpdateTooltip()
		end
	end
	
	function lib:ReattachTooltip()
		if self:IsTooltipDetached() then
			FuBarTooltip:ReleaseDetached(self.tooltip)
			self:UpdateTooltip()
		end
	end
	
	function lib:GetName()
		return self.name
	end
	
	function lib:GetCategory()
		return self.category
	end
	
	function lib:GetFrame()
		return self.frame
	end
	
	function lib:GetPanel()
		return self.panel
	end
	
	function lib:GetDefaultPosition()
		return self.defaultPosition or "LEFT"
	end
	
	local function IsCorrectPanel(panel)
		if type(panel) ~= "table" then
			return false
		elseif type(panel.AddPlugin) ~= "function" then
			return false
		elseif type(panel.RemovePlugin) ~= "function" then
			return false
		elseif type(panel.GetNumPlugins) ~= "function" then
			return false
		elseif type(panel:GetNumPlugins()) ~= "number" then
			return false
		elseif type(panel.GetPlugin) ~= "function" then
			return false
		elseif type(panel.HasPlugin) ~= "function" then
			return false
		elseif type(panel.GetPluginSide) ~= "function" then
			return false
		end
		return true
	end
	
	function lib:SetPanel(panel)
		if panel then
			self:assert(IsCorrectPanel(panel), "Panel does not have the correct API.")
		end
		self.panel = panel
	end
	
	function lib:SetFontSize(size)
		self:assert(not self.userDefinedFrame, "You must provide a SetFontSize(size) method if you provide your own frame.")
		if self.hasIcon and self.iconFrame then
--			self:assert(self.iconFrame, (self.name and self.name .. ": " or "") .. "No iconFrame found")
			self.iconFrame:SetWidth(size + 3)
			self.iconFrame:SetHeight(size + 3)
		end
		if not self.hasNoText and self.textFrame then
--			self:assert(self.textFrame, (self.name and self.name .. ": " or "") .. "No textFrame found")
			local font, _, flags = self.textFrame:GetFont()
			self.textFrame:SetFont(font, size, flags)
		end
		self:CheckWidth()
	end
	
	function lib:SetLoadOnDemand(lod)
		self._loadOnDemand = lod and true or false
	end
	
	function lib:IsLoadOnDemand()
		return self._loadOnDemand
	end
	
	function lib:IsDisabled()
		return self.disabled
	end
	
	function lib:FuBar_Plugin_OpenMenu(plugin)
		if not plugin.panel then
			return
		end
		FuBarTooltipFrame:Hide()
		
		if not plugin.menuInitialized then
			plugin.menuInitialized = true
			UIDropDownMenu_Initialize(plugin.menuFrame, function(level)
				if level == 1 then
					local info = compost:AcquireHash(
						'text', plugin:GetTitle(),
						'notClickable', true,
						'isTitle', true
					)
					UIDropDownMenu_AddButton(info)
					compost:Reclaim(info)
				end
				
				if plugin.MenuSettings then
					plugin:MenuSettings(level, UIDROPDOWNMENU_MENU_VALUE)
				end
				
				if level == 1 and not plugin.overrideMenu then
					if plugin.MenuSettings then
						FuBarUtils.AddSpacerDropDownMenu()
					end
					plugin:AddImpliedMenuOptions()
				end
				if level == 1 then
					local info = compost:AcquireHash(
						'text', CLOSE,
						'func', CloseDropDownMenus
					)
					UIDropDownMenu_AddButton(info)
					compost:Reclaim(info)
				end
			end, "MENU")
		end
		
		HideDropDownMenu(1)
		ToggleDropDownMenu(1, nil, plugin.menuFrame, plugin.frame, 0, 0)
		
		local x, y = plugin.frame:GetLeft(), plugin.frame:GetTop()
		local width, height = GetScreenWidth(), GetScreenHeight()
		local ratio = width / height
		local anchor
		if plugin.frame:GetCenter() < width / 2 then
			anchor = "LEFT"
		else
			anchor = "RIGHT"
		end
		local offset = 0
		DropDownList1:ClearAllPoints()
		if y > height/2 then
			DropDownList1:SetPoint("TOP" .. anchor, plugin.frame, "BOTTOM" .. anchor, offset, 0)
		else
			DropDownList1:SetPoint("BOTTOM" .. anchor, plugin.frame, "TOP" .. anchor, offset, 0)
		end
		if ratio >= 2.4 and DropDownList1:GetRight() > width / 2 and DropDownList1:GetLeft() < width / 2 then
			print('alpha')
			local offsetx
			if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then
				offsetx = DropDownList1:GetRight() - GetScreenWidth() / 2
			else
				offsetx = DropDownList1:GetLeft() - width / 2
			end
			local point, parent, relativePoint, x, y = DropDownList1:GetPoint(1)
			DropDownList1:SetPoint(point, parent, relativePoint, (x or 0) - offsetx, y or 0)
		end
	end
	
	function lib:FuBar_Plugin_ShowTooltip(plugin)
		FuBarTooltip.Initialize()
		FuBar:Panel_OnEnter(plugin)
		if self.lastChildFrame then
			self.lastChildFrame:Hide()
		end
		plugin.tooltip:Hide()
		if plugin.overrideTooltip then
			plugin:ShowTooltip()
			if plugin.UpdateTooltip then
				plugin:UpdateTooltip()
			end
		elseif plugin.UpdateTooltip and DropDownList1.attachedTo ~= plugin then
			if not plugin.tooltip then
				plugin.tooltip = FuBarTooltipFrame
			end
			if plugin.tooltip.SetOwner then
				plugin.tooltip:SetOwner(plugin.frame)
				plugin.tooltip.entered = plugin
				plugin.tooltip.enteredFrame = true
				plugin:UpdateTooltip()
			end
		end
	end
	
	function lib:FuBar_Plugin_HideTooltip(plugin)
		FuBarTooltip.Initialize()
		FuBar:Panel_OnLeave(plugin)
		if not plugin.tooltip or plugin:IsTooltipDetached() then
			return
		end
		if plugin.overrideTooltip and plugin.HideTooltip then
			plugin:HideTooltip()
		else
			if plugin.tooltip.IsOwned and plugin.tooltip:IsOwned(plugin.frame) then
				plugin.tooltip.enteredFrame = false
			end
		end
	end
	
	function lib:RegisterForLoad()
		if not self.defaults then
			self.defaults = {}
		end
		if not self.defaults.detachedTooltip then
			self.defaults.detachedTooltip = {}
		end
		
		if not self.cmd then
			local title = string.lower(self:GetTitle())
			self.cmd = AceChatCmd:new({"/" .. string.gsub(title, " ", "_"), "/" .. string.gsub(title, " ", "")}, {})
		end
		
		_,_,self.folderName = string.find(debugstack(2, 1, 0), "\\AddOns\\(.*)\\")
		
		self.versionNumber = VersionToNumber(self.version)
		
		if not self.frame then
			local name = "FuBarPlugin" .. self:GetTitle() .. "Frame"
			local frame = getglobal(name)
			if not frame or not getglobal(name .. "Text") or not getglobal(name .. "Icon") then
				frame = getmetatable(self).__index.CreateBasicPluginFrame(self, name)
				
				local icon = frame:CreateTexture(name .. "Icon", "ARTWORK")
				icon:SetWidth(16)
				icon:SetHeight(16)
				icon:SetPoint("LEFT", frame, "LEFT")
				
				local text = frame:CreateFontString(name .. "Text", "ARTWORK")
				text:SetWidth(134)
				text:SetHeight(24)
				text:SetPoint("LEFT", icon, "RIGHT", 0, 1)
				text:SetFontObject(GameFontNormal)
			end
			self.frame = frame
			self.textFrame = getglobal(name .. "Text")
			self.iconFrame = getglobal(name .. "Icon")
			
			self.frame:SetScript("OnEnter", function()
				this.stopClick = 0
				self:FuBar_Plugin_ShowTooltip(this.plugin)
			end)
			self.frame:SetScript("OnLeave", function()
				self:FuBar_Plugin_HideTooltip(this.plugin)
			end)
			self.frame:SetScript("OnMouseWheel", function()
				if not this.plugin:IsTooltipDetached() then
					this.plugin.tooltip:Scroll(arg1 < 0)
				end
			end)
			local OnMouseDown = self.frame:GetScript("OnMouseDown")
			self.frame:SetScript("OnMouseDown", function()
				if arg1 == "LeftButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
					self.tooltip:Hide()
				elseif arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
					self:FuBar_Plugin_OpenMenu(this.plugin)
					return
				end
				if OnMouseDown then
					OnMouseDown()
				end
			end)
			
			local name = self.frame:GetName()
			local menu = CreateFrame("Frame", name .. "Menu", frame)
			menu:Hide()
			local parentMenu = WorldMapZoneDropDown
			local parentName = parentMenu:GetName()
			menu:SetWidth(parentMenu:GetWidth())
			menu:SetHeight(parentMenu:GetHeight())
			
			local menuLeft = menu:CreateTexture(name .. "MenuLeft", "ARTWORK")
			local parentLeft = getglobal(parentName .. "Left")
			menuLeft:SetTexture(parentLeft:GetTexture())
			menuLeft:SetWidth(parentLeft:GetWidth())
			menuLeft:SetHeight(parentLeft:GetHeight())
			for i = 1, parentLeft:GetNumPoints() do
				menuLeft:SetPoint(parentLeft:GetPoint(i))
			end
			menuLeft:SetTexCoord(0, 0.1953125, 0, 1)
		
			local menuMiddle = menu:CreateTexture(name .. "MenuMiddle", "ARTWORK")
			local parentMiddle = getglobal(parentName .. "Middle")
			menuMiddle:SetTexture(parentMiddle:GetTexture())
			menuMiddle:SetWidth(parentMiddle:GetWidth())
			menuMiddle:SetHeight(parentMiddle:GetHeight())
			for i = 1, parentMiddle:GetNumPoints() do
				menuMiddle:SetPoint(parentMiddle:GetPoint(i))
			end
			menuMiddle:SetTexCoord(0.1953125, 0.8046875, 0, 1)
		
			local menuRight = menu:CreateTexture(name .. "MenuRight", "ARTWORK")
			local parentRight = getglobal(parentName .. "Right")
			menuRight:SetTexture(parentRight:GetTexture())
			menuRight:SetWidth(parentRight:GetWidth())
			menuRight:SetHeight(parentRight:GetHeight())
			for i = 1, parentRight:GetNumPoints() do
				menuRight:SetPoint(parentRight:GetPoint(i))
			end
			menuRight:SetTexCoord(0.8046875, 1, 0, 1)
			
			local menuText = menu:CreateFontString(name .. "MenuText", "ARTWORK")
			local parentText = getglobal(parentName .. "Text")
			menuText:SetWidth(parentText:GetWidth())
			menuText:SetHeight(parentText:GetHeight())
			for i = 1, parentText:GetNumPoints() do
				menuText:SetPoint(parentText:GetPoint(i))
			end
			menuText:SetFontObject(parentText:GetFontObject())
			
			local menuButton = CreateFrame("Button", name .. "MenuButton", menu)
			local parentButton = getglobal(parentName .. "Button")
			menuButton:SetWidth(parentButton:GetWidth())
			menuButton:SetHeight(parentButton:GetHeight())
			for i = 1, parentButton:GetNumPoints() do
				menuButton:SetPoint(parentButton:GetPoint(i))
			end
			
			menuButton:SetScript("OnClick", parentButton:GetScript("OnClick"))
			menuButton:SetScript("OnHide", parentButton:GetScript("OnHide"))
			
			local menuButtonNormalTexture = menuButton:CreateTexture(name .. "MenuButtonNormalTexture")
			local parentButtonNormalTexture = getglobal(parentName .. "ButtonNormalTexture")
			menuButtonNormalTexture:SetTexture(parentButtonNormalTexture:GetTexture())
			menuButtonNormalTexture:SetWidth(parentButtonNormalTexture:GetWidth())
			menuButtonNormalTexture:SetHeight(parentButtonNormalTexture:GetHeight())
			for i = 1, parentButtonNormalTexture:GetNumPoints() do
				menuButtonNormalTexture:SetPoint(parentButtonNormalTexture:GetPoint(i))
			end
			menuButton:SetNormalTexture(menuButtonNormalTexture)
			
			local menuButtonPushedTexture = menuButton:CreateTexture(name .. "MenuButtonPushedTexture")
			local parentButtonPushedTexture = getglobal(parentName .. "ButtonPushedTexture")
			menuButtonPushedTexture:SetTexture(parentButtonPushedTexture:GetTexture())
			menuButtonPushedTexture:SetWidth(parentButtonPushedTexture:GetWidth())
			menuButtonPushedTexture:SetHeight(parentButtonPushedTexture:GetHeight())
			for i = 1, parentButtonPushedTexture:GetNumPoints() do
				menuButtonPushedTexture:SetPoint(parentButtonPushedTexture:GetPoint(i))
			end
			menuButton:SetPushedTexture(menuButtonPushedTexture)
			
			local menuButtonDisabledTexture = menuButton:CreateTexture(name .. "MenuButtonDisabledTexture")
			local parentButtonDisabledTexture = getglobal(parentName .. "ButtonDisabledTexture")
			menuButtonDisabledTexture:SetTexture(parentButtonDisabledTexture:GetTexture())
			menuButtonDisabledTexture:SetWidth(parentButtonDisabledTexture:GetWidth())
			menuButtonDisabledTexture:SetHeight(parentButtonDisabledTexture:GetHeight())
			for i = 1, parentButtonDisabledTexture:GetNumPoints() do
				menuButtonDisabledTexture:SetPoint(parentButtonDisabledTexture:GetPoint(i))
			end
			menuButton:SetDisabledTexture(menuButtonDisabledTexture)
			
			local menuButtonHighlightTexture = menuButton:CreateTexture(name .. "MenuButtonHighlightTexture")
			local parentButtonHighlightTexture = getglobal(parentName .. "ButtonHighlightTexture")
			menuButtonHighlightTexture:SetTexture(parentButtonHighlightTexture:GetTexture())
			menuButtonHighlightTexture:SetWidth(parentButtonHighlightTexture:GetWidth())
			menuButtonHighlightTexture:SetHeight(parentButtonHighlightTexture:GetHeight())
			for i = 1, parentButtonHighlightTexture:GetNumPoints() do
				menuButtonHighlightTexture:SetPoint(parentButtonHighlightTexture:GetPoint(i))
			end
			menuButton:SetHighlightTexture(menuButtonHighlightTexture)
		else
			self.userDefinedFrame = true
		end
		
		self.frame.plugin = self
		self.frame:SetParent(UIParent)
		self.frame:SetPoint("RIGHT", UIParent, "LEFT", -5, 0)
		self.frame:Hide()
		
		if self.OnUpdate then
			if not self.updateTime then
				self.updateTime = 0.1
			end
			self._lastUpdate = 0
		end
		
		if not self.UpdateData then
			self.UpdateData = function(self) end
		end
		if not self.UpdateText then
			if self.hasNoText then
				self.UpdateText = function(self) end
			else
				self.UpdateText = function(self)
					self:SetText(self:GetTitle())
				end
			end
		end
		if not self.UpdateTooltip then
			self.UpdateTooltip = function(self) end
		end
		
		if self.hasIcon then
			self:SetIcon(self.hasIcon)
			
			if not self.cmd.options then
				self.cmd.options = {}
			end
			
			table.insert(self.cmd.options, {
				option = loc.ARGUMENT_SHOWICON,
				desc = loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON,
				method = "ToggleIconShown"
			})
			
			local old_Enable = self.Enable
			function self:Enable()
				if old_Enable then
					old_Enable(self)
				end
				if self.iconFrame then
					if self:IsIconShown() then
						self.iconFrame:Show()
					else
						self.iconFrame:Hide()
					end
				end
				self:CheckWidth(true)
			end
			
			local old_Report = self.Report
			if old_Report then
				function self:Report()
					old_Report(self)
					ace:print(" - ", format(ACE_CMD_REPORT_LINE, loc.ARGUMENT_SHOWICON, loc.MAP_ONOFF[self:IsIconShown() and 1 or 0]))
				end
			else
				function self:Report()
					local report = compost:Acquire(
						compost:AcquireHash(
							'text', loc.ARGUMENT_SHOWICON,
							'val', self:IsIconShown() and 1 or 0,
							'map', loc.MAP_ONOFF
						)
					)
					self.cmd:report(report)
					compost:Reclaim(report, 1)
				end
			end
		end
		
		if not self.textFrame or not self.hasIcon then
			self.cannotHideText = true
		end
		if not self.cannotHideText then
			table.insert(self.cmd.options, {
				option = loc.ARGUMENT_SHOWTEXT,
				desc = loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT,
				method = "ToggleTextShown"
			})
			
			local old_Enable = self.Enable
			function self:Enable()
				if old_Enable then
					old_Enable(self)
				end
				if self:IsTextShown() then
					self.textFrame:Show()
				else
					self.textFrame:Hide()
				end
				self:CheckWidth(true)
			end
			
			local old_Report = self.Report
			if old_Report then
				function self:Report()
					old_Report(self)
					ace:print(" - ", format(ACE_CMD_REPORT_LINE, loc.ARGUMENT_SHOWTEXT, loc.MAP_ONOFF[self:IsTextShown() and 1 or 0]))
				end
			else
				function self:Report()
					local report = compost:Acquire(
						compost:AcquireHash(
							'text', loc.ARGUMENT_SHOWTEXT,
							'val', self:IsTextShown() and 1 or 0,
							'map', loc.MAP_ONOFF
						)
					)
					self.cmd:report(report)
					compost:Reclaim(report, 1)
				end
			end
		end
		
		if self.hideWithoutStandby then
			self:EnableHideWithoutStandby()
		end
		
		local old_Enable = self.Enable
		function self:Enable()
			if old_Enable then
				old_Enable(self)
			end
			if not self.hideWithoutStandby or not self.data.hidden then
				self:Show()
			end
			self:RegisterEvent("ACE_PROFILE_LOADED", "_OnAceProfileLoaded")
			
			if not self.overrideTooltip and not self.cannotDetachTooltip and self.data.detachedTooltip and self.data.detachedTooltip.detached then
				self:DetachTooltip()
			end
			if self.OnUpdate then
				metro:Register(self:GetTitle(), self.OnUpdate, self.updateTime, self)
				metro:Start(self:GetTitle())
			end
		end
		
		if self.db then
			local old_Initialize = self.Initialize
			function self:Initialize()
				if self.queuedDebugs then
					for _,msg in ipairs(self.queuedDebugs) do
						self:debug(msg)
					end
					compost:Reclaim(self.queuedDebugs)
					self.queuedDebugs = nil
				end
				local t = self.db._table
				if not t.profiles then
					t.profiles = {}
				end
				if not t.profiles[self.profilePath[2]] then
					t.profiles[self.profilePath[2]] = {}
				end
				
				if not t.realms then
					t.realms = {}
				end
				if not t.realms[GetRealmName() .. UnitFactionGroup("player")] then
					t.realms[GetRealmName() .. UnitFactionGroup("player")] = {}
				end
				if type(self.chardb) ~= "string" then
					if not t.chars then
						t.chars = {}
					end
					if not t.chars[GetRealmName() .. UnitName("player")] then
						t.chars[GetRealmName() .. UnitName("player")] = {}
					end
					self.charData = t.chars[GetRealmName() .. UnitName("player")]
				else
					local c = getglobal(self.chardb)
					if type(c) ~= "table" then
						setglobal(self.chardb, {})
						c = getglobal(self.chardb)
					end
					self.charData = c
				end
				if not t.classes then
					t.classes = {}
				end
				if not t.classes[UnitClass("player")] then
					t.classes[UnitClass("player")] = {}
				end
				if not t.full then
					t.full = {}
				end
				self.data = t.profiles[self.profilePath[2]]
				inheritDefaults(self.data, self.defaults)
				self.realmData = t.realms[GetRealmName() .. UnitFactionGroup("player")]
				inheritDefaults(self.realmData, self.realmDefaults)
				inheritDefaults(self.charData, self.charDefaults)
				self.classData = t.classes[UnitClass("player")]
				inheritDefaults(self.classData, self.classDefaults)
				self.fullData = t.full
				inheritDefaults(self.fullData, self.fullDefaults)
				
				self.data.version = VersionToNumber(self.data.version)
				self.charData.version = VersionToNumber(self.charData.version)
				self.classData.version = VersionToNumber(self.classData.version)
				self.realmData.version = VersionToNumber(self.realmData.version)
				self.fullData.version = VersionToNumber(self.fullData.version)
				if self.data.version >= 500 then
					self.data.version = self.data.version / 100
					self.charData.version = self.charData.version / 100
					self.classData.version = self.classData.version / 100
					self.realmData.version = self.realmData.version / 100
					self.fullData.version = self.fullData.version / 100
				end
				
				if old_Initialize then
					old_Initialize(self)
				end
				
				self.data.version = VersionToNumber(self.version)
				self.charData.version = VersionToNumber(self.version)
				self.classData.version = VersionToNumber(self.version)
				self.realmData.version = VersionToNumber(self.version)
				self.fullData.version = VersionToNumber(self.version)
			end
		else
			local old_Initialize = self.Initialize
			function self:Initialize()
				if self.queuedDebugs then
					for _,msg in ipairs(self.queuedDebugs) do
						self:debug(msg)
					end
					self.queuedDebugs = nil
				end
				
				if not FuBarDB.pluginDB then
					FuBarDB.pluginDB = {}
				end
				
				if not FuBarDB.pluginDB[self:GetTitle()] then
					FuBarDB.pluginDB[self:GetTitle()] = {}
				end
				
				local t = FuBarDB.pluginDB[self:GetTitle()]
				
				if not t.profiles then
					t.profiles = {}
				end
				if not t.profiles[FuBar.profilePath[2]] then
					t.profiles[FuBar.profilePath[2]] = {}
				end
				if not t.realms then
					t.realms = {}
				end
				if not t.realms[GetRealmName() .. UnitFactionGroup("player")] then
					t.realms[GetRealmName() .. UnitFactionGroup("player")] = {}
				end
				if type(self.chardb) ~= "string" then
					if not t.chars then
						t.chars = {}
					end
					if not t.chars[GetRealmName() .. UnitName("player")] then
						t.chars[GetRealmName() .. UnitName("player")] = {}
					end
					self.charData = t.chars[GetRealmName() .. UnitName("player")]
				else
					local c = getglobal(self.chardb)
					if type(c) ~= "table" then
						setglobal(self.chardb, {})
						c = getglobal(self.chardb)
					end
					self.charData = c
				end
				if not t.classes then
					t.classes = {}
				end
				if not t.classes[UnitClass("player")] then
					t.classes[UnitClass("player")] = {}
				end
				if not t.full then
					t.full = {}
				end
				self.data = t.profiles[FuBar.profilePath[2]]
				inheritDefaults(self.data, self.defaults)
				self.realmData = t.realms[GetRealmName() .. UnitFactionGroup("player")]
				inheritDefaults(self.realmData, self.realmDefaults)
				inheritDefaults(self.charData, self.charDefaults)
				self.classData = t.classes[UnitClass("player")]
				inheritDefaults(self.classData, self.classDefaults)
				self.fullData = t.full
				inheritDefaults(self.fullData, self.fullDefaults)
				
				if old_Initialize then
					old_Initialize(self)
				end
				
				self.data.version = VersionToNumber(self.version)
				self.charData.version = VersionToNumber(self.version)
				self.classData.version = VersionToNumber(self.version)
				self.realmData.version = VersionToNumber(self.version)
				self.fullData.version = VersionToNumber(self.version)
				
				if self.data.disabled then
					self:DisableAddon()
				end
			end
		end
		
		local old_Disable = self.Disable
		function self:Disable()
			if old_Disable then
				old_Disable(self)
			end
			self:Hide()
			if self.OnUpdate then
				metro:Stop(self:GetTitle())
				metro:Unregister(self:GetTitle())
			end
		end
		
		self.cannotHideText = not self.canHideText
		self.canHideText = nil
		self.defaultPosition = self.showOnRight and "RIGHT" or "LEFT"
		self.showOnRight = nil
		self.menuFrame = getglobal(self.frame:GetName() .. "Menu")
		self.tooltip = FuBarTooltipFrame
		
		local old_Initialize = self.Initialize
		local initialized = false
		function self:Initialize()
			if initialized then
				return
			end
			initialized = true
			if old_Initialize then
				old_Initialize(self)
			end
		end
		
		local enabled = false
		local old_Enable = self.Enable
		function self:Enable()
			if not enabled and old_Enable then
				enabled = true
				old_Enable(self)
			elseif not old_Enable then
                enabled = true
			end
		end
		
		local old_Disable = self.Disable
		function self:Disable()
			if enabled and old_Disable then
				enabled = false
				old_Disable(self)
			elseif not old_Disable then
                enabled = false
			end
		end
		
		if not self.overrideTooltip then
			self._UpdateTooltip = self.UpdateTooltip
			function self:UpdateTooltip()
				local tooltip = self.tooltip
				if not tooltip then
					return
				end
				if tooltip.IsOwned and tooltip:IsOwned(self.frame) then
					tooltip:SetTitle(self:GetTitle())
					tooltip.updating = true
					tooltip:SetOwner(self.frame)
					if self._UpdateTooltip then
						tooltip.clickable = self.clickableTooltip
						local num = VersionToNumber(self.fuCompatible)
						if num >= 500 then
							num = num / 100
						end
						if num < 4.0023 then
							self.tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, true)
						else
							self:_UpdateTooltip()
						end
					end
					if tooltip:NumLines() == 0 then
						tooltip:_AddTitle()
					end
					tooltip:Show()
					if tooltip == FuBarTooltipFrame then
						local x, y = self.frame:GetCenter()
						local width = GetScreenWidth()
						local height = GetScreenHeight()
						local ratio = width / height
						local offset = 0
						if ratio >= 2.4 then
							if x < width/2 then
								if x < width/4 then
									anchor = "LEFT"
								else
									anchor = "RIGHT"
									local rx = self.frame:GetRight()
									if rx > width/2 then
										if x + rx > width then
											anchor = "LEFT"
											offset = -x + width/2
										else
											offset = -rx + width/2
										end
									end
								end
							else
								if x < width*3/4 then
									anchor = "LEFT"
								else
									anchor = "RIGHT"
								end
							end
						else
							if x < width/2 then
								anchor = "LEFT"
							else
								anchor = "RIGHT"
							end
						end
						tooltip:ClearAllPoints()
						local topAnchor, bottomAnchor
						if y > height/2 then
							topAnchor, bottomAnchor = "TOP", "BOTTOM"
						else
							topAnchor, bottomAnchor = "BOTTOM", "TOP"
						end
						tooltip:SetPoint(topAnchor .. anchor, self.frame, bottomAnchor .. anchor, offset, 0)
						if tooltip:GetRight() > GetScreenWidth() then
							tooltip:SetPoint(topAnchor .. anchor, self.frame, bottomAnchor .. anchor, offset + GetScreenWidth() - tooltip:GetRight(), 0)
						elseif tooltip:GetLeft() < 0 then
							tooltip:SetPoint(topAnchor .. anchor, self.frame, bottomAnchor .. anchor, offset - tooltip:GetLeft(), 0)
						end
					end
					tooltip.updating = false
				end
			end
		end
		
		FuBar:RegisterPlugin(self)
		AceAddon.RegisterForLoad(self)
	end
	
	function lib:new(o)
		local mt = { __index = self }
		if type(o) ~= "table" then
			o = {}
		end
		return setmetatable(o, mt)
	end
	
	function lib:CreateBasicPluginFrame(name)
		local frame = CreateFrame("Button", name, UIParent)
		frame:SetFrameStrata("HIGH")
		frame:EnableMouse(true)
		frame:EnableMouseWheel(true)
		frame:SetMovable(true)
		frame:SetWidth(150)
		frame:SetHeight(24)
		frame:SetPoint("CENTER", UIParent, "CENTER")
		
		frame:SetScript("OnClick", function()
			if type(self.OnClick) == "function" then
				self:OnClick()
			end
		end)
		frame:SetScript("OnDoubleClick", function()
			if type(self.OnDoubleClick) == "function" then
				self:OnDoubleClick()
			end
		end)
		frame:SetScript("OnMouseDown", function()
			if arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
				self:OpenMenu()
				return
			else
				HideDropDownMenu(1)
				if type(self.OnMouseDown) == "function" then
					self:OnMouseDown(arg1)
				end
			end
		end)
		frame:SetScript("OnMouseUp", function()
			if type(self.OnMouseUp) == "function" then
				self:OnMouseUp(arg1)
			end
		end)
		return frame
	end
	
	function lib:GetLibraryVersion()
		return MAJOR_VERSION, MINOR_VERSION
	end
	
	function lib:LibActivate(stub, oldLib, oldList)
	end
	
	function lib:LibDeactivate()
	end
	
	FuBarPlugin:Register(lib)
	lib = nil
	
	if not FuBarPlugin.new then
		function FuBarPlugin:new(o)
			self:GetInstance(MAJOR_VERSION):assert(type(o) == "table", "You must provide a table to register")
			local name
			if o.name then
				name = o.name .. ": "
			else
				name = ""
			end
			self:GetInstance(MAJOR_VERSION):assert(o.fuCompatible, name .. "You must provide a fuCompatible field.")
			local compatNumber = VersionToNumber(o.fuCompatible)
			if compatNumber >= 500 then
				compatNumber = compatNumber / 100
			end
			if compatNumber < 101 then
				return self:GetInstance("1.0"):new(o)
			elseif compatNumber < 103 then
				return self:GetInstance("1.2"):new(o)
			end
		end
	end
end

-- FuBarTooltip 1.0
do
	local compost = CompostLib:GetInstance('compost-1')
	
	local lib = {}
	local initialized = false
	local tooltip = CreateFrame("Frame", "FuBarTooltipFrame", UIParent)
	FuBarTooltipFrame = tooltip
	
	local function NewLine(self)
		if self.maxLines <= self.numLines then
			self.maxLines = self.maxLines + 1
			local name = self:GetName() or "FuBarTooltipFrame"
			local button = CreateFrame("Button", name .. "Button" .. self.maxLines, self)
			local check = button:CreateTexture(name .. "Check" .. self.maxLines, "ARTWORK")
			local left = button:CreateFontString(name .. "TextLeft" .. self.maxLines, "ARTWORK")
			local right = button:CreateFontString(name .. "TextRight" .. self.maxLines, "ARTWORK")
			table.insert(self.buttons, button)
			table.insert(self.checks, check)
			table.insert(self.lefts, left)
			table.insert(self.rights, right)
			left:SetWidth(0)
			if self.maxLines == 1 then
				left:SetFontObject(GameTooltipHeaderText)
				right:SetFontObject(GameTooltipHeaderText)
				left:SetJustifyH("CENTER")
				button:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10)
				button:SetScript("OnEnter", self:GetScript("OnEnter"))
				button:SetScript("OnLeave", self:GetScript("OnLeave"))
			else
				left:SetFontObject(GameTooltipText)
				right:SetFontObject(GameTooltipText)
				button:SetPoint("TOPLEFT", self.buttons[self.maxLines - 1], "BOTTOMLEFT", 0, -2)
				button:SetScript("OnEnter", self.buttons[1]:GetScript("OnEnter"))
				button:SetScript("OnLeave", self.buttons[1]:GetScript("OnLeave"))
			end
			button:SetPoint("RIGHT", self, "RIGHT", -10, 0)
			check.shown = false
			check:SetPoint("LEFT", button, "LEFT")
			left:SetPoint("LEFT", check, "LEFT")
			right:SetPoint("LEFT", left, "RIGHT", 40, 0)
			local _,size = GameTooltipText:GetFont()
			check:SetHeight(size)
			check:SetWidth(size)
			check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
			check:SetAlpha(0)
			button:SetScript("OnMouseWheel", self:GetScript("OnMouseWheel"))
			button:EnableMouseWheel(TRUE)
			button:Hide()
			check:Show()
			left:Hide()
			right:Hide()
		end
	end
	
	local function GetMaxLinesPerScreen(self)
		if self == tooltip then
			return floor(50 / self:GetFontSizePercent())
		else
			return floor(30 / self:GetFontSizePercent())
		end
	end
	
	local _,headerSize = GameTooltipHeaderText:GetFont()
	local _,normalSize = GameTooltipText:GetFont()
	local backdrop = {
		bgFile = "Interface\\Buttons\\WHITE8X8",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = TRUE,
		tileSize = 16,
		edgeSize = 16,
		insets = {
			left = 5,
			right = 5,
			top = 5,
			bottom = 5,
		},
	}
	
	function lib.Initialize()
		if tooltip.SetOwner then
			return
		end
		
		local data = FuBar.data
		if not data then
			data = FuBar.db and FuBar.db._table and FuBar.db._table.profiles and FuBar.db._table.profiles[FuBar.profilePath[2]]
		end
		
		tooltip:EnableMouse(TRUE)
		tooltip:EnableMouseWheel(TRUE)
		tooltip:SetFrameStrata("TOOLTIP")
		tooltip:SetBackdrop(backdrop)
		tooltip:SetBackdropColor(0, 0, 0, 1)
		
		tooltip.numLines = 0
		tooltip.categoryLines = {}
		tooltip.idLines = {}
		tooltip.categories = 0
		tooltip.owner = nil
		tooltip.fontSizePercent = data and data.tooltip and data.tooltip.fontSizePercent or 1
		tooltip.maxLines = 0
		tooltip.buttons = {}
		tooltip.checks = {}
		tooltip.lefts = {}
		tooltip.rights = {}
		tooltip.transparency = data and data.tooltip and data.tooltip.transparency or 0.75
		tooltip.r = data and data.tooltip and data.tooltip.r or 0
		tooltip.g = data and data.tooltip and data.tooltip.g or 0
		tooltip.b = data and data.tooltip and data.tooltip.b or 0
		tooltip:SetBackdropColor(tooltip.r, tooltip.g, tooltip.b, tooltip.transparency)
		tooltip:SetBackdropBorderColor(1, 1, 1, tooltip.transparency)
		tooltip.scroll = 0
		
		tooltip:SetScript("OnUpdate", function()
			if not tooltip.updating and not tooltip.enteredFrame then
				tooltip.scroll = 0
				tooltip:Hide()
			end
		end)
		
		tooltip:SetScript("OnEnter", function()
			if tooltip.clickable and not tooltip.updating then
				tooltip.enteredFrame = TRUE
			end
		end)
		
		tooltip:SetScript("OnLeave", function()
			if not tooltip.updating then
				tooltip.enteredFrame = FALSE
			end
		end)
		
		local tooltip_AddLine
		local tooltip_AddBlankLine
		local tooltip_AddDoubleLine
		
		NewLine(tooltip)
		
		tooltip.hint = tooltip:CreateFontString("FuBarTooltipFrameTextHint", "ARTWORK")
		tooltip.hint:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2)
		tooltip.hint:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10)
		tooltip.hint:SetFontObject(GameTooltipText)
		tooltip.hint:Hide()
		local font,_,flags = tooltip.hint:GetFont()
		tooltip.hint:SetFont(font, normalSize * tooltip.fontSizePercent, flags)
		
		tooltip.scrollUp = tooltip:CreateFontString("FuBarTooltipFrameTextScrollUp", "ARTWORK")
		tooltip.scrollUp:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2)
		tooltip.scrollUp:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10)
		tooltip.scrollUp:SetFontObject(GameTooltipText)
		tooltip.scrollUp:Hide()
		local font,_,flags = tooltip.scrollUp:GetFont()
		tooltip.scrollUp:SetFont(font, normalSize * tooltip.fontSizePercent, flags)
		tooltip.scrollUp:SetJustifyH("CENTER")
		tooltip.scrollUp:SetTextColor(1, 0.823529, 0)
		tooltip.scrollUp:SetText(" ")
		
		tooltip.scrollDown = tooltip:CreateFontString("FuBarTooltipFrameTextScrollUp", "ARTWORK")
		tooltip.scrollDown:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2)
		tooltip.scrollDown:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10)
		tooltip.scrollDown:SetFontObject(GameTooltipText)
		tooltip.scrollDown:Hide()
		local font,_,flags = tooltip.scrollUp:GetFont()
		tooltip.scrollDown:SetFont(font, normalSize * tooltip.fontSizePercent, flags)
		tooltip.scrollDown:SetJustifyH("CENTER")
		tooltip.scrollDown:SetTextColor(1, 0.823529, 0)
		tooltip.scrollDown:SetText(" ")
		
		tooltip:SetScript("OnMouseWheel", function()
			tooltip.updating = true
			tooltip:Scroll(arg1 < 0)
			tooltip.updating = false
		end)
		
		function tooltip:SetOwner(o)
			self:Hide(o)
			self.owner = o
		end
		
		function tooltip:IsOwned(o)
			return self.owner == o
		end
		
		function tooltip:ClearLines()
			for i = 1, self.numLines do
				local button = self.buttons[i]
				local check = self.checks[i]
				local left = self.lefts[i]
				local right = self.rights[i]
				button:Hide()
				button:SetScript("OnClick", nil)
				left:Hide()
				right:Hide()
				check.shown = false
				check:SetAlpha(0)
				left:SetText("")
				right:SetText("")
				left:SetTextColor(1, 0.823529, 0)
				right:SetTextColor(1, 0.823529, 0)
			end
			for key,_ in pairs(self.categoryLines) do
				self.categoryLines[key] = nil
			end
			for key,_ in pairs(self.idLines) do
				if self:IsChecked(key) then
					self:ToggleChecked(key)
				end
				self.idLines[key] = nil
			end
			self.hint:Hide()
			self.hint:SetText("")
			self.numLines = 0
			self.categories = 0
		end
		
		function tooltip:NumLines()
			return self.numLines
		end
		
		local lastWidth
		local old_tooltip_Hide = tooltip.Hide
		function tooltip:Hide(newOwner)
			if self == tooltip or newOwner == nil then
				old_tooltip_Hide(self)
			end
			self:ClearLines()
			self.owner = nil
			self.lastWidth = nil
		end
		
		tooltip.currentTitle = "Title"
		local addingTitle = FALSE
		local function AddTitle(self)
			if self ~= tooltip then
				return
			end
			if self.numLines >= 1 then
				self.lefts[1]:SetText(self.currentTitle)
				self.lefts[1]:SetJustifyH("CENTER")
				self.lefts[1]:Show()
				self.lefts[1]:SetTextColor(1, 0.823529, 0)
			else
				addingTitle = TRUE
				tooltip_AddLine(self, nil, self.currentTitle, nil, nil, nil, FALSE, "CENTER", GameTooltipHeaderText)
				addingTitle = FALSE
			end
		end
		
		function tooltip:_AddTitle()
			AddTitle(self)
		end
		
		local old_tooltip_Show = tooltip.Show
		function tooltip:Show()
			if self.owner == nil or self.notInUse then
				return
			end
			old_tooltip_Show(self)
			
			if self.numLines == 0 then
				AddTitle(self)
			end
			if self.numLines == 0 then
				self:AddLine(nil, self.currentTitle)
			end
			
			local maxWidth = 0
			local hasWrap = FALSE
			local screenWidth = GetScreenWidth()
			local scrollMax = self.numLines
			if scrollMax > GetMaxLinesPerScreen(self) + self.scroll then
				scrollMax = GetMaxLinesPerScreen(self) + self.scroll
			end
			for i = 1, self.numLines do
				local button = self.buttons[i]
				local check = self.checks[i]
				local left = self.lefts[i]
				local right = self.rights[i]
				left:SetWidth(screenWidth)
				right:SetWidth(screenWidth)
				local checkWidth = 0
				if check.shown then
					checkWidth = check:GetWidth()
				end
				local width = checkWidth + left:GetStringWidth()
				if right:GetText() ~= nil then
					width = width + 40 + right:GetStringWidth()
				elseif left.wrap then
					hasWrap = TRUE
					if width > 180*self:GetFontSizePercent() then
						width = 180*self:GetFontSizePercent()
					end
				end
				if width > maxWidth then
					maxWidth = width
				end
			end
			local height = 20
			if self.hint:GetText() ~= nil then
				self.hint:ClearAllPoints()
				if self.numLines == 1 then
					self.hint:SetPoint("TOPLEFT", self.buttons[1], "BOTTOMLEFT", 0, -2)
				elseif self.numLines == 0 then
					local text = self.hint:GetText()
					self.hint:Hide()
					self.hint:SetText("")
					self:AddLine(nil, text, 0, 1, 0, TRUE)
					self:Show()
					return
				elseif scrollMax == self.numLines then
					self.hint:SetPoint("TOPLEFT", self.buttons[self.numLines], "BOTTOMLEFT", 0, -16)
				else
					self.hint:SetPoint("TOPLEFT", self.scrollDown, "BOTTOMLEFT", 0, -16)
				end
				self.hint:SetWidth(500)
				local width = self.hint:GetStringWidth()
				if width > 180*self:GetFontSizePercent() then
					width = 180*self:GetFontSizePercent()
				end
				if maxWidth > width then
					width = maxWidth
				end
				self.hint:SetWidth(width)
				if width > maxWidth then
					local h = self.hint:GetHeight()
					while width > 10 do
						width = width - 5
						self.hint:SetWidth(width)
						if self.hint:GetHeight() ~= h then
							width = width + 5
							self.hint:SetWidth(width)
							break
						end
					end
				end
				if width > maxWidth then
					maxWidth = width
				end
				if self.numLines == 1 then
					height = height + self.hint:GetHeight() + 2
				else
					height = height + self.hint:GetHeight() + 16
				end
			end
			if scrollMax ~= self.numLines then
				self.scrollDown:SetWidth(500)
				local width = self.scrollDown:GetStringWidth()
				if width > 180*self:GetFontSizePercent() then
					width = 180*self:GetFontSizePercent()
				end
				if maxWidth > width then
					width = maxWidth
				end
				self.scrollDown:SetWidth(width)
				if width > maxWidth then
					maxWidth = width
				end
				height = height + self.scrollDown:GetHeight() + 2
			end
			if self.scroll ~= 0 then
				self.scrollUp:SetWidth(500)
				local width = self.scrollDown:GetStringWidth()
				if width > 180*self:GetFontSizePercent() then
					width = 180*self:GetFontSizePercent()
				end
				if maxWidth > width then
					width = maxWidth
				end
				self.scrollUp:SetWidth(width)
				if width > maxWidth then
					maxWidth = width
				end
				height = height + self.scrollUp:GetHeight() + 2
			end
			self:SetWidth(maxWidth + 20)
			for i = 1, self.numLines do
				self.buttons[i]:ClearAllPoints()
				self.buttons[i]:Hide()
			end
			local tmp = self.scroll + 1
			if tmp ~= 1 then
				tmp = tmp + 1
			end
			for i = tmp, scrollMax do
				if i == scrollMax and i ~= self.numLines then
					break
				end
				local button = self.buttons[i]
				local left = self.lefts[i]
				local right = self.rights[i]
				if right:GetText() ~= nil then
					left:SetWidth(left:GetStringWidth())
					right:ClearAllPoints()
					right:SetPoint("LEFT", left, "RIGHT", 40, 0)
					right:SetPoint("RIGHT", button, "RIGHT")
				else
					local check = self.checks[i]
					if check.shown then
						left:SetWidth(maxWidth - check:GetWidth())
					else
						left:SetWidth(maxWidth)
					end
				end
				height = height + left:GetHeight() + 2
				button:SetWidth(maxWidth)
				button:SetHeight(left:GetHeight())
				if i == self.scroll + 1 then
					button:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10)
				else
					button:SetPoint("TOPLEFT", self.buttons[i - 1], "BOTTOMLEFT", 0, -2)
				end
				button:Show()
			end
			if self.scroll ~= 0 then
				self.scrollUp:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10)
				self.buttons[self.scroll + 2]:SetPoint("TOPLEFT", self.scrollUp, "BOTTOMLEFT", 0, -2)
				self.scrollUp:SetText(loc.TEXT_SCROLL_UP .. " (" .. self.scroll + 2 .. " / " .. self.numLines .. ")")
				self.scrollUp:Show()
			else
				self.scrollUp:Hide()
			end
			if scrollMax ~= self.numLines and self.buttons[scrollMax - 1] then
				self.scrollDown:SetPoint("TOPLEFT", self.buttons[scrollMax - 1], "BOTTOMLEFT", 0, -2)
				self.scrollDown:SetText(loc.TEXT_SCROLL_DOWN .. " (" .. scrollMax - 1 .. " / " .. self.numLines .. ")")
				self.scrollDown:Show()
			else
				self.scrollDown:Hide()
			end
			self:SetHeight(height)
		end
		
		function tooltip:SetHint(text)
			if self == tooltip then
				self.hint:Show()
				self.hint:SetText(loc.TEXT_HINT .. ": " .. text)
				self.hint:SetTextColor(0, 1, 0)
				
				if self:IsShown() then
					self:Show()
				end
			end
		end
		
		function tooltip:SetTitle(text)
			if text == nil or text == "" then
				text = "Title"
			end
			self.currentTitle = text
			AddTitle(self)
			
			if self:IsShown() then
				self:Show()
			end
		end
		
		local addingCategory = FALSE
		local function ShiftDown(self, num)
			self.numLines = self.numLines + 1
			NewLine(self)
			self.lefts[self.numLines]:Show()
			self.buttons[self.numLines]:Show()
			for i = self.numLines - 1, num, -1 do
				local buttonUp = self.buttons[i]
				local buttonDown = self.buttons[i + 1]
				local checkUp = self.checks[i]
				local checkDown = self.checks[i + 1]
				local leftUp = self.lefts[i]
				local leftDown = self.lefts[i + 1]
				local rightUp = self.rights[i]
				local rightDown = self.rights[i + 1]
				buttonDown:SetScript("OnClick", buttonUp:GetScript("OnClick"))
				if rightUp:IsShown() then
					rightDown:Show()
				else
					rightDown:Hide()
				end
				if checkUp.shown then
					checkDown.shown = true
					leftDown:SetPoint("LEFT", checkDown, "RIGHT")
				else
					checkDown.shown = false
					leftDown:SetPoint("LEFT", checkDown, "LEFT")
				end
				checkDown:SetAlpha(checkUp:GetAlpha())
				checkDown:SetWidth(checkUp:GetWidth())
				checkDown:SetHeight(checkUp:GetHeight())
				leftDown:SetJustifyH(leftUp:GetJustifyH())
				rightDown:SetJustifyH("RIGHT")
				leftDown:SetText(leftUp:GetText())
				rightDown:SetText(rightUp:GetText())
				leftDown:SetTextColor(leftUp:GetTextColor())
				rightDown:SetTextColor(rightUp:GetTextColor())
				leftDown:SetFont(leftUp:GetFont())
				rightDown:SetFont(rightUp:GetFont())
			end
			if num <= self.numLines - 1 then
				local check = self.checks[num]
				local left = self.lefts[num]
				local right = self.rights[num]
				check:SetAlpha(0)
				check.shown = false
				left:SetJustifyH("LEFT")
				left:SetText("")
				left:Show()
				right:SetText("")
				right:Hide()
			end
			if not addingCategory then
				for name,line in pairs(self.categoryLines) do
					if line >= num then
						self.categoryLines[name] = self.categoryLines[name] + 1
					end
				end
			end
			for name,line in pairs(self.idLines) do
				if line >= num then
					self.idLines[name] = self.idLines[name] + 1
				end
			end
		end
		
		function tooltip:IsChecked(id)
			local i = self.idLines[id]
			if i == nil then
				return
			end
			local check = self.checks[i]
			if check == nil or not check.shown then
				return
			end
			return check:GetAlpha() == 1
		end
		
		function tooltip:ToggleChecked(id)
			local i = self.idLines[id]
			if i == nil then
				return
			end
			local check = self.checks[i]
			if check == nil or not check.shown then
				return
			end
			if check:GetAlpha() == 1 then
				check:SetAlpha(0)
				return false
			else
				check:SetAlpha(1)
				return true
			end
		end
		
		function tooltip:GetCheckTexture(id)
			local i = self.idLines[id]
			if i == nil then
				return
			end
			local check = self.checks[i]
			if check == nil or not check.shown then
				return
			end
			return check:GetTexture()
		end
		
		function tooltip:SetCheckTexture(id, texture)
			local i = self.idLines[id]
			if i == nil then
				return
			end
			local check = self.checks[i]
			if check == nil or not check.shown then
				return
			end
			return check:SetTexture(texture)
		end
		
		function tooltip:AddCategory(name, lText, rText, func, checked, checkTexture, hideBlankLine)
			FuBarPlugin:GetInstance(MAJOR_VERSION):assert(name ~= nil, "You must provide a name for the category")
			if self.categoryLines[name] ~= nil then
				return
			end
			AddTitle(self)
			self.categories = self.categories + 1
			if hideBlankLine and (lText ~= nil or rText ~= nil) then
				addingCategory = TRUE
				if rText ~= nil then
					tooltip_AddDoubleLine(self, name, lText or "", rText, 1, 1, 1, 1, 1, 1, nil, name, func, checked, checkTexture)
				elseif lText ~= nil then
					tooltip_AddLine(self, name, lText, 1, 1, 1, TRUE, nil, nil, name, func, checked, checkTexture)
				end
				addingCategory = FALSE
				self.categoryLines[name] = self.numLines + 1
			else
				if self.numLines > 1 or self.categories > 1 then
					addingCategory = TRUE
					tooltip_AddBlankLine(self, name)
					addingCategory = FALSE
				end
				self.categoryLines[name] = self.numLines + 1
				if rText ~= nil then
					tooltip_AddDoubleLine(self, name, lText or "", rText, 1, 1, 1, 1, 1, 1, nil, name, func, checked, checkTexture)
				elseif lText ~= nil then
					tooltip_AddLine(self, name, lText, 1, 1, 1, TRUE, nil, nil, name, func, checked, checkTexture)
				end
			end
		end
		
		function tooltip:AddBlankLine(category)
			if self.preventNextBlank then
				self.preventNextBlank = FALSE
			else
				tooltip_AddLine(self, category, "\n")
			end
		end
		
		function tooltip:AddLine(category, text, r, g, b, wrap, justify, size, id, func, checked, checkTexture)
			if text == nil or text == "" then
				text = "\n"
				if self.preventNextBlank then
					self.preventNextBlank = FALSE
					return
				end
				r, g, b, wrap, justify, size, id, func, checked = nil
			end
			if not addingTitle then
				AddTitle(self)
			end
			
			local num
			if not addingCategory and category ~= nil then
				FuBarPlugin:GetInstance(MAJOR_VERSION):assert(self.categoryLines[category] ~= nil, "Category '" .. tostring(category) .. "' does not exist.")
				ShiftDown(self, self.categoryLines[category])
				num = self.categoryLines[category] - 1
			else
				ShiftDown(self, self.numLines + 1)
				num = self.numLines
			end
			
			if id ~= nil and self.idLines[id] == nil then
				self.idLines[id] = num
			end
			local button = self.buttons[num]
			local left = self.lefts[num]
			local right = self.rights[num]
			local check = self.checks[num]
			left:SetText(text)
			right:SetText("")
			left:Show()
			if b == nil then
				left:SetTextColor(1, 0.823529, 0)
			else
				left:SetTextColor(r, g, b)
			end
			left.wrap = wrap
			if type(size) == "table" and size:IsObjectType("Font") then
				left:SetFontObject(size)
				right:SetFontObject(size)
				_,size = size:GetFont()
				size = size * self:GetFontSizePercent()
			else
				left:SetFontObject(GameTooltipText)
				right:SetFontObject(GameTooltipText)
				size = (size or normalSize) * self:GetFontSizePercent()
			end
			local font,_,flags = left:GetFont()
			left:SetFont(font, size, flags)
			check:SetWidth(size)
			check:SetHeight(size)
			if checked ~= nil then
				check.shown = true
				check:Show()
				check:SetTexture(checkTexture or "Interface\\Buttons\\UI-CheckBox-Check")
				check:SetAlpha(checked and 1 or 0)
				left:SetPoint("LEFT", check, "RIGHT")
			else
				left:SetPoint("LEFT", check, "LEFT")
			end
			if false and text == "\n" then
				left:SetHeight(size)
			else
				left:SetHeight(0)
			end
			left:SetJustifyH(justify or "LEFT")
			if self:IsShown() then
				self:Show()
			end
			if not self.locked or IsAltKeyDown() then
				if type(func) == "string" then
					local plugin = self.entered
					if self ~= tooltip then
						plugin = self.owner.plugin
					end
					if plugin[func] ~= nil then
						button:SetScript("OnMouseUp", function()
							if self:HasScript("OnMouseUp") and self:GetScript("OnMouseUp") then
								self:GetScript("OnMouseUp")()
							end
							if arg1 == "RightButton" then
								if self:HasScript("OnClick") and self:GetScript("OnClick") then
									self:GetScript("OnClick")()
								end
							else
								if self.preventClick == nil or GetTime() > self.preventClick then
									self.preventClick = nil
									self.updating = true
									plugin[func](plugin, id, arg1)
									self.updating = false
								end
							end
						end)
						button:SetScript("OnMouseDown", self:GetScript("OnMouseDown"))
						button:EnableMouse(TRUE)
					else
						button:SetScript("OnMouseDown", nil)
						button:SetScript("OnMouseUp", nil)
						button:EnableMouse(FALSE)
					end
				elseif type(func) == "function" then
					button:SetScript("OnMouseUp", function()
						if self:HasScript("OnMouseUp") and self:GetScript("OnMouseUp") then
							self:GetScript("OnMouseUp")()
						end
						if arg1 == "RightButton" then
							if self:HasScript("OnClick") and self:GetScript("OnClick") then
								self:GetScript("OnClick")()
							end
						else
							if self.preventClick == nil or GetTime() > self.preventClick then
								self.preventClick = nil
								self.updating = true
								func(id, arg1)
								self.updating = false
							end
						end
					end)
					button:SetScript("OnMouseDown", self:GetScript("OnMouseDown"))
					button:EnableMouse(TRUE)
				else
					button:SetScript("OnMouseDown", nil)
					button:SetScript("OnMouseUp", nil)
					button:EnableMouse(FALSE)
				end
			else
				button:SetScript("OnMouseDown", nil)
				button:SetScript("OnMouseUp", nil)
				button:EnableMouse(FALSE)
			end
		end
		
		function tooltip:AddDoubleLine(category, lText, rText, lr, lg, lb, rr, rg, rb, size, id, func, checked, checkTexture)
			if (lText == nil or lText == "") and (rText == nil or rText == "") then
				tooltip_AddBlankLine(self, category)
				return
			elseif lText == nil or lText == "" then
				tooltip_AddLine(self, category, rText, rr, rg, rb, FALSE, "RIGHT", size, id, func, checked)
				return
			elseif rText == nil or rText == "" then
				tooltip_AddLine(self, category, lText, lr, lg, lb, FALSE, "LEFT", size, id, func, checked)
				return
			end
			AddTitle(self)
			
			local num
			if category ~= nil then
				FuBarPlugin:GetInstance(MAJOR_VERSION):assert(self.categoryLines[category] ~= nil, "Category '" .. category .. "' does not exist.")
				ShiftDown(self, self.categoryLines[category])
				num = self.categoryLines[category] - 1
			else
				ShiftDown(self, self.numLines + 1)
				num = self.numLines
			end
			
			if id ~= nil and self.idLines[id] == nil then
				self.idLines[id] = num
			end
			local button = self.buttons[num]
			local left = self.lefts[num]
			local right = self.rights[num]
			local check = self.checks[num]
			left:SetText(lText)
			right:SetText(rText)
			left:Show()
			right:Show()
			if lb ~= nil then
				left:SetTextColor(lr, lg, lb)
				if rb ~= nil then
					right:SetTextColor(rr, rg, rb)
				else
					right:SetTextColor(1, 0.823529, 0)
				end
			else
				left:SetTextColor(1, 0.823529, 0)
				right:SetTextColor(1, 0.823529, 0)
			end
			left.wrap = FALSE
			if type(size) == "table" and size:IsObjectType("Font") then
				left:SetFontObject(size)
				right:SetFontObject(size)
				_,size = size:GetFont()
				size = size * self:GetFontSizePercent()
			else
				size = (size or normalSize) * self:GetFontSizePercent()
			end
			local font,_,flags = left:GetFont()
			left:SetFont(font, size, flags)
			right:SetFont(font, size, flags)
			check:SetWidth(size)
			check:SetHeight(size)
			if checked ~= nil then
				check.shown = true
				check:Show()
				check:SetTexture(checkTexture or "Interface\\Buttons\\UI-CheckBox-Check")
				check:SetAlpha(checked and 1 or 0)
				left:SetPoint("LEFT", check, "RIGHT")
			else
				left:SetPoint("LEFT", check, "LEFT")
			end
			left:SetHeight(0)
			left:SetJustifyH("LEFT")
			right:SetJustifyH("RIGHT")
			if self:IsShown() then
				self:Show()
			end
			if not self.locked or IsAltKeyDown() then
				if type(func) == "string" then
					local plugin = self.entered
					if self ~= tooltip then
						plugin = self.owner.plugin
					end
					if plugin[func] ~= nil then
						button:SetScript("OnMouseDown", self:GetScript("OnMouseDown"))
						button:SetScript("OnMouseUp", function()
							if self:HasScript("OnMouseUp") and self:GetScript("OnMouseUp") then
								self:GetScript("OnMouseUp")()
							end
							if arg1 == "RightButton" then
								if self:HasScript("OnClick") and self:GetScript("OnClick") then
									self:GetScript("OnClick")()
								end
							else
								if self.preventClick == nil or GetTime() > self.preventClick then
									self.preventClick = nil
									self.updating = true
									plugin[func](plugin, id, arg1)
									self.updating = false
								end
							end
						end)
						button:EnableMouse(TRUE)
					else
						button:SetScript("OnMouseDown", nil)
						button:SetScript("OnMouseUp", nil)
						button:EnableMouse(FALSE)
					end
				elseif type(func) == "function" then
					button:SetScript("OnMouseDown", self:GetScript("OnMouseDown"))
					button:SetScript("OnMouseUp", function()
						if self:HasScript("OnMouseUp") and self:GetScript("OnMouseUp") then
							self:GetScript("OnMouseUp")()
						end
						if arg1 == "RightButton" then
							if self:HasScript("OnClick") and self:GetScript("OnClick") then
								self:GetScript("OnClick")()
							end
						else
							if self.preventClick == nil or GetTime() > self.preventClick then
								self.preventClick = nil
								self.updating = true
								func(id, arg1)
								self.updating = false
							end
						end
					end)
					button:EnableMouse(TRUE)
				else
					button:SetScript("OnMouseDown", nil)
					button:SetScript("OnMouseUp", nil)
					button:EnableMouse(FALSE)
				end
			else
				button:SetScript("OnMouseDown", nil)
				button:SetScript("OnMouseUp", nil)
				button:EnableMouse(FALSE)
			end
		end
		
		function tooltip:GetNormalFontSize()
			return normalSize
		end
		
		function tooltip:GetHeaderFontSize()
			return headerSize
		end
		
		function tooltip:GetNormalFontObject()
			return GameTooltipText
		end
		
		function tooltip:GetHeaderFontObject()
			return GameTooltipHeaderText
		end
		
		function tooltip:SetFontSizePercent(percent)
			local lastSize = self:GetFontSizePercent()
			percent = tonumber(percent) or 1
			if percent < 0.25 then
				percent = 0.25
			elseif percent > 4 then
				percent = 4
			end
			self.fontSizePercent = percent
			local t
			if self == tooltip then
				t = FuBar.data.tooltip
			else
				t = self.owner.plugin.data.detachedTooltip
			end
			t.fontSizePercent = percent ~= 1 and percent or nil
			local font,_,flags = self.hint:GetFont()
			self.hint:SetFont(font, normalSize * self:GetFontSizePercent(), flags)
			self.scrollUp:SetFont(font, normalSize * self:GetFontSizePercent(), flags)
			self.scrollDown:SetFont(font, normalSize * self:GetFontSizePercent(), flags)
			local ratio = self:GetFontSizePercent() / lastSize
			for i = 1, self.numLines do
				local left = self.lefts[i]
				local right = self.rights[i]
				local check = self.checks[i]
				local font, size, flags = left:GetFont()
				left:SetFont(font, size * ratio, flags)
				right:SetFont(font, size * ratio, flags)
				check:SetWidth(check:GetWidth() * ratio)
				check:SetHeight(check:GetHeight() * ratio)
			end
			if self:IsShown() then
				self:Show()
			end
		end
		
		function tooltip:GetFontSizePercent()
			local t
			if self == tooltip then
				t = FuBar.data.tooltip
			else
				t = self.owner.plugin.data.detachedTooltip
			end
			return t.fontSizePercent or 1
		end
	
		function tooltip:SetTransparency(alpha)
			self.transparency = alpha
			if self == tooltip then
				FuBar.data.tooltip.transparency = alpha ~= 0.75 and alpha or nil
			else
				self.owner.plugin.data.detachedTooltip.transparency = alpha ~= 0.75 and alpha or nil
			end
			self:SetBackdropColor(self.r or 0, self.g or 0, self.b or 0, alpha)
			self:SetBackdropBorderColor(1, 1, 1, alpha)
		end
		
		function tooltip:GetTransparency()
			local t
			if self == tooltip then
				t = FuBar.data.tooltip
			else
				t = self.owner.plugin.data.detachedTooltip
			end
			return t.transparency or 0.75
		end
		
		function tooltip:SetColor(r, g, b)
			self.r = r
			self.g = g
			self.b = b
			if self == tooltip then
				FuBar.data.tooltip.r = r ~= 0 and r or nil
				FuBar.data.tooltip.g = g ~= 0 and g or nil
				FuBar.data.tooltip.b = b ~= 0 and b or nil
			else
				self.owner.plugin.data.detachedTooltip.r = r ~= 0 and r or nil
				self.owner.plugin.data.detachedTooltip.g = g ~= 0 and g or nil
				self.owner.plugin.data.detachedTooltip.b = b ~= 0 and b or nil
			end
			self:SetBackdropColor(self.r or 0, self.g or 0, self.b or 0, alpha)
			self:SetBackdropBorderColor(1, 1, 1, alpha)
		end
		
		function tooltip:GetColor()
			local t
			if self == tooltip then
				t = FuBar.data.tooltip
			else
				t = self.owner.plugin.data.detachedTooltip
			end
			return t.r or 0, t.g or 0, t.b or 0
		end
		
		function tooltip:Scroll(down)
			if down then
				if IsShiftKeyDown() then
					self.scroll = self.numLines - GetMaxLinesPerScreen(self)
				else
					self.scroll = self.scroll + 3
				end
			else
				if IsShiftKeyDown() then
					self.scroll = 0
				else
					self.scroll = self.scroll - 3
				end
			end
			if self.scroll > self.numLines - GetMaxLinesPerScreen(self) then
				self.scroll = self.numLines - GetMaxLinesPerScreen(self)
			end
			if self.scroll < 0 then
				self.scroll = 0
			end
			if self:IsShown() then
				self:Show()
			end
		end
		
		tooltip_AddLine = tooltip.AddLine
		tooltip_AddBlankLine = tooltip.AddBlankLine
		tooltip_AddDoubleLine = tooltip.AddDoubleLine
		
		FuBarTooltip.SetHint = function(self, hint)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.SetTitle = function(self, title)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.IsChecked = function(self, id)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.ToggleChecked = function(self, id)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.GetCheckTexture = function(self, id)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.SetCheckTexture = function(self, id, texture)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.AddCategory = function(self, name, lText, rText, func, checked, checkTexture, hideBlankLine)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.AddBlankLine = function(self, category)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.AddLine = function(self, category, text, r, g, b, wrap, justify, size, id, func, checked, checkTexture)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.AddDoubleLine = function(self, category, lText, rText, lr, lg, lb, rr, rg, rb, size, id, func, checked, checkTexture)
			tooltip:ClearLines()
			tooltip:AddLine(nil, "This plugin is using a deprecated tooltip scheme. Please upgrade to a more recent version.", 1, 1, 1, TRUE)
		end
		
		FuBarTooltip.GetNormalFontSize = tooltip.GetNormalFontSize
		FuBarTooltip.GetHeaderFontSize = tooltip.GetHeaderFontSize
		FuBarTooltip.GetNormalFontObject = tooltip.GetNormalFontObject
		FuBarTooltip.GetHeaderFontObject = tooltip.GetHeaderFontObject
		
		FuBarTooltip.SetFontSizePercent = function(self, percent)
			TabletLib:GetInstance('1.0'):SetFontSizePercent(FuBar.data.tooltip, percent)
			return tooltip:SetFontSizePercent(percent)
		end
		
		FuBarTooltip.GetFontSizePercent = function(self)
			return tooltip:GetFontSizePercent()
		end
		
		FuBarTooltip.SetTransparency = function(self, alpha)
			TabletLib:GetInstance('1.0'):SetTransparency(FuBar.data.tooltip, alpha)
			return tooltip:SetTransparency(alpha)
		end
		
		FuBarTooltip.GetTransparency = function(self)
			return tooltip:GetTransparency()
		end
		
		FuBarTooltip.SetColor = function(self, r, g, b)
			TabletLib:GetInstance('1.0'):SetColor(FuBar.data.tooltip, r, g, b)
			return tooltip:SetColor(r, g, b)
		end
		
		FuBarTooltip.GetColor = function(self)
			return tooltip:GetColor()
		end
	end
	
	local function Lock(self)
		self:EnableMouse(self.locked)
		self.locked = not self.locked
		self.owner.plugin.data.detachedTooltip.locked = self.locked or nil
		self.owner.plugin:UpdateTooltip()
	end
	
	local detachedTooltips
	
	local sekeys = SpecialEventsEmbed:GetInstance("Keys 1")
	sekeys:RegisterEvent(lib, "SPECIAL_ALTKEY_DOWN")
	sekeys:RegisterEvent(lib, "SPECIAL_ALTKEY_UP")
	
	function lib:SPECIAL_ALTKEY_DOWN()
		if detachedTooltips then
			for _, detached in detachedTooltips do
				if detached:IsShown() and detached.locked then
					detached:EnableMouse(IsAltKeyDown())
					detached.owner.plugin:UpdateTooltip()
				end
			end
		end
	end
	
	lib.SPECIAL_ALTKEY_UP = lib.SPECIAL_ALTKEY_DOWN
	
	local sizeFrame
	function lib:AcquireDetached(owner)
		if not tooltip.SetOwner then
			self.Initialize()
		end
		FuBarPlugin:GetInstance(MAJOR_VERSION):assert(owner and owner.plugin and owner.plugin.data, "Acquired tooltip must have an owner")
		if not owner.plugin.data.detachedTooltip then
			owner.plugin.data.detachedTooltip = {}
		end
		owner.plugin.data.detachedTooltip.detached = true
		if not detachedTooltips then
			detachedTooltips = {}
		end
		local numDetached = table.getn(detachedTooltips)
		for i = 1, numDetached do
			if detachedTooltips[i].notInUse then
				local detached = detachedTooltips[i]
				detached.fontSizePercent = owner.plugin.data.detachedTooltip.fontSizePercent or 1
				detached.transparency = owner.plugin.data.detachedTooltip.transparency or 1
				detached.r = owner.plugin.data.detachedTooltip.r or 0
				detached.g = owner.plugin.data.detachedTooltip.g or 0
				detached.b = owner.plugin.data.detachedTooltip.b or 0
				detached.locked = owner.plugin.data.detachedTooltip.locked
				detached:SetBackdropColor(detached.r, detached.g, detached.b, detached.transparency)
				detached:SetBackdropBorderColor(1, 1, 1, detached.transparency)
				detached:ClearAllPoints()
				detached:SetPoint(owner.plugin.data.detachedTooltip.anchor or "CENTER", UIParent, owner.plugin.data.detachedTooltip.anchor or "CENTER", owner.plugin.data.detachedTooltip.offsetx or 0, owner.plugin.data.detachedTooltip.offsety or 0)
				detached.notInUse = FALSE
				detached:SetOwner(owner)
				detached:Show()
				return detached
			end
		end
		
		if not sizeFrame then
			sizeFrame = CreateFrame("Frame", "FuBarTooltipSizeFrame", UIParent)
			sizeFrame:SetWidth(95)
			sizeFrame:SetHeight(140)
			local backdrop = compost:AcquireHash(
				'bgFile', "Interface\\TutorialFrame\\TutorialFrameBackground",
				'edgeFile', "Interface\\DialogFrame\\UI-DialogBox-Border",
				'tile', TRUE,
				'edgeSize', 16,
				'tileSize', 32,
				'insets', compost:AcquireHash(
					'left', 5,
					'right', 5,
					'top', 5,
					'bottom', 5
				)
			)
			sizeFrame:SetBackdrop(backdrop)
			compost:Reclaim(backdrop, 1)
			sizeFrame:EnableMouse(TRUE)
			sizeFrame:Show()
			sizeFrame:SetPoint("CENTER", UIParent, "CENTER")
			local slider = CreateFrame("Slider", sizeFrame:GetName() .. "Slider", sizeFrame)
			slider:SetOrientation("VERTICAL")
			slider:SetMinMaxValues(0, 1)
			slider:SetValueStep(0.01)
			slider:SetValue(0.5)
			slider:SetWidth(50)
			slider:SetHeight(100)
			slider:SetPoint("LEFT", sizeFrame, "LEFT", 5, 0)
			backdrop = compost:AcquireHash(
				'bgFile', "Interface\\Buttons\\UI-SliderBar-Background",
				'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border",
				'tile', TRUE,
				'edgeSize', 8,
				'tileSize', 8,
				'insets', compost:AcquireHash(
					'left', 6,
					'right', 6,
					'top', 3,
					'bottom', 3
				)
			)
			slider:SetBackdrop(backdrop)
			compost:Reclaim(backdrop, 1)
			slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
			local text = slider:CreateFontString(slider:GetName() .. "TopText", "ARTWORK")
			text:SetFontObject(GameFontGreenSmall)
			text:SetText("200%")
			text:SetPoint("BOTTOM", slider, "TOP")
			local text = slider:CreateFontString(slider:GetName() .. "BottomText", "ARTWORK")
			text:SetFontObject(GameFontGreenSmall)
			text:SetText("50%")
			text:SetPoint("TOP", slider, "BOTTOM")
			local text = slider:CreateFontString(slider:GetName() .. "Text", "ARTWORK")
			text:SetFontObject(GameFontHighlightSmall)
			text:SetText("100%")
			text:SetPoint("LEFT", slider, "RIGHT")
			local changing = false
			slider:SetScript("OnValueChanged", function()
				if changing then
					return
				end
				local value = 1 - slider:GetValue()
				if value < 0.5 then
					value = value + 0.5
				else
					value = value * 2
				end
				text:SetText(format("%.0f%%", value * 100))
				if sizeFrame.func then
					sizeFrame.func(value)
				end
			end)
			function sizeFrame:SetValue(value)
				if value < 1 then
					value = value - 0.5
				else
					value = value / 2
				end
				value = 1 - value
				changing = true
				slider:SetValue(value)
				changing = false
			end
			local entered = false
			local sizeFrame_Show = sizeFrame.Show
			function sizeFrame:Show()
				sizeFrame_Show(self)
				entered = true
			end
			sizeFrame:SetScript("OnUpdate", function()
				if not entered then
					sizeFrame:Hide()
				end
			end)
			sizeFrame:SetScript("OnEnter", function()
				entered = true
				UIDropDownMenu_StopCounting(DropDownList1)
			end)
			sizeFrame:SetScript("OnLeave", function()
				UIDropDownMenu_StartCounting(DropDownList1)
				entered = false
			end)
			slider:SetScript("OnEnter", function()
				entered = true
				UIDropDownMenu_StopCounting(DropDownList1)
			end)
			slider:SetScript("OnLeave", function()
				UIDropDownMenu_StartCounting(DropDownList1)
				entered = false
			end)
		end
		
		numDetached = numDetached + 1
		local detached = CreateFrame("Frame", "FuBarDetachedTooltip" .. numDetached, UIParent)
		table.insert(detachedTooltips, detached)
		detached:EnableMouse(not owner.plugin.data.detachedTooltip.locked)
		detached:EnableMouseWheel(TRUE)
		detached:SetMovable(TRUE)
		
		detached:ClearAllPoints()
		detached:SetPoint(owner.plugin.data.detachedTooltip.anchor or "CENTER", UIParent, owner.plugin.data.detachedTooltip.anchor or "CENTER", owner.plugin.data.detachedTooltip.offsetx or 0, owner.plugin.data.detachedTooltip.offsety or 0)
		
		detached:SetBackdrop(backdrop)
		detached:SetBackdropColor(0, 0, 0, 1)
		
		detached.numLines = 0
		detached.categoryLines = {}
		detached.idLines = {}
		detached.categories = 0
		detached.owner = nil
		detached.fontSizePercent = owner.plugin.data.detachedTooltip.fontSizePercent or 1
		detached.maxLines = 0
		detached.buttons = {}
		detached.checks = {}
		detached.lefts = {}
		detached.rights = {}
		detached.transparency = owner.plugin.data.detachedTooltip.transparency or 1
		detached.r = owner.plugin.data.detachedTooltip.r or 0
		detached.g = owner.plugin.data.detachedTooltip.g or 0
		detached.b = owner.plugin.data.detachedTooltip.b or 0
		detached:SetFrameStrata("BACKGROUND")
		detached:SetBackdropColor(detached.r, detached.g, detached.b, detached.transparency)
		detached:SetBackdropBorderColor(1, 1, 1, detached.transparency)
		detached.locked = owner.plugin.data.detachedTooltip.locked
		detached.scroll = 0
		
		local name = detached:GetName()
		local menu = CreateFrame("Frame", name .. "Menu", frame)
		menu:Hide()
		local parentMenu = WorldMapZoneDropDown
		local parentName = parentMenu:GetName()
		menu:SetWidth(parentMenu:GetWidth())
		menu:SetHeight(parentMenu:GetHeight())
		
		local menuLeft = menu:CreateTexture(name .. "MenuLeft", "ARTWORK")
		local parentLeft = getglobal(parentName .. "Left")
		menuLeft:SetTexture(parentLeft:GetTexture())
		menuLeft:SetWidth(parentLeft:GetWidth())
		menuLeft:SetHeight(parentLeft:GetHeight())
		for i = 1, parentLeft:GetNumPoints() do
			menuLeft:SetPoint(parentLeft:GetPoint(i))
		end
		menuLeft:SetTexCoord(0, 0.1953125, 0, 1)
	
		local menuMiddle = menu:CreateTexture(name .. "MenuMiddle", "ARTWORK")
		local parentMiddle = getglobal(parentName .. "Middle")
		menuMiddle:SetTexture(parentMiddle:GetTexture())
		menuMiddle:SetWidth(parentMiddle:GetWidth())
		menuMiddle:SetHeight(parentMiddle:GetHeight())
		for i = 1, parentMiddle:GetNumPoints() do
			menuMiddle:SetPoint(parentMiddle:GetPoint(i))
		end
		menuMiddle:SetTexCoord(0.1953125, 0.8046875, 0, 1)
	
		local menuRight = menu:CreateTexture(name .. "MenuRight", "ARTWORK")
		local parentRight = getglobal(parentName .. "Right")
		menuRight:SetTexture(parentRight:GetTexture())
		menuRight:SetWidth(parentRight:GetWidth())
		menuRight:SetHeight(parentRight:GetHeight())
		for i = 1, parentRight:GetNumPoints() do
			menuRight:SetPoint(parentRight:GetPoint(i))
		end
		menuRight:SetTexCoord(0.8046875, 1, 0, 1)
		
		local menuText = menu:CreateFontString(name .. "MenuText", "ARTWORK")
		local parentText = getglobal(parentName .. "Text")
		menuText:SetWidth(parentText:GetWidth())
		menuText:SetHeight(parentText:GetHeight())
		for i = 1, parentText:GetNumPoints() do
			menuText:SetPoint(parentText:GetPoint(i))
		end
		menuText:SetFontObject(parentText:GetFontObject())
		
		local menuButton = CreateFrame("Button", name .. "MenuButton", menu)
		local parentButton = getglobal(parentName .. "Button")
		menuButton:SetWidth(parentButton:GetWidth())
		menuButton:SetHeight(parentButton:GetHeight())
		for i = 1, parentButton:GetNumPoints() do
			menuButton:SetPoint(parentButton:GetPoint(i))
		end
		
		menuButton:SetScript("OnClick", parentButton:GetScript("OnClick"))
		menuButton:SetScript("OnHide", parentButton:GetScript("OnHide"))
		
		local menuButtonNormalTexture = menuButton:CreateTexture(name .. "MenuButtonNormalTexture")
		local parentButtonNormalTexture = getglobal(parentName .. "ButtonNormalTexture")
		menuButtonNormalTexture:SetTexture(parentButtonNormalTexture:GetTexture())
		menuButtonNormalTexture:SetWidth(parentButtonNormalTexture:GetWidth())
		menuButtonNormalTexture:SetHeight(parentButtonNormalTexture:GetHeight())
		for i = 1, parentButtonNormalTexture:GetNumPoints() do
			menuButtonNormalTexture:SetPoint(parentButtonNormalTexture:GetPoint(i))
		end
		menuButton:SetNormalTexture(menuButtonNormalTexture)
		
		local menuButtonPushedTexture = menuButton:CreateTexture(name .. "MenuButtonPushedTexture")
		local parentButtonPushedTexture = getglobal(parentName .. "ButtonPushedTexture")
		menuButtonPushedTexture:SetTexture(parentButtonPushedTexture:GetTexture())
		menuButtonPushedTexture:SetWidth(parentButtonPushedTexture:GetWidth())
		menuButtonPushedTexture:SetHeight(parentButtonPushedTexture:GetHeight())
		for i = 1, parentButtonPushedTexture:GetNumPoints() do
			menuButtonPushedTexture:SetPoint(parentButtonPushedTexture:GetPoint(i))
		end
		menuButton:SetPushedTexture(menuButtonPushedTexture)
		
		local menuButtonDisabledTexture = menuButton:CreateTexture(name .. "MenuButtonDisabledTexture")
		local parentButtonDisabledTexture = getglobal(parentName .. "ButtonDisabledTexture")
		menuButtonDisabledTexture:SetTexture(parentButtonDisabledTexture:GetTexture())
		menuButtonDisabledTexture:SetWidth(parentButtonDisabledTexture:GetWidth())
		menuButtonDisabledTexture:SetHeight(parentButtonDisabledTexture:GetHeight())
		for i = 1, parentButtonDisabledTexture:GetNumPoints() do
			menuButtonDisabledTexture:SetPoint(parentButtonDisabledTexture:GetPoint(i))
		end
		menuButton:SetDisabledTexture(menuButtonDisabledTexture)
		
		local menuButtonHighlightTexture = menuButton:CreateTexture(name .. "MenuButtonHighlightTexture")
		local parentButtonHighlightTexture = getglobal(parentName .. "ButtonHighlightTexture")
		menuButtonHighlightTexture:SetTexture(parentButtonHighlightTexture:GetTexture())
		menuButtonHighlightTexture:SetWidth(parentButtonHighlightTexture:GetWidth())
		menuButtonHighlightTexture:SetHeight(parentButtonHighlightTexture:GetHeight())
		for i = 1, parentButtonHighlightTexture:GetNumPoints() do
			menuButtonHighlightTexture:SetPoint(parentButtonHighlightTexture:GetPoint(i))
		end
		menuButton:SetHighlightTexture(menuButtonHighlightTexture)
		
		HideDropDownMenu(1)
		UIDropDownMenu_Initialize(menu, function(level)
			local value = UIDROPDOWNMENU_MENU_VALUE
			local info = compost:Acquire()
			if level == 1 then
				UIDropDownMenu_AddButton(compost:RecycleHash(info,
					'text', detached.owner.plugin:GetTitle(),
					'notClickable', TRUE,
					'isTitle', TRUE
				))
			end
			if detached.owner and detached.owner.plugin and detached.owner.plugin.MenuSettings then
				detached.owner.plugin:MenuSettings(level, value, TRUE)
				if level == 1 then
					FuBarUtils.AddSpacerDropDownMenu()
				end
			end
			if level == 1 then
				UIDropDownMenu_AddButton(compost:RecycleHash(info,
					'text', loc.MENU_DETACH_TOOLTIP,
					'func', function()
						self:ReleaseDetached(detached)
					end,
					'checked', true
				), level)
				
				UIDropDownMenu_AddButton(compost:RecycleHash(info,
					'text', loc.MENU_LOCK_TOOLTIP,
					'func', function()
						detached:Lock()
					end,
					'checked', detached.locked
				), level)
				
				local i = DropDownList1.numButtons + 1
				UIDropDownMenu_AddButton(compost:RecycleHash(info,
					'text', COLOR,
					'opacityFunc', function()
						detached:SetTransparency(1 - OpacitySliderFrame:GetValue())
					end,
					'swatchFunc', function()
						detached:SetColor(ColorPickerFrame:GetColorRGB())
					end,
					'func', function()
						getglobal("DropDownList1Button" .. i .. "ColorSwatch"):Click()
					end,
					'hasColorSwatch', TRUE,
					'r', detached.r or 0,
					'g', detached.g or 0,
					'b', detached.b or 0,
					'opacity', 1 - (detached.transparency or 0),
					'hasOpacity', TRUE
				), level)
				
				UIDropDownMenu_AddButton(compost:RecycleHash(info,
					'text', loc.MENU_SIZE,
					'hasArrow', TRUE,
					'value', "size"
				), level)
				
				local button = getglobal("DropDownList1Button" .. DropDownList1.numButtons)
				local func = function()
					sizeFrame:ClearAllPoints()
					sizeFrame:Show()
					sizeFrame:SetPoint("BOTTOMLEFT", button, "BOTTOMRIGHT")
					sizeFrame.func = function(value)
						detached:SetFontSizePercent(value)
					end
					sizeFrame:SetParent(DropDownList1)
				end
				local button_OnEnter = button:GetScript("OnEnter")
				button:SetScript("OnEnter", function()
					getglobal(this:GetName().."Highlight"):Show()
					UIDropDownMenu_StopCounting(this:GetParent())
					func()
				end)
				local arrow = getglobal(button:GetName() .. "ExpandArrow")
				local arrow_OnEnter = arrow:GetScript("OnEnter")
				arrow:SetScript("OnEnter", func)
				local arrow_OnClick = arrow:GetScript("OnClick")
				arrow:SetScript("OnClick", func)
				button:SetScript("OnHide", function()
					button:SetScript("OnHide", nil)
					button:SetScript("OnEnter", button_OnEnter)
					arrow:SetScript("OnEnter", arrow_OnEnter)
					arrow:SetScript("OnClick", arrow_OnClick)
					sizeFrame:Hide()
				end)
				
				FuBarUtils.AddSpacerDropDownMenu()
				
				UIDropDownMenu_AddButton(compost:RecycleHash(info,
					'text', CLOSE,
					'func', function()
						HideDropDownMenu(1)
					end
				), level)
			elseif level == 2 then
				if value == "size" then
					for i = 50, 200, 5 do
						if i > 100 then
							i = i + 5
						end
						local i = i
						local text
						text = format("%d%%", i)
						UIDropDownMenu_AddButton(compost:RecycleHash(info,
							'text', text,
							'func', function()
								detached:SetFontSizePercent(i / 100)
							end,
							'checked', floor(i / 5 + 0.5) == floor(detached.fontSizePercent * 20 + 0.5)
						), level)
					end
				end
			end
			compost:Reclaim(info)
		end, "MENU")
		
		local width = GetScreenWidth()
		local height = GetScreenHeight()
		detached:SetScript("OnMouseDown", function()
			if arg1 == "LeftButton" then
				HideDropDownMenu(1)
				if not detached.locked then
					detached:StartMoving()
				end
			elseif arg1 == "RightButton" then
				HideDropDownMenu(1)
				ToggleDropDownMenu(1, nil, menu, detached, 0, 0)
				DropDownList1:ClearAllPoints()
				local anchor
				if detached:GetTop() + detached:GetBottom() < height then
					anchor = "BOTTOM"
				else
					anchor = "TOP"
				end
				if detached:GetLeft() + detached:GetRight() < width then
					DropDownList1:SetPoint(anchor .. "LEFT", detached, anchor .. "RIGHT")
				else
					DropDownList1:SetPoint(anchor .. "RIGHT", detached, anchor .. "LEFT")
				end
			end
		end)
		
		detached:SetScript("OnMouseUp", function()
			if arg1 == "LeftButton" then
				if not detached.locked then 
					detached:StopMovingOrSizing()
					local anchor
					local offsetx
					local offsety
					if detached:GetTop() + detached:GetBottom() < height then
						anchor = "BOTTOM"
						offsety = detached:GetBottom()
						if offsety < 0 then
							offsety = 0
						end
						if offsety < MainMenuBar:GetTop() and MainMenuBar:IsVisible() then
							offsety = MainMenuBar:GetTop()
						end
						local top = 0
						for i = 1, FuBar:GetNumPanels() do
							local panel = FuBar:GetPanel(i)
							if panel:GetAttachPoint() == "BOTTOM" then
								if panel.frame:GetTop() > top then
									top = panel.frame:GetTop()
								end
							end
						end
						if offsety < top then
							offsety = top
						end
					else
						anchor = "TOP"
						offsety = detached:GetTop() - height
						if offsety > 0 then
							offsety = 0
						end
						local bottom = GetScreenHeight()
						for i = 1, FuBar:GetNumPanels() do
							local panel = FuBar:GetPanel(i)
							if panel:GetAttachPoint() == "TOP" then
								if panel.frame:GetBottom() < bottom then
									bottom = panel.frame:GetBottom()
								end
							end
						end
						bottom = bottom  - GetScreenHeight()
						if offsety > bottom then
							offsety = bottom
						end
					end
					if detached:GetLeft() + detached:GetRight() < width * 2 / 3 then
						anchor = anchor .. "LEFT"
						offsetx = detached:GetLeft()
						if offsetx < 0 then
							offsetx = 0
						end
					elseif detached:GetLeft() + detached:GetRight() < width * 4 / 3 then
						if anchor == "" then
							anchor = "CENTER"
						end
						offsetx = (detached:GetLeft() + detached:GetRight() - GetScreenWidth()) / 2
					else
						anchor = anchor .. "RIGHT"
						offsetx = detached:GetRight() - width
						if offsetx > 0 then
							offsetx = 0
						end
					end
					detached:ClearAllPoints()
					detached:SetPoint(anchor, UIParent, anchor, offsetx, offsety)
					local t = owner.plugin.data.detachedTooltip
					if t.anchor ~= anchor or math.abs(t.offsetx - offsetx) > 8 or math.abs(t.offsety - offsety) > 8 then
						detached.preventClick = GetTime() + 0.05
					end
					t.anchor = anchor
					t.offsetx = offsetx
					t.offsety = offsety
					detached:Show()
				end
			end
		end)
		
		NewLine(detached)
		
		detached.hint = detached:CreateFontString(detached:GetName() .. "TextHint", "ARTWORK")
		detached.hint:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2)
		detached.hint:SetPoint("RIGHT", detached, "RIGHT", 0, -10)
		detached.hint:SetFontObject(GameTooltipText)
		detached.hint:Hide()
		local font,_,flags = detached.hint:GetFont()
		detached.hint:SetFont(font, normalSize * detached.fontSizePercent, flags)
		
		detached.scrollUp = detached:CreateFontString(detached:GetName() .. "TextScrollUp", "ARTWORK")
		detached.scrollUp:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2)
		detached.scrollUp:SetPoint("RIGHT", detached, "RIGHT", 0, -10)
		detached.scrollUp:SetFontObject(GameTooltipText)
		detached.scrollUp:Hide()
		local font,_,flags = detached.scrollUp:GetFont()
		detached.scrollUp:SetFont(font, normalSize * detached.fontSizePercent, flags)
		detached.scrollUp:SetJustifyH("CENTER")
		detached.scrollUp:SetTextColor(1, 0.823529, 0)
		detached.scrollUp:SetText(" ")
		
		detached.scrollDown = detached:CreateFontString(detached:GetName() .. "TextScrollUp", "ARTWORK")
		detached.scrollDown:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2)
		detached.scrollDown:SetPoint("RIGHT", detached, "RIGHT", 0, -10)
		detached.scrollDown:SetFontObject(GameTooltipText)
		detached.scrollDown:Hide()
		local font,_,flags = detached.scrollUp:GetFont()
		detached.scrollDown:SetFont(font, normalSize * detached.fontSizePercent, flags)
		detached.scrollDown:SetJustifyH("CENTER")
		detached.scrollDown:SetTextColor(1, 0.823529, 0)
		detached.scrollDown:SetText(" ")
		
		detached:SetScript("OnMouseWheel", function()
			detached:Scroll(arg1 < 0)
		end)
		
		detached.SetTransparency = tooltip.SetTransparency
		detached.GetTransparency = tooltip.GetTransparency
		detached.SetColor = tooltip.SetColor
		detached.GetColor = tooltip.GetColor
		
		detached.SetOwner = tooltip.SetOwner
		detached.IsOwned = tooltip.IsOwned
		detached.ClearLines = tooltip.ClearLines
		detached.NumLines = tooltip.NumLines
		detached.Hide = tooltip.Hide
		detached.Show = tooltip.Show
		detached.SetHint = tooltip.SetHint
		detached._AddTitle = tooltip._AddTitle
		detached.SetTitle = tooltip.SetTitle
		detached.IsChecked = tooltip.IsChecked
		detached.ToggleChecked = tooltip.ToggleChecked
		detached.GetCheckTexture = tooltip.GetCheckTexture
		detached.SetCheckTexture = tooltip.SetCheckTexture
		detached.AddCategory = tooltip.AddCategory
		detached.AddBlankLine = tooltip.AddBlankLine
		detached.AddLine = tooltip.AddLine
		detached.AddDoubleLine = tooltip.AddDoubleLine
		detached.GetNormalFontSize = tooltip.GetNormalFontSize
		detached.GetHeaderFontSize = tooltip.GetHeaderFontSize
		detached.GetNormalFontObject = tooltip.GetNormalFontObject
		detached.GetHeaderFontObject = tooltip.GetHeaderFontObject
		detached.SetFontSizePercent = tooltip.SetFontSizePercent
		detached.GetFontSizePercent = tooltip.GetFontSizePercent
		detached.Scroll = tooltip.Scroll
		detached.Lock = Lock
		detached.notInUse = FALSE
		detached:SetOwner(owner)
		detached:Show()
		return detached
	end
	
	function lib:ReleaseDetached(detached)
		FuBarPlugin:GetInstance(MAJOR_VERSION):assert(detached, "Detached tooltip not given.")
		FuBarPlugin:GetInstance(MAJOR_VERSION):assert(detached.AddLine, "detached argument not a Tooltip.")
		FuBarPlugin:GetInstance(MAJOR_VERSION):assert(detached.owner, "Detached tooltip has no owner.")
		FuBarPlugin:GetInstance(MAJOR_VERSION):assert(not detached.notInUse, "Detached tooltip not in use.")
		detached.owner.plugin.data.detachedTooltip.detached = nil
		detached.owner.plugin.tooltip = tooltip
		detached:SetOwner(nil)
		detached.notInUse = TRUE
	end
	
	function lib:GetLibraryVersion()
		return MAJOR_VERSION, MINOR_VERSION
	end
	
	function lib:LibActivate(stub, oldLib, oldList)
		local mt = getmetatable(FuBarTooltip) or {}
		mt.__index = self
		setmetatable(FuBarTooltip, mt)
		
		if not oldlib then
			local FuBar_Initialize = FuBar.Initialize
			function FuBar.Initialize(FuBar)
				self.Initialize()
				FuBar_Initialize(FuBar)
			end
		end
	end
	
	function lib:LibDeactivate()
	end
	
	FuBarTooltip:Register(lib)
	lib = nil
end