vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
local MAJOR_VERSION = "1.2"
local MINOR_VERSION = tonumber(string.sub("$Revision: 8308 $", 12, -3))

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

local loc = {
        ARGUMENT_VISIBLE = "visible",
        ARGUMENT_COLOR = "color",
        ARGUMENT_SHOWICON = "showIcon",
        ARGUMENT_SHOWTEXT = "showText",
        ARGUMENT_PROFILE = "profile",
        
        TEXT_TOGGLE_VISIBILITY = "Toggle Visibility.",
        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_LIST_PROFILING_INFO = "List profiling information",
        
        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_ON_LEFT_SIDE = "On left side",
        MENU_IN_CENTER = "In center",
        MENU_ON_RIGHT_SIDE = "On right side",
        MENU_ATTACH = "Attach to minimap",
        MENU_HIDE = "Hide",
        MENU_DISABLE = "Disable",
        MENU_ABOUT = "About",
        
        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_VISIBILITY = "Sichtbarkeit umschalten."
        loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Iconanzeige umschalten."
        loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Textanzeige umschalten."
        loc.TEXT_LIST_PROFILING_INFO = "Liste Profilinformationen"
        
        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_ON_LEFT_SIDE = "Auf linker Seite anzeigen"
        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.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_VISIBILITY = "Bascule la visibilite."
        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_LIST_PROFILING_INFO = "List profiling information" -- CHECK
        
        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_ON_LEFT_SIDE = "On left side" -- 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.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"
        
elseif ( GetLocale() == "zhCN" ) then
        loc.TEXT_TOGGLE_VISIBILITY = "是否可见."
        loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "是否显示图标."
        loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "是否显示文本."
        loc.TEXT_LIST_PROFILING_INFO = "显示配置文件信息"
        
        loc.MENU_SHOW_ICON = "显示图标"
        loc.MENU_SHOW_TEXT = "显示文本"
        loc.MENU_SHOW_COLORED_TEXT = "显示彩色文本"
        loc.MENU_DETACH_TOOLTIP = "分离提示信息"
        loc.MENU_LOCK_TOOLTIP = "锁定提示信息"
        loc.MENU_ON_LEFT_SIDE = "靠左侧"
        loc.MENU_IN_CENTER = "居中"
        loc.MENU_ON_RIGHT_SIDE = "靠右侧"
        loc.MENU_ATTACH = "吸附在小地图周围"
        loc.MENU_HIDE = "隐藏"
        loc.MENU_DISABLE = "禁用"
        loc.MENU_ABOUT = "关于"
        
        loc.MAP_ONOFF = {[0]="|cffff0000关闭|r",[1]="|cff00ff00开启|r"}
        
        loc.PATTERN_MERGE_WITH_CHILD = "与 %s 合并"
        loc.PATTERN_SWITCH_TO_CHILD = "切换至 %s"
        
elseif ( GetLocale() == "koKR" ) then 
        loc.ARGUMENT_VISIBLE = "visible"
        loc.ARGUMENT_COLOR = "color"
        loc.ARGUMENT_SHOWICON = "showIcon"
        loc.ARGUMENT_SHOWTEXT = "showText"
        loc.ARGUMENT_PROFILE = "profile"
        
        loc.TEXT_TOGGLE_VISIBILITY = "Toggle Visibility."
        loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Toggle whether to show the icon."
        loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Toggle whether to show text."
        loc.TEXT_LIST_PROFILING_INFO = "List profiling information"
        
        loc.MENU_SHOW_ICON = "아이콘 보이기"
        loc.MENU_SHOW_TEXT = "Show text"
        loc.MENU_SHOW_COLORED_TEXT = "Show colored text"
        loc.MENU_DETACH_TOOLTIP = "툴팁 분리"
        loc.MENU_LOCK_TOOLTIP = "툴팁 잠그기"
        loc.MENU_ON_LEFT_SIDE = "왼쪽으로"
        loc.MENU_IN_CENTER = "가운데로"
        loc.MENU_ON_RIGHT_SIDE = "오른쪽으로"
        loc.MENU_HIDE = "숨기기"
        loc.MENU_DISABLE = "끄기"
        loc.MENU_ABOUT = "About"
        
        loc.MAP_ONOFF[0]="|cffff0000꺼짐|r"
        loc.MAP_ONOFF[1]="|cff00ff00켜짐|r"
        
        PATTERN_MERGE_WITH_CHILD = "Merge with %s"
        PATTERN_SWITCH_TO_CHILD = "Switch to %s"

end

local dewdrop = DewdropLib:GetInstance('1.0')
local tablet = TabletLib:GetInstance('1.0')

if FUBAR_REVISION and MINOR_VERSION > FUBAR_REVISION then
        FUBAR_REVISION = MINOR_VERSION
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) then
   FuBarPlugin = stub:NewStub();
end
if (not FuBarPlugin.MinimapContainer) then
   FuBarPlugin.MinimapContainer = stub:NewStub();
end

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



local RegisterTablet
-- FuBarPlugin
do
        local compost
        if CompostLib then
                compost = CompostLib:GetInstance('compost-1')
        end
        
        local epsilon = 1e-5
        
        local lib = AceAddon:new()
        
        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
        
        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")
                        file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
                        if not message then
                                local _,_,second = string.find(stack, "\n(.-)\n")
                                message = "assertion failed! " .. second
                        end
                        if self.name then
                                local _,_,title = string.find(self.name, "FuBar %- (.+)")
                                if not title then
                                        title = self.name
                                end
                                message = title .. ": " .. message
                        end
                        local i = 1
                        for s in string.gfind(stack, "\n([^\n]*)") do
                                i = i + 1
                                if not string.find(s, file .. "%.lua:%d+:") then
                                        error(message, i)
                                        return
                                end
                        end
                        error(message, 2)
                        return
                end
                return condition
        end
        
        function lib:argCheck(arg, num, kind, kind2, kind3, kind4)
                if tostring(type(arg)) ~= kind then
                        if kind2 then
                                if tostring(type(arg)) ~= kind2 then
                                        if kind3 then
                                                if tostring(type(arg)) ~= kind3 then
                                                        if kind4 then
                                                                if tostring(type(arg)) ~= kind4 then
                                                                        local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
                                                                        self:assert(false, format("Bad argument #%s to `%s' (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", kind2 or "---", kind3 or "---", kind4 or "---", type(arg)))
                                                                end
                                                        else
                                                                local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
                                                                self:assert(false, format("Bad argument #%s to `%s' (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", kind2 or "---", kind3 or "---", type(arg)))
                                                        end
                                                end
                                        else
                                                local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
                                                self:assert(false, format("Bad argument #%s to `%s' (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", kind2 or "---", type(arg)))
                                        end
                                end
                        else
                                local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
                                self:assert(false, format("Bad argument #%s to `%s' (%s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", type(arg)))
                        end
                end
        end
        
        function lib:GetTitle()
                self:assert(self.name, "You must provide self.name")
                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:ToggleMinimapAttached()
                if FuBar and not self.cannotAttachToMinimap then
                        local value = self:IsMinimapAttached()
                        if value then
                                self.panel:RemovePlugin(self)
                                FuBar:GetPanel(1):AddPlugin(self, nil, self.defaultPosition)
                        else
                                self.panel:RemovePlugin(self)
                                FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION):AddPlugin(self)
                        end
                end
        end
        
        function lib:IsMinimapAttached()
                return self.panel == FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION)
        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:UpdateDisplay()
                self:UpdateText()
                self:UpdateTooltip()
        end
        
        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 == 1 and defaults[k] == true then
                                t[k] = nil
                        elseif v == true and defaults[k] == 1 then
                                t[k] = nil
                        end
                end
                setmetatable(t, { __index = defaults })
        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
                elseif FuBar then
                        local FuBarDB = FuBar2DB or FuBarDB
                        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["default"] then
                                FuBarDB.pluginDB[self:GetTitle()].profiles["default"] = {}
                        end
                        if self.data ~= FuBarDB.pluginDB[self:GetTitle()].profiles["default"] then
                                self.data = FuBarDB.pluginDB[self:GetTitle()].profiles["default"]
                        else
                                return
                        end
                end
                inheritDefaults(self.data, self.defaults)
                
                if type(self.ACE_PROFILE_LOADED) == "function" then
                        self:ACE_PROFILE_LOADED()
                end
                        
                self.data.version = self.version
                
                self:Update()
        end
        
        function lib:Show(panelId)
                if self.frame:IsShown() or (self.minimapFrame and self.minimapFrame:IsShown()) then
                        return
                end
                if panelId ~= false then
                        self.data.hidden = nil
                end
                if self:IsLoadOnDemand() and FuBar then
                        local data = FuBar.db and FuBar.db.profile or FuBar.data
                        if not data.loadOnDemand then
                                data.loadOnDemand = {}
                        end
                        if not data.loadOnDemand[self.folderName] then
                                data.loadOnDemand[self.folderName] = {}
                        end
                        data.loadOnDemand[self.folderName].disabled = nil
                end
                if self.disabled then
                        self.panelIdTmp = panelId
                        self:EnableAddon()
                        self.panelIdTmp = nil
                        if not self.db then
                                self.data.disabled = nil
                        end
                elseif self.data and not self.data.hidden then
                        if panelId == 0 or not FuBar then
                                FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION):AddPlugin(self)
                        else
                                FuBar:ShowPlugin(self, panelId or self.panelIdTmp)
                        end
                        self:Update()
                end
        end
        
        function lib:Hide()
                if not self.frame:IsShown() and (not self.minimapFrame or not self.minimapFrame:IsShown()) then
                        return
                end
                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
                        if not FuBar or not FuBar:IsChangingProfile() then
                                self:DisableAddon()
                                if self:IsLoadOnDemand() and FuBar then
                                        local data = FuBar.db and FuBar.db.profile or FuBar.data
                                        if not data.loadOnDemand then
                                                data.loadOnDemand = {}
                                        end
                                        if not data.loadOnDemand[self.folderName] then
                                                data.loadOnDemand[self.folderName] = {}
                                        end
                                        data.loadOnDemand[self.folderName].disabled = true
                                end
                        end
                end
                if self.panel then
                        self.panel:RemovePlugin(self)
                end
                self.frame:Hide()
                if self.minimapFrame then
                        self.minimapFrame:Hide()
                end
        end
        
        function lib:AddImpliedMenuOptions(level)
                self:argCheck(level, 2, "number", "nil")
                if self.hasIcon and not self.hasNoText then
                        dewdrop:AddLine(
                                'text', loc.MENU_SHOW_ICON,
                                'func', function()
                                        self:ToggleIconShown()
                                end,
                                'checked', self:IsIconShown(),
                                'level', level
                        )
                end
                
                if not self.cannotHideText and self.hasIcon and not self.hasNoText then
                        dewdrop:AddLine(
                                'text', loc.MENU_SHOW_TEXT,
                                'func', function()
                                        self:ToggleTextShown()
                                end,
                                'checked', self:IsTextShown(),
                                'leve', level
                        )
                end
                
                if not self.userDefinedFrame and not self.hasNoText and not self.hasNoColor then
                        dewdrop:AddLine(
                                'text', loc.MENU_SHOW_COLORED_TEXT,
                                'arg1', self,
                                'func', "ToggleTextColored",
                                'checked', self:IsTextColored(),
                                'level', level
                        )
                end
                
                if not self.overrideTooltip and not self.cannotDetachTooltip then
                        dewdrop:AddLine(
                                'text', loc.MENU_DETACH_TOOLTIP,
                                'func', function()
                                        if self:IsTooltipDetached() then
                                                self:ReattachTooltip()
                                        else
                                                self:DetachTooltip()
                                        end
                                end,
                                'checked', self:IsTooltipDetached(),
                                'level', level
                        )
                        
                        dewdrop:AddLine(
                                'text', loc.MENU_LOCK_TOOLTIP,
                                'arg1', tablet,
                                'func', "ToggleLocked",
                                'arg2', self.frame,
                                'checked', tablet:IsLocked(self.frame),
                                'disabled', not self:IsTooltipDetached(),
                                'level', level
                        )
                end
                
                if not self:IsMinimapAttached() then
                        dewdrop:AddLine(
                                'text', loc.MENU_ON_LEFT_SIDE,
                                'arg1', self.panel,
                                'func', self.panel:GetPluginSide(self) ~= "LEFT" and "SetPluginSide",
                                'arg2', self,
                                'arg3', "LEFT",
                                'checked', self.panel:GetPluginSide(self) == "LEFT",
                                'level', level,
                                'closeWhenClicked', self.panel:GetPluginSide(self) ~= "LEFT",
                                'isRadio', true
                        )
                        
                        dewdrop:AddLine(
                                'text', loc.MENU_IN_CENTER,
                                'arg1', self.panel,
                                'func', self.panel:GetPluginSide(self) ~= "CENTER" and "SetPluginSide",
                                'arg2', self,
                                'arg3', "CENTER",
                                'checked', self.panel:GetPluginSide(self) == "CENTER",
                                'level', level,
                                'closeWhenClicked', self.panel:GetPluginSide(self) ~= "CENTER",
                                'isRadio', true
                        )
                        
                        dewdrop:AddLine(
                                'text', loc.MENU_ON_RIGHT_SIDE,
                                'arg1', self.panel,
                                'func', self.panel:GetPluginSide(self) ~= "RIGHT" and "SetPluginSide",
                                'arg2', self,
                                'arg3', "RIGHT",
                                'checked', self.panel:GetPluginSide(self) == "RIGHT",
                                'level', level,
                                'closeWhenClicked', self.panel:GetPluginSide(self) ~= "RIGHT",
                                'isRadio', true
                        )
                end
                
                if not self.cannotAttachToMinimap or self:IsMinimapAttached() then
                        dewdrop:AddLine(
                                'text', loc.MENU_ATTACH,
                                'arg1', self,
                                'func', "ToggleMinimapAttached",
                                'checked', self:IsMinimapAttached(),
                                'level', level,
                                'closeWhenClicked', true
                        )
                end
                
                if self.hideWithoutStandby then
                        dewdrop:AddLine(
                                'text', loc.MENU_HIDE,
                                'arg1', self,
                                'func', "Hide",
                                'level', level,
                                'closeWhenClicked', true
                        )
                end
                
                dewdrop:AddLine(
                        'text', loc.MENU_DISABLE,
                        'arg1', self,
                        'func', "DisableAddon",
                        'level', level,
                        'closeWhenClicked', true
                )
                
                dewdrop:AddLine(
                        'level', level
                )
                
                dewdrop:AddLine(
                        'text', loc.MENU_ABOUT,
                        'arg1', self.cmd,
                        'func', "DisplayAddonInfo",
                        'level', level
                )
        end
        
        function lib:SetIcon(path)
                if not path then
                        return
                end
                if path == 1 then
                        path = true
                end
                self:argCheck(path, 2, "string", "boolean")
                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 = format("Interface\\AddOns\\%s\\icon", self.folderName)
                elseif not string.find(path, '^Interface[\\/]') then
                        path = format("Interface\\AddOns\\%s\\%s", self.folderName, path)
                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)
                if self.minimapIcon then
                        if string.sub(path, 1, 16) == "Interface\\Icons\\" then
                                self.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
                        else
                                self.minimapIcon:SetTexCoord(0, 1, 0, 1)
                        end
                        self.minimapIcon:SetTexture(path)
                end
        end
        
        function lib:GetIcon()
                if self.hasIcon then
                        return self.iconFrame:GetTexture()
                end
        end
        
        function lib:CheckWidth(force)
                self:argCheck(force, 2, "boolean", "nil")
                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:argCheck(text, 2, "string", "number")
                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:argCheck(child, 2, "table")
                if FuBarPlugin.lastChildFrame then
                        FuBarPlugin.lastChildFrame:Hide()
                end
                FuBarPlugin.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
        
        local onClickTypes = {"OnClick", "OnDoubleClick", "OnMouseDown", "OnMouseUp"}
        
        function lib:HookIntoPlugin(mother, style)
                self:argCheck(mother, 2, "table", "nil")
                self:argCheck(style, 3, "string", "nil")
                if self.hookedPlugin then
                        ace:print(self:GetTitle() .. ": Cannot hook into a plugin while already hooked into another.")
                        return false
                end
                if not mother or type(mother) ~= "table" or getmetatable(self).__index ~= getmetatable(mother).__index then
                        ace:debug(self:GetTitle() .. ": 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(mother).__index.SetIcon(mother, childIcon)
                        else
                                self.data["switch." .. mother:GetTitle()] = "MOTHER"
                                current = "MOTHER"
                                getmetatable(mother).__index.SetIcon(mother, motherIcon)
                        end
                        mother:UpdateText()
                        mother:UpdateTooltip()
                        dewdrop:Close()
                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
                                                tablet:AddCategory(
                                                        'text', child:GetTitle(),
                                                        'font', tablet:GetHeaderFontObject(),
                                                        'justify', "CENTER",
                                                        'isTitle', true
                                                )
                                        end
                                        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(mother).__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(mother).__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
                                        if mother_funcs[name] and child_func 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
                                        elseif child_func then
                                                mother[name] = function(self, alpha)
                                                        if current ~= "MOTHER" and child_func then
                                                                child_func(child, alpha)
                                                        end
                                                end
                                        elseif mother_funcs[name] then
                                                mother[name] = function(self, alpha)
                                                        if current == "MOTHER" and mother_funcs[name] ~= "nil" then
                                                                mother_funcs[name](mother, alpha)
                                                        end
                                                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(mother).__index.SetIcon(mother, path)
                                end
                                function child:SetIcon(path)
                                        childIcon = path
                                        getmetatable(mother).__index.SetIcon(mother, path)
                                end
                        end
                        
                        function child:Show(panelId)
                                if panelId and panelId ~= 0 then
                                        unmerge()
                                end
                                
                                child_Show(self, panelId)
                        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
                                dewdrop:AddLine(
                                        '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()
                                )
                        elseif level == 2 and value == child:GetTitle() then
                                dewdrop:AddLine(
                                        'text', format(loc.PATTERN_SWITCH_TO_CHILD, child:GetTitle()),
                                        'func', switch,
                                        'checked', current ~= "MOTHER"
                                )
                        end
                        if merged then
                                if (style ~= "SWITCH" or (style == "SWITCH" and current == "MOTHER")) and mother_MenuSettings then
                                        if level == 1 then
                                                dewdrop:AddLine()
                                        end
                                        mother_MenuSettings(mother, level, value)
                                end
                                if (style ~= "SWITCH" or (style == "SWITCH" and current == "CHILD")) and child.MenuSettings then
                                        if level == 1 then
                                                dewdrop:AddLine()
                                                dewdrop:AddLine(
                                                        'text', child:GetTitle(),
                                                        'isTitle', true
                                                )
                                        end
                                        child:MenuSettings(level, value)
                                end
                        else
                                if mother_MenuSettings then
                                        if level == 1 then
                                                dewdrop:AddLine()
                                        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()
                if not tablet.registry[self.frame] then
                        self:UpdateTooltip()
                end
                return not tablet:IsAttached(self.frame)
        end
        
        function lib:DetachTooltip()
                self:UpdateTooltip()
                tablet:Detach(self.frame)
        end
        
        function lib:ReattachTooltip()
                self:UpdateTooltip()
                tablet:Attach(self.frame)
        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 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 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:argCheck(lod, 2, "boolean")
                self._loadOnDemand = lod
        end
        
        function lib:IsLoadOnDemand()
                return self._loadOnDemand
        end
        
        function lib:IsDisabled()
                return self.disabled
        end
        
        local function cleanDefaults(t, defaults, notFirst)
                if defaults then
                        for k,v in pairs(defaults) do
                                if type(v) == "table" then
                                        if type(t[k]) == "table" then
                                                cleanDefaults(t[k], v, true)
                                                if next(t[k]) == nil then
                                                        t[k] = nil
                                                end
                                        end
                                elseif t[k] == v then
                                        t[k] = nil
                                elseif t[k] == true and v == TRUE then
                                        t[k] = nil
                                elseif t[k] == TRUE and v == true then
                                        t[k] = nil
                                end
                        end
                        for k,v in pairs(t) do
                                if v == false and not defaults[k] then
                                        t[k] = nil
                                end
                        end
                end
                if not notFirst then
                        if next(t) == "version" and next(t, "version") == nil then
                                t.version = nil
                                return true
                        end
                end
                return false
        end
        
        function RegisterTablet(self)
                if not tablet:IsRegistered(self.frame) then
                        local FuBar_data = FuBar and (FuBar.db and FuBar.db.profile or FuBar.data)
                        tablet:Register(self.frame,
                                'children', function()
                                        tablet:SetTitle(self:GetTitle())
                                        self:_UpdateTooltip()
                                end,
                                'clickable', self.clickableTooltip,
                                'data', FuBar and FuBar_data.tooltip or self.data.detachedTooltip,
                                'detachedData', self.data.detachedTooltip,
                                'point', function(frame)
                                        if frame:GetTop() > GetScreenHeight() / 2 then
                                                local x = frame:GetCenter()
                                                if x < GetScreenWidth() / 3 then
                                                        return "TOPLEFT", "BOTTOMLEFT"
                                                elseif x < GetScreenWidth() * 2 / 3 then
                                                        return "TOP", "BOTTOM"
                                                else
                                                        return "TOPRIGHT", "BOTTOMRIGHT"
                                                end
                                        else
                                                local x = frame:GetCenter()
                                                if x < GetScreenWidth() / 3 then
                                                        return "BOTTOMLEFT", "TOPLEFT"
                                                elseif x < GetScreenWidth() * 2 / 3 then
                                                        return "BOTTOM", "TOP"
                                                else
                                                        return "BOTTOMRIGHT", "TOPRIGHT"
                                                end
                                        end
                                end,
                                'menu', function(level, value, valueN_1, valueN_2, valueN_3, valueN_4)
                                        if self.MenuSettings then
                                                self:MenuSettings(level, value, true, valueN_1, valueN_2, valueN_3, valueN_4)
                                        end
                                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(self.frame:GetName() .. "Text")
                        self.iconFrame = getglobal(self.frame:GetName() .. "Icon")
                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 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:IsIconShown() then
                                        self.iconFrame:Show()
                                else
                                        self.iconFrame: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_SHOWICON, loc.MAP_ONOFF[self:IsIconShown() and 1 or 0]))
                                end
                        else
                                function self:Report()
                                        local report = compost and compost:Acquire(
                                                compost:AcquireHash(
                                                        'text', loc.ARGUMENT_SHOWICON,
                                                        'val', self:IsIconShown() and 1 or 0,
                                                        'map', loc.MAP_ONOFF
                                                )
                                        ) or {{
                                                text = loc.ARGUMENT_SHOWICON,
                                                val = self:IsIconShown() and 1 or 0,
                                                map = loc.MAP_ONOFF
                                        }}
                                        self.cmd:report(report)
                                        if compost then
                                                compost:Reclaim(report, 1)
                                        end
                                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 and compost:Acquire(
                                                compost:AcquireHash(
                                                        'text', loc.ARGUMENT_SHOWTEXT,
                                                        'val', self:IsTextShown() and 1 or 0,
                                                        'map', loc.MAP_ONOFF
                                                )
                                        ) or {{
                                                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
                end
                
                if self.db then
                        local old_Initialize = self.Initialize
                        function self:Initialize()
                                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
                elseif FuBar then
                        local old_Initialize = self.Initialize
                        function self:Initialize()
                                local FuBarDB = FuBar2DB or FuBarDB
                                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.default then
                                        t.profiles.default = {}
                                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["default"]
                                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
                else
                        local old_Initialize = self.Initialize
                        function self:Initialize()
                                self.data = {}
                                self.charData = {}
                                self.classData = {}
                                self.realmData = {}
                                self.fullData = {}
                                
                                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
                end
                
                local old_Disable = self.Disable
                function self:Disable()
                        if old_Disable then
                                old_Disable(self)
                        end
                        self:Hide()
                end
                
                if not self.overrideTooltip then
                        self._UpdateTooltip = self.UpdateTooltip
                        function self:UpdateTooltip()
                                RegisterTablet(self)
                                tablet:Refresh(self.frame)
                        end
                end
                
                local self_Initialize = self.Initialize
                function self:Initialize()
                        self_Initialize(self)
                        
                        local profilePlugin = FuBar and FuBar:GetPluginProfiling()
                        
                        if self == profilePlugin then
                                local start = GetTime()
                                local tree = {}
                                local treeMemories = {}
                                local treeTimes = {}
                                local memories = {}
                                local times = {}
                                local aname = self.name
                                for name,value in pairs(self) do
                                        if type(value) == "function" and name ~= "Initialize" then
                                                local oldFunction = value
                                                local name = name
                                                local rName = name
                                                if name == "UpdateTooltip" then
                                                        name = "tablet:Refresh"
                                                elseif name == "_UpdateTooltip" then
                                                        name = "UpdateTooltip"
                                                end
                                                if strsub(name, 1, 1) ~= "_" then
                                                        memories[name] = 0
                                                        times[name] = 0
                                                        self[rName] = function(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
                                                                local pos = table.getn(tree)
                                                                table.insert(tree, name)
                                                                table.insert(treeMemories, 0)
                                                                table.insert(treeTimes, 0)
                                                                local t, mem = GetTime(), gcinfo() 
                                                                local r1, r2, r3, r4, r5, r6, r7, r8 = oldFunction(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
                                                                mem, t = gcinfo() - mem, GetTime() - t
                                                                if pos > 0 then
                                                                        treeMemories[pos] = treeMemories[pos] + mem
                                                                        treeTimes[pos] = treeTimes[pos] + t
                                                                end
                                                                local otherMem = table.remove(treeMemories)
                                                                if mem - otherMem > 0 then
                                                                        memories[name] = memories[name] + mem - otherMem
                                                                end
                                                                times[name] = times[name] + t - table.remove(treeTimes)
                                                                table.remove(tree)
                                                                return r1, r2, r3, r4, r5, r6, r7, r8
                                                        end
                                                end
                                        end
                                end
                                
                                if not self.cmd.options then
                                        self.cmd.options = {}
                                end
                                
                                table.insert(self.cmd.options, {
                                        option = loc.ARGUMENT_PROFILE,
                                        desc = loc.TEXT_LIST_PROFILING_INFO,
                                        method = "_ListProfileInfo"
                                })
                                
                                function self:_ListProfileInfo()
                                        local duration = GetTime() - start
                                        for name in pairs(memories) do
                                                local mem = memories[name]
                                                local time = times[name]
                                                DEFAULT_CHAT_FRAME:AddMessage(string.format("%.3fs / %.3fs (%.3f%%) || %s (%d KiB)", times[name], duration, times[name] / duration * 100, name, memories[name]))
                                        end
                                end
                                
                                function self:GetProfileInfo()
                                        return GetTime() - start, times, memories
                                end
                        end
                end
                
                if self.defaultPosition ~= "LEFT" and self.defaultPosition ~= "CENTER" and self.defaultPosition ~= "RIGHT" and self.defaultPosition ~= "MINIMAP" then
                        self.defaultPosition = "LEFT"
                end
                if type(self.defaultMinimapPosition) ~= "number" then
                        self.defaultMinimapPosition = math.random(1, 360)
                end
                
                self.frame:RegisterEvent("PLAYER_LOGOUT")
                local OnEvent = self.frame:GetScript("OnEvent")
                self.frame:SetScript("OnEvent", function()
                        if OnEvent then
                                OnEvent()
                        end
                        if event == "PLAYER_LOGOUT" then
                                local t
                                if self.db then
                                        t = self.db._table
                                elseif FuBar then
                                        local FuBarDB = FuBar2DB or FuBarDB
                                        t = FuBarDB.pluginDB[self:GetTitle()]
                                else
                                        return
                                end
                                if cleanDefaults(self.data, self.defaults) then
                                        if self.db then
                                                t.profiles[self.profilePath[2]] = nil
                                        else
                                                t.profiles["default"] = nil
                                        end
                                        if not next(t.profiles) then
                                                t.profiles = nil
                                        end
                                end
                                if cleanDefaults(self.charData, self.charDefaults) then
                                        if type(self.chardb) ~= "string" then
                                                t.chars[ace.char.realm .. ace.char.name] = nil
                                                if not next(t.chars) then
                                                        t.chars = nil
                                                end
                                        else
                                                setglobal(self.chardb, nil)
                                        end
                                end
                                if cleanDefaults(self.fullData, self.fullDefaults) then
                                        t.full = nil
                                end
                                if cleanDefaults(self.realmData, self.realmDefaults) then
                                        t.realms[ace.char.realm .. ace.char.faction] = nil
                                        if not next(t.realms) then
                                                t.realms = nil
                                        end
                                end
                                if cleanDefaults(self.classData, self.classDefaults) then
                                        t.classes[ace.char.class] = nil
                                        if not next(t.classes) then
                                                t.classes = nil
                                        end
                                end
                                if not next(t) then
                                        if self.db then
                                                setglobal(self.db.name, nil)
                                        else
                                                local FuBarDB = FuBar2DB or FuBarDB
                                                FuBarDB.pluginDB[self:GetTitle()] = nil
                                        end
                                end
                        end
                end)
                
                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
                
                AceAddon.RegisterForLoad(self)
                if FuBar then
                        FuBar:RegisterPlugin(self)
                end
        end
        
        function lib:GetLibraryVersion()
                return MAJOR_VERSION, MINOR_VERSION
        end
        
        function lib:LibActivate(stub, oldLib, oldList)
        end
        
        function lib:LibDeactivate()
        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:CreatePluginChildFrame(frameType, name, parent)
                assert(self.frame, "You must have self.frame declared in order to add child frames")
                self:argCheck(frameType, 1, "string")
                local child = CreateFrame(frameType, name, parent)
                if parent then
                        child:SetFrameLevel(parent:GetFrameLevel() + 2)
                end
                child:SetScript("OnEnter", function()
                        if self.frame:GetScript("OnEnter") then
                                self.frame:GetScript("OnEnter")()
                        end
                end)
                child:SetScript("OnLeave", function()
                        if self.frame:GetScript("OnLeave") then
                                self.frame:GetScript("OnLeave")()
                        end
                end)
                if child:HasScript("OnClick") then
                        child:SetScript("OnClick", function()
                                if self.frame:HasScript("OnClick") and self.frame:GetScript("OnClick") then
                                        self.frame:GetScript("OnClick")()
                                end
                        end)
                end
                if child:HasScript("OnDoubleClick") then
                        child:SetScript("OnDoubleClick", function()
                                if self.frame:HasScript("OnDoubleClick") and self.frame:GetScript("OnDoubleClick") then
                                        self.frame:GetScript("OnDoubleClick")()
                                end
                        end)
                end
                child:SetScript("OnMouseDown", function()
                        if self.frame:GetScript("OnMouseDown") then
                                self.frame:GetScript("OnMouseDown")()
                        end
                end)
                child:SetScript("OnMouseUp", function()
                        if self.frame:GetScript("OnMouseUp") then
                                self.frame:GetScript("OnMouseUp")()
                        end
                end)
                return child
        end
        
        function lib:OpenMenu(frame)
                if not frame then
                        frame = self:GetFrame()
                end
                if not frame or not self:GetFrame() or dewdrop:IsOpen(frame) then
                        dewdrop:Close()
                        return
                end
                tablet:Close()
                
                if not dewdrop:IsRegistered(self:GetFrame()) then
                        dewdrop:Register(self:GetFrame(),
                                'children', function(level, value, valueN_1, valueN_2, valueN_3, valueN_4)
                                        if level == 1 then
                                                dewdrop:AddLine(
                                                        'text', self:GetTitle(),
                                                        'isTitle', true
                                                )
                                        end
                                        
                                        if self.MenuSettings then
                                                self:MenuSettings(level, value, false, valueN_1, valueN_2, valueN_3, valueN_4)
                                        end
                                        
                                        if level == 1 and not self.overrideMenu then
                                                if self.MenuSettings then
                                                        dewdrop:AddLine()
                                                end
                                                self:AddImpliedMenuOptions()
                                        end
                                        if level == 1 then
                                                dewdrop:AddLine(
                                                        'text', CLOSE,
                                                        'func', dewdrop.Close,
                                                        'arg1', dewdrop
                                                )
                                        end
                                end,
                                'point', function(frame)
                                        local x, y = frame:GetCenter()
                                        local leftRight
                                        if x < GetScreenWidth() / 2 then
                                                leftRight = "LEFT"
                                        else
                                                leftRight = "RIGHT"
                                        end
                                        if y < GetScreenHeight() / 2 then
                                                return "BOTTOM" .. leftRight, "TOP" .. leftRight
                                        else
                                                return "TOP" .. leftRight, "BOTTOM" .. leftRight
                                        end
                                end,
                                'dontHook', true
                        )
                end
                if frame == self:GetFrame() then
                        dewdrop:Open(self:GetFrame())
                else
                        dewdrop:Open(frame, self:GetFrame())
                end
        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.versions["1.0"] and self:GetInstance("1.0"):new(o)
                        elseif compatNumber < 103 then
                                return self.versions["1.2"] and self:GetInstance("1.2"):new(o)
                        end
                end
        end
end

-- MinimapContainer
do
        local lib = {}
        
        local initialized = false
        function lib:Initialize()
                if initialized then
                        return
                end
                initialized = true
                
                self.plugins = {}
        end
        
        function lib:AddPlugin(plugin)
                if FuBar and FuBar:IsChangingProfile() then
                        return
                end
                self:Initialize()
                if plugin.panel ~= nil then
                        plugin.panel:RemovePlugin(plugin)
                end
                plugin.panel = self
                if not plugin.minimapFrame then
                        local frame = CreateFrame("Button", plugin.frame:GetName() .. "MinimapButton", Minimap)
                        plugin.minimapFrame = frame
                        RegisterTablet(plugin)
                        tablet:Register(frame, plugin.frame)
                        frame.plugin = plugin
                        frame:SetWidth(31)
                        frame:SetHeight(31)
                        frame:SetFrameStrata("LOW")
                        frame:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
                        local icon = frame:CreateTexture(frame:GetName() .. "Icon", "BACKGROUND")
                        plugin.minimapIcon = icon
                        local path = plugin:GetIcon() or (plugin.iconFrame and plugin.iconFrame:GetTexture()) or "Interface\\Icons\\INV_Misc_QuestionMark"
                        icon:SetTexture(path)
                        if string.sub(path, 1, 16) == "Interface\\Icons\\" then
                                icon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
                        else
                                icon:SetTexCoord(0, 1, 0, 1)
                        end
                        icon:SetWidth(20)
                        icon:SetHeight(20)
                        icon:SetPoint("TOPLEFT", frame, "TOPLEFT", 7, -5)
                        local overlay = frame:CreateTexture(frame:GetName() .. "Overlay","OVERLAY")
        overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
                        overlay:SetWidth(53)
                        overlay:SetHeight(53)
                        overlay:SetPoint("TOPLEFT",frame,"TOPLEFT")
                        frame:EnableMouse(true)
                        frame:RegisterForClicks("LeftButtonUp")
                        frame.plugin = plugin
                        if type(plugin.OnClick) == "function" then
                                frame:SetScript("OnClick", function()
                                        if not this.dragged then
                                                plugin:OnClick(arg1)
                                        end
                                end)
                        end
                        if type(plugin.OnDoubleClick) == "function" then
                                frame:SetScript("OnDoubleClick", function()
                                        plugin:OnDoubleClick(arg1)
                                end)
                        end
                        frame:SetScript("OnMouseDown", function()
                                this.dragged = false
                                if arg1 == "LeftButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
                                        HideDropDownMenu(1)
                                        if type(plugin.OnMouseDown) == "function" then
                                                plugin:OnMouseDown(arg1)
                                        end
                                elseif arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
                                        plugin:OpenMenu(frame)
                                else
                                        HideDropDownMenu(1)
                                        if type(plugin.OnMouseDown) == "function" then
                                                plugin:OnMouseDown(arg1)
                                        end
                                end
                                if plugin.OnClick or plugin.OnMouseDown or plugin.OnMouseUp or plugin.OnDoubleClick then
                                        if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then
                                                plugin.minimapIcon:SetTexCoord(0.14, 0.86, 0.14, 0.86)
                                        else
                                                plugin.minimapIcon:SetTexCoord(0.1, 0.9, 0.1, 0.9)
                                        end
                                end
                        end)
                        frame:SetScript("OnMouseUp", function()
                                if not this.dragged and type(plugin.OnMouseUp) == "function" then
                                        plugin:OnMouseUp(arg1)
                                end
                                if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then
                                        plugin.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
                                else
                                        plugin.minimapIcon:SetTexCoord(0, 1, 0, 1)
                                end
                        end)
                        frame:RegisterForDrag("LeftButton")
                        frame:SetScript("OnDragStart", self.OnDragStart)
                        frame:SetScript("OnDragStop", self.OnDragStop)
                end
                plugin.frame:Hide()
                plugin.minimapFrame:Show()
                self:ReadjustLocation(plugin)
                table.insert(self.plugins, plugin)
                local exists = false
                return true
        end
        
        function lib:RemovePlugin(index)
                if FuBar and FuBar:IsChangingProfile() then
                        return
                end
                self:Initialize()
                if type(index) == "table" then
                        index = self:IndexOfPlugin(index)
                        if not index then
                                return
                        end
                end
                local t = self.plugins
                local plugin = t[index]
                assert(plugin.panel == self, "Plugin has improper panel field")
                plugin:SetPanel(nil)
                table.remove(t, index)
                return true
        end
        
        function lib:ReadjustLocation(plugin)
                local frame = plugin.minimapFrame
                if not plugin.data.minimapPositionWild then
                        local position = plugin.data.minimapPosition or plugin.defaultMinimapPosition or math.random(1, 360)
                        local angle = math.rad(position or 0)
                        local x = math.cos(angle) * 80
                        local y = math.sin(angle) * 80
                        frame:SetPoint("CENTER", Minimap, "CENTER", x, y)
                else
                        frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", plugin.data.minimapPositionX, plugin.data.minimapPositionY)
                end
        end

        function lib:GetPlugin(index)
                return self.plugins[index]
        end

        function lib:GetNumPlugins()
                return table.getn(self.plugins)
        end
        
        function lib:IndexOfPlugin(plugin)
                for i,p in ipairs(self.plugins) do
                        if p == plugin then
                                return i, "MINIMAP"
                        end
                end
        end
        
        function lib:HasPlugin(plugin)
                return self:IndexOfPlugin(plugin) ~= nil
        end
        
        function lib:GetPluginSide(plugin)
                local index = self:IndexOfPlugin(plugin)
                assert(index, "Plugin not in panel")
                return "MINIMAP"
        end
        
        function lib.OnDragStart()
                this.dragged = true
                this:LockHighlight()
                this:SetScript("OnUpdate", FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION).OnUpdate)
                if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then
                        this.plugin.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
                else
                        this.plugin.minimapIcon:SetTexCoord(0, 1, 0, 1)
                end
        end
        
        function lib.OnDragStop()
                this:SetScript("OnUpdate", nil)
                this:UnlockHighlight()
        end
        
        function lib.OnUpdate()
                if not IsAltKeyDown() then
                        local mx, my = Minimap:GetCenter()
                        local px, py = GetCursorPosition()
                        local scale = UIParent:GetEffectiveScale()
                        px, py = px / scale, py / scale
                        local lastPosition = this.plugin.data.minimapPosition
                        local position = math.deg(math.atan2(py - my, px - mx))
                        if position <= 0 then
                                position = position + 360
                        elseif position > 360 then
                                position = position - 360
                        end
                        this.plugin.data.minimapPosition = position
                        this.plugin.data.minimapPositionX = nil
                        this.plugin.data.minimapPositionY = nil
                        this.plugin.data.minimapPositionWild = nil
                else
                        local px, py = GetCursorPosition()
                        local scale = UIParent:GetEffectiveScale()
                        px, py = px / scale, py / scale
                        this.plugin.data.minimapPositionX = px
                        this.plugin.data.minimapPositionY = py
                        this.plugin.data.minimapPosition = nil
                        this.plugin.data.minimapPositionWild = true
                end
                FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION):ReadjustLocation(this.plugin)
        end
        
        function lib:GetLibraryVersion()
                return MAJOR_VERSION, MINOR_VERSION
        end
        
        function lib:LibActivate(stub, oldLib, oldList)
        end
        
        function lib:LibDeactivate()
        end
        
        FuBarPlugin.MinimapContainer:Register(lib)
        lib = nil
end