changeset 28:21bcaf8215ff

- converted to Ace3 - rearranged file layout - configGUI menus not working right now
author Flick <flickerstreak@gmail.com>
date Mon, 17 Mar 2008 18:24:53 +0000
parents f1e838841ce1
children 9c89042bc328
files Bar.lua ReAction.lua ReAction.toc ReAction.xml ReAction_Bar.lua bindings.lua lib/AceAddon-2.0/AceAddon-2.0.lua lib/AceAddon-2.0/AceAddon-2.0.toc lib/AceAddon-3.0/AceAddon-3.0.lua lib/AceAddon-3.0/AceAddon-3.0.xml lib/AceConsole-2.0/AceConsole-2.0.lua lib/AceConsole-2.0/AceConsole-2.0.toc lib/AceDB-2.0/AceDB-2.0.lua lib/AceDB-2.0/AceDB-2.0.toc lib/AceDB-3.0/AceDB-3.0.lua lib/AceDB-3.0/AceDB-3.0.xml lib/AceEvent-2.0/AceEvent-2.0.lua lib/AceEvent-2.0/AceEvent-2.0.toc lib/AceEvent-3.0/AceEvent-3.0.lua lib/AceEvent-3.0/AceEvent-3.0.xml lib/AceLibrary/AceLibrary.lua lib/AceLibrary/AceLibrary.toc lib/AceLocale-2.2/AceLocale-2.2.lua lib/AceLocale-2.2/AceLocale-2.2.toc lib/AceLocale-3.0/AceLocale-3.0.lua lib/AceLocale-3.0/AceLocale-3.0.xml lib/AceModuleCore-2.0/AceModuleCore-2.0.lua lib/AceModuleCore-2.0/AceModuleCore-2.0.toc lib/AceOO-2.0/AceOO-2.0.lua lib/AceOO-2.0/AceOO-2.0.toc lib/CallbackHandler-1.0/CallbackHandler-1.0.lua lib/CallbackHandler-1.0/CallbackHandler-1.0.xml lib/Dewdrop-2.0/Dewdrop-2.0.lua lib/LibStub/LibStub.lua lib/embeds.xml locale/enUS.lua modules/FuBar_ReActionFu/FuBar_ReActionFu.lua modules/FuBar_ReActionFu/FuBar_ReActionFu.xml modules/FuBar_ReActionFu/lib/AceAddon-2.0/AceAddon-2.0.lua modules/FuBar_ReActionFu/lib/AceAddon-2.0/AceAddon-2.0.toc modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.lua modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.toc modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.lua modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.toc modules/FuBar_ReActionFu/lib/AceOO-2.0/AceOO-2.0.lua modules/FuBar_ReActionFu/lib/AceOO-2.0/AceOO-2.0.toc modules/FuBar_ReActionFu/lib/Dewdrop-2.0/Dewdrop-2.0.lua modules/ReAction_Action/ReAction_Action.lua modules/ReAction_ConfigUI/ReAction_ConfigUI.lua modules/ReAction_ConfigUI/ReAction_ConfigUI.xml modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.lua modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.toc modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.lua modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.toc modules/ReAction_ConfigUI/lib/Dewdrop-2.0/Dewdrop-2.0.lua modules/ReAction_HideBlizzard/ReAction_HideBlizzard.lua modules/ReAction_ModuleTemplate/ReAction_ModuleName.lua modules/ReAction_PetAction/ReAction_PetAction.lua modules/ReAction_PetAction/ReAction_PetAction.toc modules/ReAction_PetAction/ReAction_PetAction.xml modules/ReAction_State/ReAction_State.lua modules/modules.xml
diffstat 62 files changed, 15420 insertions(+), 14580 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Bar.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,146 @@
+local ReAction = ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+
+-- update ReAction revision if this file is newer
+local revision = tonumber(("$Revision: 1 $"):match("%d+"))
+if revision > ReAction.revision then
+  Reaction.revision = revision
+end
+
+------ BAR CLASS ------
+local Bar = { _classID = {} }
+
+local function Constructor( self, name, config )
+  self.name, self.config = name, config
+
+  if type(config) ~= "table" then
+    error("ReAction.Bar: config table required")
+  end
+
+  local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate")
+  f:SetFrameStrata("MEDIUM")
+  config.width = config.width or 400
+  config.height = config.height or 80
+  f:SetWidth(config.width)
+  f:SetWidth(config.height)
+
+  self.frame = f
+  self:RefreshLayout()
+  self:ApplyAnchor()
+  f:Show()
+end
+
+function Bar:Destroy()
+  local f = self.frame
+  f:UnregisterAllEvents()
+  f:Hide()
+  f:SetParent(UIParent)
+  f:ClearAllPoints()
+  self.labelString = nil
+  self.controlFrame = nil
+  self.frame = nil
+  self.config = nil
+end
+
+function Bar:RefreshLayout()
+  ReAction:CallMethodOnAllModules("RefreshBar", self)
+end
+
+function Bar:ApplyAnchor()
+  local f, config = self.frame, self.config
+  f:SetWidth(config.width)
+  f:SetHeight(config.height)
+  local anchor = config.anchor
+  if anchor then
+    local anchorTo
+    if config.anchorTo then
+      anchorTo = ReAction:GetBar(config.anchorTo) or _G[config.anchorTo]
+    end
+    f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0)
+  else
+    f:SetPoint("CENTER")
+  end
+end
+
+function Bar:GetFrame()
+  return self.frame
+end
+
+function Bar:GetSize()
+  return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200
+end
+
+function Bar:SetSize(w,h)
+  self.config.width = w
+  self.config.height = h
+end
+
+function Bar:GetButtonSize()
+  local w = self.config.btnWidth or 32
+  local h = self.config.btnHeight or 32
+  -- TODO: get from modules?
+  return w,h
+end
+
+function Bar:SetButtonSize(w,h)
+  if w > 0 and h > 0 then
+    self.config.btnWidth = w
+    self.config.btnHeight = h
+  end
+end
+
+function Bar:GetButtonGrid()
+  local cfg = self.config
+  local r = cfg.btnRows or 1
+  local c = cfg.btnColumns or 1
+  local s = cfg.spacing or 4
+  return r,c,s
+end
+
+function Bar:SetButtonGrid(r,c,s)
+  if r > 0 and c > 0 and s > 0 then
+    local cfg = self.config
+    cfg.btnRows = r
+    cfg.btnColumns = c
+    cfg.spacing = s
+  end
+end
+
+function Bar:GetName()
+  return self.name
+end
+
+function Bar:PlaceButton(f, idx, baseW, baseH)
+  local r, c, s = self:GetButtonGrid()
+  local bh, bw = self:GetButtonSize()
+  local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based
+  local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s
+  local scale = bw/baseW
+
+  f:ClearAllPoints()
+  f:SetPoint("TOPLEFT",x/scale,-y/scale)
+  f:SetScale(scale)
+--  f:Show()
+end
+
+
+
+------ Export as a class-factory ------
+ReAction.Bar = {
+  prototype = Bar,
+
+  IsInstance = function(self, x)
+    return type(x) == "table" and x._classID == Bar._classID
+  end,
+
+  new = function(self, ...)
+    local x = { }
+    for k,v in pairs(Bar) do
+      x[k] = v
+    end
+    Constructor(x, ...)
+    return x
+  end
+}
--- a/ReAction.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/ReAction.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -1,95 +1,19 @@
---[[
-  ReAction Add-On main file. 
-  Performs add-on and library initialization and setup.
---]]
+-- ReAction.lua
+-- See modules/ReAction_ModuleTemplate for Module API listing
+-- See Bar.lua for Bar object listing
 
------- LOCALIZATION ----------
-local L = AceLibrary("AceLocale-2.2"):new("ReAction")
-
-
------- GLOBAL VARIABLES ------
--- 'ReAction' is exported as a global.
-ReAction = AceLibrary("AceAddon-2.0"):new(
-  "AceModuleCore-2.0",
-  "AceEvent-2.0",
-  "AceDB-2.0"
-)
--- global variable strings for integration with WoW keybindings dialog (see bindings.xml)
-BINDING_HEADER_REACTION             = L["ReAction"]
-BINDING_NAME_REACTION_TOGGLELOCK    = L["Toggle ReAction Bar Lock"]
-BINDING_NAME_REACTION_TOGGLEKEYBIND = L["ReAction Keybinding Mode"]
-
+------ LIBRARIES ------
+local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
 
 ------ CORE ------
-local ReAction = ReAction
+local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction" )
 ReAction.revision = tonumber(("$Revision: 1 $"):match("%d+"))
 ReAction.L = L
 
+------ GLOBALS ------
+_G["ReAction"] = ReAction
 
-
--- from AceAddon-2.0
-function ReAction:OnInitialize()
-  self:RegisterDB("ReActionDB")
-end
-
--- from AceAddon-2.0
-function ReAction:OnEnable()
-
-end
-
--- from AceAddon-2.0
-function ReAction:OnDisable()
-
-end
-
--- from AceDB-2.0
-function ReAction:OnProfileEnable()
-
-end
-
--- from AceDB-2.0
-function ReAction:OnProfileDisable()
-
-end
-
--- from AceModuleCore-2.0
-function ReAction:OnModuleEnable(module)
-  -- this handles initialization ordering issues with ReAction_Bar
-  local barMod = self:GetModule("Bar")
-  if barMod and module.ApplyToBar then
-    for _, b in pairs(barMod.bars) do
-      if b then
-        module:ApplyToBar(b)
-      end
-    end
-  end
-end
-
--- from AceModuleCore-2.0
-function ReAction:OnModuleDisable(module)
-  local barMod = self:GetModule("Bar")
-  if barMod and module.RemoveFromBar then
-    for _, b in pairs(barMod.bars) do
-      if b then
-        module:RemoveFromBar(b)
-      end
-    end
-  end
-end
-
---[[
-  Module API (see bar.lua for usage)
-
-  module:ApplyToBar(bar)
-  module:RemoveFromBar(bar)
-  module:RefreshBar(bar)
-  module:ApplyConfigMode(mode,listOfBars)
-  module:GetBarNameModifier(bar)
-  module:EraseBarConfig(barName)
-]]--
-
-
--- debugging
+------ DEBUGGING ------
 ReAction.debug = true
 if ReAction.debug then
   ReAction.print = function(msg)
@@ -100,3 +24,204 @@
   ReAction.print = function() end
 end
 
+------ PRIVATE ------
+local SelectBar, DestroyBar, InitializeBars, TearDownBars, DeepCopy, SafeCall, CheckMethod
+do
+  local pcall = pcall
+  local geterrorhandler = geterrorhandler
+
+  SelectBar = function(x)
+    local bar, name
+    if type(x) == "string" then
+      name = x
+      bar = ReAction:GetBar(name)
+    elseif ReAction.Bar:IsInstance(x) then
+      bar = x
+      for k,v in pairs(ReAction.bars) do
+        if v == bar then
+          name = k
+        end
+      end
+    else
+      error("bad argument to SelectBar")
+    end
+    return bar, name
+  end
+
+  DestroyBar = function(x)
+    local bar, name = SelectBar(x)
+    if name and bar then
+      ReAction.bars[name] = nil
+      ReAction:CallMethodOnAllModules("RemoveFromBar", bar)
+      bar:Destroy()
+    end
+  end
+
+  InitializeBars = function ()
+    if not(ReAction.inited) then
+      for name, config in pairs(ReAction.db.profile.bars) do
+        if config then
+          ReAction:CreateBar(name, config)
+        end
+      end
+      ReAction:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering
+      ReAction.inited = true
+    end
+  end
+
+  TearDownBars = function()
+    for name, bar in pairs(ReAction.bars) do
+      if bar then
+        ReAction.bars[name] = DestroyBar(bar)
+      end
+    end
+    ReAction.inited = false
+  end
+
+  DeepCopy = function(x)
+    if type(x) ~= "table" then
+      return x
+    end
+    local r = {}
+    for k,v in pairs(x) do
+      r[k] = DeepCopy(v)
+    end
+    return r
+  end
+
+  SafeCall = function(f, ...)
+    if f then
+      local success, err = pcall(f,...)
+      if not success then
+        geterrorhandler()(err)
+      end
+    end
+  end
+
+  CheckMethod = function(m)
+    if type(m) == "function" then
+      return m
+    end
+    if type(m) ~= "string" then
+      error("Invalid method")
+    end
+  end
+end
+
+
+------ HANDLERS ------
+function ReAction:OnInitialize()
+  self.db = LibStub("AceDB-3.0"):New("ReAction_DB", 
+    { 
+      profile = {
+        bars = { },
+        defaultBar = { }
+      }
+    }
+    -- default profile is character-specific
+  )
+  self.db.RegisterCallback(self,"OnProfileChanged")
+
+  self.bars = {}
+end
+
+function ReAction:OnEnable()
+  InitializeBars()
+end
+
+function ReAction:OnDisable()
+  TearDownBars()
+end
+
+function ReAction:OnProfileChanged()
+  self.TearDownBars()
+  self.InitializeBars()
+end
+
+function ReAction:OnModuleEnable(module)
+  if module.ApplyToBar then
+    for _, b in pairs(bars) do
+      if b then
+        module:ApplyToBar(b)
+      end
+    end
+  end
+end
+
+function ReAction:OnModuleDisable(module)
+  if module.RemoveFromBar then
+    for _, b in pairs(bars) do
+      if b then
+        module:RemoveFromBar(b)
+      end
+    end
+  end
+end
+
+
+------ API ------
+function ReAction:CallMethodOnAllModules(method, ...)
+  local m = CheckMethod(method)
+  for _, x in self:IterateModules() do
+    if x then
+      SafeCall(m or x[method], x, ...)
+    end
+  end
+end
+
+function ReAction:CallMethodOnAllBars(method,...)
+  local m = CheckMethod(method)
+  for _, x in pairs(self.bars) do
+    if x then
+      SafeCall(m or x[method], x, ...)
+    end
+  end
+end
+
+function ReAction:CreateBar(name, defaultConfig, prefix)
+  local profile = self.db.profile
+  defaultConfig = defaultConfig or profile.defaultBar
+  prefix = prefix or L["Bar "]
+  if not name then
+    i = 1
+    repeat
+      name = prefix..i
+      i = i + 1
+    until self.bars[name] == nil
+  end
+  profile.bars[name] = profile.bars[name] or DeepCopy(defaultConfig)
+  local bar = self.Bar:new( name, profile.bars[name] )  -- ReAction.Bar defined in Bar.lua
+  self:CallMethodOnAllModules("ApplyToBar", bar)
+  self.bars[name] = bar
+  return bar
+end
+
+function ReAction:EraseBar(x)
+  local bar, name = SelectBar(x)
+  if name and bar then
+    DestroyBar(bar)
+    self.db.profile.bars[name] = nil
+    self:CallMethodOnAllModules("EraseBarConfig", name)
+  end
+end
+
+function ReAction:GetBar(name)
+  return self.bars[name]
+end
+
+function ReAction:RenameBar(x, newname)
+  local bar, name = SelectBar(x)
+  if bar and name and newname then
+    if self.bars[newname] then
+      error(L["ReAction: name already in use"])
+    end
+    self.bars[newname] = self.bars[name]
+    self.bars[name] = nil
+    bar.name = newname or ""
+    local cfg = self.db.profile.bars
+    cfg[newname], cfg[name] = cfg[name], nil
+    self:CallMethodOnAllModules("RenameBarConfig", name, newname)
+  end
+end
+
+
--- a/ReAction.toc	Tue Mar 11 21:39:34 2008 +0000
+++ b/ReAction.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -5,8 +5,7 @@
 ## LoadOnDemand: 0
 ## Author: Flick
 ## Version: 1.0
-## SavedVariables: ReActionDB
+## SavedVariables: ReAction_DB
 ## X-Category: Action Bars
-## X-Embeds: AceAddon-2.0, AceConsole-2.0, AceDB-2.0, AceEvent-2.0, AceHook-2.1, AceLibrary, AceLocale-2.2, AceModuleCore-2.0, AceOO-2.0, Dewdrop-2.0, Waterfall-1.0
 
 ReAction.xml
--- a/ReAction.xml	Tue Mar 11 21:39:34 2008 +0000
+++ b/ReAction.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -6,8 +6,9 @@
 <Include file="locale\locale.xml"/>
 
 <Script file="ReAction.lua"/>
-<Script file="ReAction_Bar.lua"/>
+<Script file="Bar.lua"/>
 
 <Include file="modules\modules.xml"/>
+<Include file="bindings.lua"/>
 
 </Ui>
--- a/ReAction_Bar.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,393 +0,0 @@
---[[
-  ReAction bar module.
-
-  This is the heart of ReAction, the bar management module. Many of its
-  functions turn around and iterate all modules registered to the ReAction
-  parent core.
-
-  Also defined in this file is the Bar class implementation, which can be
-  used by other modules to manipulate the action bars. Many of the module
-  iterated calls pass a bar or list of bars as an argument.
-
-  Module methods called by the Bar module:
-    module:ApplyToBar(bar)
-    module:RemoveFromBar(bar)
-    module:RefreshBar(bar)
-    module:ApplyConfigMode(mode,listOfBars)
-    module:GetBarNameModifier(bar)
-    module:EraseBarConfig(barName)
-
-
-  useful Bar object API (partial list):
-    f     = bar:GetFrame()      -- f is derived from SecureStateDriver
-            bar:RefreshLayout()
-    w,h   = bar:GetSize()
-    r,c,s = bar:GetButtonGrid() -- #rows, #columns, inter-button spacing
-    name  = bar:GetName()
-            bar:PlaceButton(frame, idx, baseSizeX, baseSizeY) -- idx is 1-based
-
---]]
-
--- local imports
-local ReAction = ReAction
-local L = ReAction.L
-local _G = _G
-local AceOO = AceLibrary("AceOO-2.0")
-local CreateFrame = CreateFrame
-local geterrorhandler = geterrorhandler
-local pcall = pcall
-local print = ReAction.print
-
--- update ReAction revision if this file is newer
-local revision = tonumber(("$Revision: 1 $"):match("%d+"))
-if revision > ReAction.revision then
-  Reaction.revision = revision
-end
-
-local moduleID = "Bar"
-
---
--- Bar module declaration
---
-local module = ReAction:NewModule( moduleID )
-
---
--- Bar class declaration
---
-local BarClass = AceOO.Class()
-local Bar = BarClass.prototype
-module.BarClass = BarClass
-
---
--- local utility
---
-local function deepCopy(x)
-  if type(x) ~= "table" then
-    return x
-  end
-  local r = {}
-  for k,v in pairs(x) do
-    r[k] = deepCopy(v)
-  end
-  return r
-end
-
---
--- Bar module implementation
---
-function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
-    { 
-      bars = { },
-      defaultBar = { }
-    }
-  )
-  self.bars = {}
-end
-
-function module:OnEnable()
-  self:InitializeBars()
-end
-
-function module:OnDisable()
-  self:TearDownBars()
-end
-
-function module:OnProfileEnable()
-  self:InitializeBars()
-end
-
-function module:OnProfileDisable()
-  self:TearDownBars()
-end
-
-function module:InitializeBars()
-  if not(self.inited) then
-    for name, config in pairs(self.db.profile.bars) do
-      if config then
-        self:CreateBar(name, config)
-      end
-    end
-    self:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering
-    self.inited = true
-  end
-end
-
-function module:TearDownBars()
-  for name, bar in pairs(self.bars) do
-    if bar then
-      self.bars[name] = self:DeleteBar(bar)
-    end
-  end
-  self.inited = false
-end
-
--- Gets config from existing DB name or default if not supplied
--- Saves to DB if name not known
-function module:CreateBar(name, config)
-  local profile = self.db.profile
-  if not name then
-    i = 1
-    repeat
-      name = L["Bar "]..i
-      i = i + 1
-    until self.bars[name] == nil
-  end
-  config = config or profile.bars[name] or deepCopy(profile.defaultBar)
-  if not profile.bars[name] then
-    profile.bars[name] = config
-  end
-  local bar = self.BarClass:new( name, config )
-  ReAction:CallMethodOnAllModules("ApplyToBar", bar)
-  self.bars[name] = bar
-  return bar
-end
-
-
-local SelectBar
-do
-  SelectBar = function(x)
-    local bar, name
-    if type(x) == "string" then
-      name = x
-      bar = module:GetBar(name)
-    elseif AceOO.inherits(x,BarClass) then
-      bar = x
-      for k,v in pairs(module.bars) do
-        if v == bar then
-          name = k
-        end
-      end
-    else
-      error("bad argument to SelectBar")
-    end
-    return bar, name
-  end
-end
-
--- Takes either a bar name string or a bar object.
--- Does NOT destroy the DB entry, this function is only used for 
--- enable/disable and profile switching. To remove a bar permanently,
--- use EraseBar() instead.
-function module:DeleteBar(x)
-  local bar, name = SelectBar(x)
-  if name and bar then
-    self.bars[name] = nil
-    ReAction:CallMethodOnAllModules("RemoveFromBar", bar)
-    bar:Destroy()
-  end
-end
-
-function module:EraseBar(x)
-  local bar, name = SelectBar(x)
-  if name and bar then
-    self:DeleteBar(bar)
-    self.db.profile.bars[name] = nil
-    ReAction:CallMethodOnAllModules("EraseBarConfig", name)
-  end
-end
-
-function module:GetBar(name)
-  return self.bars[name]
-end
-
-function module:RenameBar(x, newname)
-  local bar, name = SelectBar(x)
-  if bar and name and newname then
-    if self.bars[newname] then
-      error(L["ReAction: name already in use"])
-    end
-    self.bars[newname] = self.bars[name]
-    self.bars[name] = nil
-    bar:SetName(newname)
-    local cfg = self.db.profile.bars
-    cfg[newname], cfg[name] = cfg[name], nil
-  end
-end
-
-function module:CallMethodOnAllBars(method,...)
-  local m
-  if type(method) == "function" then
-    m = method
-  elseif type(method) ~= "string" then
-    error("Invalid method passed to ReAction_Bar:CallMethodOnAllBars()")
-  end
-  for _, bar in pairs(self.bars) do
-    if bar then
-      local m = m or bar[method]
-      if m then
-        local success,err = pcall(m,bar,...)
-        if not success then
-          geterrorhandler()(err)
-        end
-      end
-    end
-  end
-end
-
-
-
-function module:GetBarMenuOptions(bar)
-  if not(bar.modMenuOpts[moduleID]) then
-    bar.modMenuOpts[moduleID] = {
-      delete = {
-        type = "execute",
-        name = L["Delete Bar"],
-        desc = L["Remove the bar from the current profile"],
-        func = function() self:EraseBar(bar) end,
-        order = 1
-      },
-    }
-  end
-  return bar.modMenuOpts[moduleID]
-end
-
-function module:GetBarConfigOptions(bar, cfgModule)
-  if not(bar.modConfigOpts[moduleID]) then
-    bar.modConfigOpts[moduleID] = {
-      delete = {
-        type = "execute",
-        name = L["Delete Bar"],
-        desc = L["Remove the bar from the current profile"],
-        func = function() self:EraseBar(bar); cfgModule:RefreshConfig() end
-      },
-      rename = {
-        type = "text",
-        name = L["Rename Bar"],
-        desc = L["Set a name for the bar"],
-        get  = "GetName",
-        set  = function(name) self:RenameBar(bar,name); cfgModule:RefreshConfig() end
-      }
-    }
-  end
-  return bar.modConfigOpts[moduleID]
-end
-
-
-
---
--- Bar class implementation
---
-function Bar:init( name, config )
-  BarClass.super.prototype.init(self)
-  self.name, self.config = name, config
-
-  if type(config) ~= "table" then
-    error("ReAction:Bar: config table required")
-  end
-
-  local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate")
-  f:SetFrameStrata("MEDIUM")
-  config.width = config.width or 400
-  config.height = config.height or 80
-  f:SetWidth(config.width)
-  f:SetWidth(config.height)
-
-  self.frame = f
-  self:RefreshLayout()
-  self:ApplyAnchor()
-  f:Show()
-end
-
-function Bar:Destroy()
-  local f = self.frame
-  f:UnregisterAllEvents()
-  f:Hide()
-  f:SetParent(UIParent)
-  f:ClearAllPoints()
-  self.labelString = nil
-  self.controlFrame = nil
-  self.frame = nil
-  self.config = nil
-end
-
-function Bar:RefreshLayout()
-  ReAction:CallMethodOnAllModules("RefreshBar", self)
-end
-
-function Bar:ApplyAnchor()
-  local f, config = self.frame, self.config
-  f:SetWidth(config.width)
-  f:SetHeight(config.height)
-  local anchor = config.anchor
-  if anchor then
-    local anchorTo
-    if config.anchorTo then
-      anchorTo = module:GetBar(config.anchorTo) or _G[config.anchorTo]
-    end
-    f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0)
-  else
-    f:SetPoint("CENTER")
-  end
-end
-
-function Bar:GetFrame()
-  return self.frame
-end
-
-function Bar:GetSize()
-  return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200
-end
-
-function Bar:SetSize(w,h)
-  self.config.width = w
-  self.config.height = h
-end
-
-function Bar:GetButtonSize()
-  local w = self.config.btnWidth or 32
-  local h = self.config.btnHeight or 32
-  -- TODO: get from modules?
-  return w,h
-end
-
-function Bar:SetButtonSize(w,h)
-  if w > 0 and h > 0 then
-    self.config.btnWidth = w
-    self.config.btnHeight = h
-  end
-end
-
-function Bar:GetButtonGrid()
-  local cfg = self.config
-  local r = cfg.btnRows or 1
-  local c = cfg.btnColumns or 1
-  local s = cfg.spacing or 4
-  return r,c,s
-end
-
-function Bar:SetButtonGrid(r,c,s)
-  if r > 0 and c > 0 and s > 0 then
-    local cfg = self.config
-    cfg.btnRows = r
-    cfg.btnColumns = c
-    cfg.spacing = s
-  end
-end
-
--- This should only be called from module:RenameBar(), otherwise
--- the bar's internal name and the module's list of bars by name
--- can get out of sync.
-function Bar:SetName( name )
-  name = name or ""
-  self.name = name
-end
-
-function Bar:GetName()
-  return self.name
-end
-
-function Bar:PlaceButton(f, idx, baseW, baseH)
-  local r, c, s = self:GetButtonGrid()
-  local bh, bw = self:GetButtonSize()
-  local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based
-  local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s
-  local scale = bw/baseW
-
-  f:ClearAllPoints()
-  f:SetPoint("TOPLEFT",x/scale,-y/scale)
-  f:SetScale(scale)
---  f:Show()
-end
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,7 @@
+local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
+local _G = _G
+
+_G["BINDING_HEADER_REACTION"]             = L["ReAction"]
+
+_G["BINDING_NAME_REACTION_TOGGLELOCK"]    = L["Toggle ReAction Bar Lock"]
+_G["BINDING_NAME_REACTION_TOGGLEKEYBIND"] = L["ReAction Keybinding Mode"]
--- a/lib/AceAddon-2.0/AceAddon-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1394 +0,0 @@
---[[
-Name: AceAddon-2.0
-Revision: $Rev: 46764 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/wiki/AceAddon-2.0
-SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceAddon-2.0
-Description: Base for all Ace addons to inherit from.
-Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "AceAddon-2.0"
-local MINOR_VERSION = "$Revision: 46764 $"
-
--- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
-
-local function safecall(func,...)
-	local success, err = pcall(func,...)
-	if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
-end
--- Localization
-local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, CREDITS, WEBSITE, CATEGORIES, ABOUT, LICENSE, PRINT_ADDON_INFO, DONATE, DONATE_DESC, HOWTO_DONATE_WINDOWS, HOWTO_DONATE_MAC
-if GetLocale() == "deDE" then
-	STANDBY = "|cffff5050(Standby)|r" -- capitalized
-
-	TITLE = "Titel"
-	NOTES = "Anmerkung"
-	VERSION = "Version"
-	AUTHOR = "Autor"
-	DATE = "Datum"
-	CATEGORY = "Kategorie"
-	EMAIL = "E-Mail"
-	WEBSITE = "Webseite"
-	CREDITS = "Credits" -- fix
-	LICENSE = "License" -- fix
-
-	ABOUT = "Über"
-	PRINT_ADDON_INFO = "Gibt Addondaten aus"
-	DONATE = "Donate" -- fix
-	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
-	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-
-	CATEGORIES = {
-		["Action Bars"] = "Aktionsleisten",
-		["Auction"] = "Auktion",
-		["Audio"] = "Audio",
-		["Battlegrounds/PvP"] = "Schlachtfeld/PvP",
-		["Buffs"] = "Stärkungszauber",
-		["Chat/Communication"] = "Chat/Kommunikation",
-		["Druid"] = "Druide",
-		["Hunter"] = "Jäger",
-		["Mage"] = "Magier",
-		["Paladin"] = "Paladin",
-		["Priest"] = "Priester",
-		["Rogue"] = "Schurke",
-		["Shaman"] = "Schamane",
-		["Warlock"] = "Hexenmeister",
-		["Warrior"] = "Krieger",
-		["Healer"] = "Heiler",
-		["Tank"] = "Tank",
-		["Caster"] = "Zauberer",
-		["Combat"] = "Kampf",
-		["Compilations"] = "Zusammenstellungen",
-		["Data Export"] = "Datenexport",
-		["Development Tools"] = "Entwicklungs Tools",
-		["Guild"] = "Gilde",
-		["Frame Modification"] = "Frame Veränderungen",
-		["Interface Enhancements"] = "Interface Verbesserungen",
-		["Inventory"] = "Inventar",
-		["Library"] = "Bibliotheken",
-		["Map"] = "Karte",
-		["Mail"] = "Post",
-		["Miscellaneous"] = "Diverses",
-		["Quest"] = "Quest",
-		["Raid"] = "Schlachtzug",
-		["Tradeskill"] = "Beruf",
-		["UnitFrame"] = "Einheiten-Fenster",
-	}
-elseif GetLocale() == "frFR" then
-	STANDBY = "|cffff5050(attente)|r"
-
-	TITLE = "Titre"
-	NOTES = "Notes"
-	VERSION = "Version"
-	AUTHOR = "Auteur"
-	DATE = "Date"
-	CATEGORY = "Catégorie"
-	EMAIL = "E-mail"
-	WEBSITE = "Site web"
-	CREDITS = "Credits" -- fix
-	LICENSE = "License" -- fix
-
-	ABOUT = "A propos"
-	PRINT_ADDON_INFO = "Afficher les informations sur l'addon"
-	DONATE = "Donate" -- fix
-	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
-	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-
-	CATEGORIES = {
-		["Action Bars"] = "Barres d'action",
-		["Auction"] = "Hôtel des ventes",
-		["Audio"] = "Audio",
-		["Battlegrounds/PvP"] = "Champs de bataille/JcJ",
-		["Buffs"] = "Buffs",
-		["Chat/Communication"] = "Chat/Communication",
-		["Druid"] = "Druide",
-		["Hunter"] = "Chasseur",
-		["Mage"] = "Mage",
-		["Paladin"] = "Paladin",
-		["Priest"] = "Prêtre",
-		["Rogue"] = "Voleur",
-		["Shaman"] = "Chaman",
-		["Warlock"] = "Démoniste",
-		["Warrior"] = "Guerrier",
-		["Healer"] = "Soigneur",
-		["Tank"] = "Tank",
-		["Caster"] = "Casteur",
-		["Combat"] = "Combat",
-		["Compilations"] = "Compilations",
-		["Data Export"] = "Exportation de données",
-		["Development Tools"] = "Outils de développement",
-		["Guild"] = "Guilde",
-		["Frame Modification"] = "Modification des fenêtres",
-		["Interface Enhancements"] = "Améliorations de l'interface",
-		["Inventory"] = "Inventaire",
-		["Library"] = "Bibliothèques",
-		["Map"] = "Carte",
-		["Mail"] = "Courrier",
-		["Miscellaneous"] = "Divers",
-		["Quest"] = "Quêtes",
-		["Raid"] = "Raid",
-		["Tradeskill"] = "Métiers",
-		["UnitFrame"] = "Fenêtres d'unité",
-	}
-elseif GetLocale() == "koKR" then
-	STANDBY = "|cffff5050(사용가능)|r"
-
-	TITLE = "제목"
-	NOTES = "노트"
-	VERSION = "버전"
-	AUTHOR = "저작자"
-	DATE = "날짜"
-	CATEGORY = "분류"
-	EMAIL = "전자 우편"
-	WEBSITE = "웹 사이트"
-	CREDITS = "공로자"
-	LICENSE = "라이센스"
-
-	ABOUT = "정보"
-	PRINT_ADDON_INFO = "애드온에 대한 정보를 출력합니다."
-	DONATE = "기부"
-	DONATE_DESC = "이 애드온의 저작자에게 기부를 합니다."
-	HOWTO_DONATE_WINDOWS = "Ctrl-A를 눌려 링크를 선택후, Ctrl-C로 복사합니다. Alt-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다."
-	HOWTO_DONATE_MAC = "Cmd-A를 눌려 링크를 선택후, Cmd-C로 복사합니다. Cmd-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다."
-
-	CATEGORIES = {
-		["Action Bars"] = "액션바",
-		["Auction"] = "경매",
-		["Audio"] = "음향",
-		["Battlegrounds/PvP"] = "전장/PvP",
-		["Buffs"] = "버프",
-		["Chat/Communication"] = "대화/의사소통",
-		["Druid"] = "드루이드",
-		["Hunter"] = "사냥꾼",
-		["Mage"] = "마법사",
-		["Paladin"] = "성기사",
-		["Priest"] = "사제",
-		["Rogue"] = "도적",
-		["Shaman"] = "주술사",
-		["Warlock"] = "흑마법사",
-		["Warrior"] = "전사",
-		["Healer"] = "힐러",
-		["Tank"] = "탱커",
-		["Caster"] = "캐스터",
-		["Combat"] = "전투",
-		["Compilations"] = "복합",
-		["Data Export"] = "자료 출력",
-		["Development Tools"] = "개발 도구",
-		["Guild"] = "길드",
-		["Frame Modification"] = "구조 변경",
-		["Interface Enhancements"] = "인터페이스 강화",
-		["Inventory"] = "인벤토리",
-		["Library"] = "라이브러리",
-		["Map"] = "지도",
-		["Mail"] = "우편",
-		["Miscellaneous"] = "기타",
-		["Quest"] = "퀘스트",
-		["Raid"] = "공격대",
-		["Tradeskill"] = "전문기술",
-		["UnitFrame"] = "유닛 프레임",
-	}
-elseif GetLocale() == "zhTW" then
-	STANDBY = "|cffff5050(待命)|r"
-
-	TITLE = "標題"
-	NOTES = "註記"
-	VERSION = "版本"
-	AUTHOR = "作者"
-	DATE = "日期"
-	CATEGORY = "類別"
-	EMAIL = "電子郵件"
-	WEBSITE = "網站"
-	CREDITS = "特別感謝"
-	LICENSE = "版權"
-
-	ABOUT = "關於"
-	PRINT_ADDON_INFO = "顯示插件資訊。"
-	DONATE = "捐贈"
-	DONATE_DESC = "捐贈金錢給插件作者。"
-	HOWTO_DONATE_WINDOWS = "請按Ctrl-A選擇網站連結,Ctrl-C複製網址,Alt-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。"
-	HOWTO_DONATE_MAC = "請按Cmd-A選擇網站連結,Cmd-C複製網址,Cmd-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。"
-
-	CATEGORIES = {
-		["Action Bars"] = "動作條",
-		["Auction"] = "拍賣",
-		["Audio"] = "音效",
-		["Battlegrounds/PvP"] = "戰場/PvP",
-		["Buffs"] = "增益",
-		["Chat/Communication"] = "聊天/通訊",
-		["Druid"] = "德魯伊",
-		["Hunter"] = "獵人",
-		["Mage"] = "法師",
-		["Paladin"] = "聖騎士",
-		["Priest"] = "牧師",
-		["Rogue"] = "盜賊",
-		["Shaman"] = "薩滿",
-		["Warlock"] = "術士",
-		["Warrior"] = "戰士",
-		["Healer"] = "治療者",
-		["Tank"] = "坦克",
-		["Caster"] = "施法者",
-		["Combat"] = "戰鬥",
-		["Compilations"] = "整合",
-		["Data Export"] = "資料匯出",
-		["Development Tools"] = "開發工具",
-		["Guild"] = "公會",
-		["Frame Modification"] = "框架修改",
-		["Interface Enhancements"] = "介面增強",
-		["Inventory"] = "庫存",
-		["Library"] = "程式庫",
-		["Map"] = "地圖",
-		["Mail"] = "郵件",
-		["Miscellaneous"] = "雜項",
-		["Quest"] = "任務",
-		["Raid"] = "團隊",
-		["Tradeskill"] = "交易技能",
-		["UnitFrame"] = "單位框架",
-	}
-elseif GetLocale() == "zhCN" then
-	STANDBY = "|cffff5050(暂挂)|r"
-
-	TITLE = "标题"
-	NOTES = "附注"
-	VERSION = "版本"
-	AUTHOR = "作者"
-	DATE = "日期"
-	CATEGORY = "分类"
-	EMAIL = "电子邮件"
-	WEBSITE = "网站"
-	CREDITS = "Credits" -- fix
-	LICENSE = "License" -- fix
-
-	ABOUT = "关于"
-	PRINT_ADDON_INFO = "印列出插件信息"
-	DONATE = "Donate" -- fix
-	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
-	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-
-	CATEGORIES = {
-		["Action Bars"] = "动作条",
-		["Auction"] = "拍卖",
-		["Audio"] = "音频",
-		["Battlegrounds/PvP"] = "战场/PvP",
-		["Buffs"] = "增益魔法",
-		["Chat/Communication"] = "聊天/交流",
-		["Druid"] = "德鲁伊",
-		["Hunter"] = "猎人",
-		["Mage"] = "法师",
-		["Paladin"] = "圣骑士",
-		["Priest"] = "牧师",
-		["Rogue"] = "盗贼",
-		["Shaman"] = "萨满祭司",
-		["Warlock"] = "术士",
-		["Warrior"] = "战士",
---		["Healer"] = "治疗保障",
---		["Tank"] = "近战控制",
---		["Caster"] = "远程输出",
-		["Combat"] = "战斗",
-		["Compilations"] = "编译",
-		["Data Export"] = "数据导出",
-		["Development Tools"] = "开发工具",
-		["Guild"] = "公会",
-		["Frame Modification"] = "框架修改",
-		["Interface Enhancements"] = "界面增强",
-		["Inventory"] = "背包",
-		["Library"] = "库",
-		["Map"] = "地图",
-		["Mail"] = "邮件",
-		["Miscellaneous"] = "杂项",
-		["Quest"] = "任务",
-		["Raid"] = "团队",
-		["Tradeskill"] = "商业技能",
-		["UnitFrame"] = "头像框架",
-	}
-elseif GetLocale() == "esES" then
-	STANDBY = "|cffff5050(espera)|r"
-
-	TITLE = "Título"
-	NOTES = "Notas"
-	VERSION = "Versión"
-	AUTHOR = "Autor"
-	DATE = "Fecha"
-	CATEGORY = "Categoría"
-	EMAIL = "E-mail"
-	WEBSITE = "Web"
-	CREDITS = "Créditos"
-	LICENSE = "License" -- fix
-
-	ABOUT = "Acerca de"
-	PRINT_ADDON_INFO = "Muestra información acerca del accesorio."
-	DONATE = "Donate" -- fix
-	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
-	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
-
-	CATEGORIES = {
-		["Action Bars"] = "Barras de Acción",
-		["Auction"] = "Subasta",
-		["Audio"] = "Audio",
-		["Battlegrounds/PvP"] = "Campos de Batalla/JcJ",
-		["Buffs"] = "Buffs",
-		["Chat/Communication"] = "Chat/Comunicación",
-		["Druid"] = "Druida",
-		["Hunter"] = "Cazador",
-		["Mage"] = "Mago",
-		["Paladin"] = "Paladín",
-		["Priest"] = "Sacerdote",
-		["Rogue"] = "Pícaro",
-		["Shaman"] = "Chamán",
-		["Warlock"] = "Brujo",
-		["Warrior"] = "Guerrero",
-		["Healer"] = "Sanador",
-		["Tank"] = "Tanque",
-		["Caster"] = "Conjurador",
-		["Combat"] = "Combate",
-		["Compilations"] = "Compilaciones",
-		["Data Export"] = "Exportar Datos",
-		["Development Tools"] = "Herramientas de Desarrollo",
-		["Guild"] = "Hermandad",
-		["Frame Modification"] = "Modificación de Marcos",
-		["Interface Enhancements"] = "Mejoras de la Interfaz",
-		["Inventory"] = "Inventario",
-		["Library"] = "Biblioteca",
-		["Map"] = "Mapa",
-		["Mail"] = "Correo",
-		["Miscellaneous"] = "Misceláneo",
-		["Quest"] = "Misión",
-		["Raid"] = "Banda",
-		["Tradeskill"] = "Habilidad de Comercio",
-		["UnitFrame"] = "Marco de Unidades",
-	}
-else -- enUS
-	STANDBY = "|cffff5050(standby)|r"
-
-	TITLE = "Title"
-	NOTES = "Notes"
-	VERSION = "Version"
-	AUTHOR = "Author"
-	DATE = "Date"
-	CATEGORY = "Category"
-	EMAIL = "E-mail"
-	WEBSITE = "Website"
-	CREDITS = "Credits"
-	LICENSE = "License"
-
-	ABOUT = "About"
-	PRINT_ADDON_INFO = "Show information about the addon."
-	DONATE = "Donate"
-	DONATE_DESC = "Give a much-needed donation to the author of this addon."
-	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."
-	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."
-
-	CATEGORIES = {
-		["Action Bars"] = "Action Bars",
-		["Auction"] = "Auction",
-		["Audio"] = "Audio",
-		["Battlegrounds/PvP"] = "Battlegrounds/PvP",
-		["Buffs"] = "Buffs",
-		["Chat/Communication"] = "Chat/Communication",
-		["Druid"] = "Druid",
-		["Hunter"] = "Hunter",
-		["Mage"] = "Mage",
-		["Paladin"] = "Paladin",
-		["Priest"] = "Priest",
-		["Rogue"] = "Rogue",
-		["Shaman"] = "Shaman",
-		["Warlock"] = "Warlock",
-		["Warrior"] = "Warrior",
-		["Healer"] = "Healer",
-		["Tank"] = "Tank",
-		["Caster"] = "Caster",
-		["Combat"] = "Combat",
-		["Compilations"] = "Compilations",
-		["Data Export"] = "Data Export",
-		["Development Tools"] = "Development Tools",
-		["Guild"] = "Guild",
-		["Frame Modification"] = "Frame Modification",
-		["Interface Enhancements"] = "Interface Enhancements",
-		["Inventory"] = "Inventory",
-		["Library"] = "Library",
-		["Map"] = "Map",
-		["Mail"] = "Mail",
-		["Miscellaneous"] = "Miscellaneous",
-		["Quest"] = "Quest",
-		["Raid"] = "Raid",
-		["Tradeskill"] = "Tradeskill",
-		["UnitFrame"] = "UnitFrame",
-	}
-end
-
-setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive
-	local lowerKey = key:lower()
-	for k,v in pairs(CATEGORIES) do
-		if k:lower() == lowerKey then
-			return v
-		end
-	end
-end })
-
--- Create the library object
-
-local AceOO = AceLibrary("AceOO-2.0")
-local AceAddon = AceOO.Class()
-local AceEvent
-local AceConsole
-local AceModuleCore
-
-function AceAddon:GetLocalizedCategory(name)
-	self:argCheck(name, 2, "string")
-	return CATEGORIES[name] or UNKNOWN
-end
-
-function AceAddon:ToString()
-	return "AceAddon"
-end
-
-local function print(text)
-	DEFAULT_CHAT_FRAME:AddMessage(text)
-end
-
-function AceAddon:ADDON_LOADED(name)
-	local unregister = true
-	local initAddon = {}
-	while #self.nextAddon > 0 do
-		local addon = table.remove(self.nextAddon, 1)
-		if addon.possibleNames[name] then
-			table.insert(initAddon, addon)
-		else
-			unregister = nil
-			table.insert(self.skipAddon, addon)
-		end
-	end
-	self.nextAddon, self.skipAddon = self.skipAddon, self.nextAddon
-	if unregister then
-		AceAddon:UnregisterEvent("ADDON_LOADED")
-	end
-	while #initAddon > 0 do
-		local addon = table.remove(initAddon, 1)
-		table.insert(self.addons, addon)
-		if not self.addons[name] then
-			self.addons[name] = addon
-		end
-		addon.possibleNames = nil
-		self:InitializeAddon(addon, name)
-	end
-end
-
-local function RegisterOnEnable(self)
-	if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK
-		AceAddon.playerLoginFired = true
-	end
-	if AceAddon.playerLoginFired then
-		AceAddon.addonsStarted[self] = true
-		if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then
-			AceAddon:ManualEnable(self)
-		end
-	else
-		if not AceAddon.addonsToOnEnable then
-			AceAddon.addonsToOnEnable = {}
-		end
-		table.insert(AceAddon.addonsToOnEnable, self)
-	end
-end
-
-function AceAddon:InitializeAddon(addon, name)
-	if addon.name == nil then
-		addon.name = name
-	end
-	if GetAddOnMetadata then
-		-- TOC checks
-		if addon.title == nil then
-			addon.title = GetAddOnMetadata(name, "Title")
-		end
-		if type(addon.title) == "string" then
-			local num = addon.title:find(" |cff7fff7f %-Ace2%-|r$")
-			if num then
-				addon.title = addon.title:sub(1, num - 1)
-			end
-			addon.title = addon.title:trim()
-		end
-		if addon.notes == nil then
-			addon.notes = GetAddOnMetadata(name, "Notes")
-		end
-		if type(addon.notes) == "string" then
-			addon.notes = addon.notes:trim()
-		end
-		if addon.version == nil then
-			addon.version = GetAddOnMetadata(name, "Version")
-		end
-		if type(addon.version) == "string" then
-			if addon.version:find("%$Revision: (%d+) %$") then
-				addon.version = addon.version:gsub("%$Revision: (%d+) %$", "%1")
-			elseif addon.version:find("%$Rev: (%d+) %$") then
-				addon.version = addon.version:gsub("%$Rev: (%d+) %$", "%1")
-			elseif addon.version:find("%$LastChangedRevision: (%d+) %$") then
-				addon.version = addon.version:gsub("%$LastChangedRevision: (%d+) %$", "%1")
-			end
-			addon.version = addon.version:trim()
-		end
-		if addon.author == nil then
-			addon.author = GetAddOnMetadata(name, "Author")
-		end
-		if type(addon.author) == "string" then
-			addon.author = addon.author:trim()
-		end
-		if addon.credits == nil then
-			addon.credits = GetAddOnMetadata(name, "X-Credits")
-		end
-		if type(addon.credits) == "string" then
-			addon.credits = addon.credits:trim()
-		end
-		if addon.donate == nil then
-			addon.donate = GetAddOnMetadata(name, "X-Donate")
-		end
-		if type(addon.donate) == "string" then
-			addon.donate = addon.donate:trim()
-		end
-		if addon.date == nil then
-			addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate")
-		end
-		if type(addon.date) == "string" then
-			if addon.date:find("%$Date: (.-) %$") then
-				addon.date = addon.date:gsub("%$Date: (.-) %$", "%1")
-			elseif addon.date:find("%$LastChangedDate: (.-) %$") then
-				addon.date = addon.date:gsub("%$LastChangedDate: (.-) %$", "%1")
-			end
-			addon.date = addon.date:trim()
-		end
-
-		if addon.category == nil then
-			addon.category = GetAddOnMetadata(name, "X-Category")
-		end
-		if type(addon.category) == "string" then
-			addon.category = addon.category:trim()
-		end
-		if addon.email == nil then
-			addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email")
-		end
-		if type(addon.email) == "string" then
-			addon.email = addon.email:trim()
-		end
-		if addon.license == nil then
-			addon.license = GetAddOnMetadata(name, "X-License")
-		end
-		if type(addon.license) == "string" then
-			addon.license = addon.license:trim()
-		end
-		if addon.website == nil then
-			addon.website = GetAddOnMetadata(name, "X-Website")
-		end
-		if type(addon.website) == "string" then
-			addon.website = addon.website:trim()
-		end
-	end
-	local current = addon.class
-	while true do
-		if current == AceOO.Class or not current then
-			break
-		end
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedInitialize) == "function" then
-					mixin:OnEmbedInitialize(addon, name)
-				end
-			end
-		end
-		current = current.super
-	end
-	local n = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0
-
-	if type(addon.OnInitialize) == "function" then
-		safecall(addon.OnInitialize, addon, name)
-	end
-	if AceEvent then
-		AceEvent:TriggerEvent("Ace2_AddonInitialized", addon)
-	end
-	RegisterOnEnable(addon)
-	local n2 = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0
-	if n2 - n > 1 then
-		local mine = table.remove(AceAddon.addonsToOnEnable)
-		table.insert(AceAddon.addonsToOnEnable, n+1, mine)
-	end
-end
-
-local aboutFrame
-local function createAboutFrame()
-	aboutFrame = CreateFrame("Frame", "AceAddon20AboutFrame", UIParent, "DialogBoxFrame")
-	aboutFrame:SetWidth(500)
-	aboutFrame:SetHeight(400)
-	aboutFrame:SetPoint("CENTER")
-	aboutFrame:SetBackdrop({
-		bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
-	    edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
-	    tile = true, tileSize = 16, edgeSize = 16,
-	    insets = { left = 5, right = 5, top = 5, bottom = 5 }
-	})
-	aboutFrame:SetBackdropColor(0,0,0,1)
-
-	local donateButton = CreateFrame("Button", "AceAddon20AboutFrameDonateButton", aboutFrame, "UIPanelButtonTemplate2")
-	aboutFrame.donateButton = donateButton
-	donateButton:SetPoint("BOTTOMRIGHT", -20, 20)
-	_G.AceAddon20AboutFrameDonateButtonText:SetText(DONATE)
-	donateButton:SetWidth(_G.AceAddon20AboutFrameDonateButtonText:GetWidth()+20)
-	donateButton:SetScript("OnClick", function()
-		aboutFrame.currentAddon:OpenDonationFrame()
-	end)
-
-	local text = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
-	aboutFrame.title = text
-	text:SetPoint("TOP", 0, -5)
-
-	aboutFrame:Hide()
-
-	aboutFrame.lefts = {}
-	aboutFrame.rights = {}
-	aboutFrame.textLefts = {}
-	aboutFrame.textRights = {}
-	function aboutFrame:Clear()
-		self.title:SetText("")
-		for i = 1, #self.lefts do
-			self.lefts[i] = nil
-			self.rights[i] = nil
-		end
-	end
-
-	function aboutFrame:AddLine(left, right)
-		aboutFrame.lefts[#aboutFrame.lefts+1] = left
-		aboutFrame.rights[#aboutFrame.rights+1] = right
-	end
-
-	local aboutFrame_Show = aboutFrame.Show
-	function aboutFrame:Show(...)
-		local maxLeftWidth = 0
-		local maxRightWidth = 0
-		local textHeight = 0
-		for i = 1, #self.lefts do
-			if not self.textLefts[i] then
-				local left = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
-				self.textLefts[i] = left
-				local right = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
-				self.textRights[i] = right
-				if i == 1 then
-					left:SetPoint("TOPRIGHT", aboutFrame, "TOPLEFT", 75, -35)
-				else
-					left:SetPoint("TOPRIGHT", self.textLefts[i-1], "BOTTOMRIGHT", 0, -5)
-				end
-				right:SetPoint("LEFT", left, "RIGHT", 5, 0)
-			end
-			self.textLefts[i]:SetText(self.lefts[i] .. ":")
-			self.textRights[i]:SetText(self.rights[i])
-			local leftWidth = self.textLefts[i]:GetWidth()
-			local rightWidth = self.textRights[i]:GetWidth()
-			textHeight = self.textLefts[i]:GetHeight()
-			if maxLeftWidth < leftWidth then
-				maxLeftWidth = leftWidth
-			end
-			if maxRightWidth < rightWidth then
-				maxRightWidth = rightWidth
-			end
-		end
-		for i = #self.lefts+1, #self.textLefts do
-			self.textLefts[i]:SetText('')
-			self.textRights[i]:SetText('')
-		end
-		aboutFrame:SetWidth(75 + maxRightWidth + 20)
-		aboutFrame:SetHeight(#self.lefts * (textHeight + 5) + 100)
-
-		aboutFrame_Show(self, ...)
-	end
-	aboutFrame:Hide()
-
-	createAboutFrame = nil
-end
-local donateFrame
-
-local function unobfuscateEmail(email)
-	return email:gsub(" AT ", "@"):gsub(" DOT ", ".")
-end
-
-local function isGoodVariable(var)
-	return type(var) == "string" or type(var) == "number"
-end
-function AceAddon.prototype:PrintAddonInfo()
-	if createAboutFrame then
-		createAboutFrame()
-	end
-	aboutFrame:Clear()
-	local x
-	if isGoodVariable(self.title) then
-		x = tostring(self.title)
-	elseif isGoodVariable(self.name) then
-		x = tostring(self.name)
-	else
-		x = "<" .. tostring(self.class) .. " instance>"
-	end
-	if type(self.IsActive) == "function" then
-		if not self:IsActive() then
-			x = x .. " " .. STANDBY
-		end
-	end
-	aboutFrame.title:SetText(x)
-
-	if isGoodVariable(self.version) then
-		aboutFrame:AddLine(VERSION, tostring(self.version))
-	end
-	if isGoodVariable(self.notes) then
-		aboutFrame:AddLine(NOTES, tostring(self.notes))
-	end
-	if isGoodVariable(self.author) then
-		aboutFrame:AddLine(AUTHOR, tostring(self.author))
-	end
-	if isGoodVariable(self.credits) then
-		aboutFrame:AddLine(CREDITS, tostring(self.credits))
-	end
-	if isGoodVariable(self.date) then
-		aboutFrame:AddLine(DATE, tostring(self.date))
-	end
-	if self.category then
-		local category = CATEGORIES[self.category]
-		if category then
-			aboutFrame:AddLine(CATEGORY, tostring(self.category))
-		end
-	end
-	if isGoodVariable(self.email) then
-		aboutFrame:AddLine(EMAIL, unobfuscateEmail(tostring(self.email)))
-	end
-	if isGoodVariable(self.website) then
-		aboutFrame:AddLine(WEBSITE, tostring(self.website))
-	end
-	if isGoodVariable(self.license) then
-		aboutFrame:AddLine(LICENSE, tostring(self.license))
-	end
-
-	if donateFrame and donateFrame:IsShown() then
-		donateFrame:Hide()
-	end
-
-	aboutFrame.currentAddon = self
-
-	aboutFrame:Show()
-
-	if self.donate then
-		aboutFrame.donateButton:Show()
-	else
-		aboutFrame.donateButton:Hide()
-	end
-end
-
-local function createDonateFrame()
-	donateFrame = CreateFrame("Frame", "AceAddon20Frame", UIParent, "DialogBoxFrame")
-
-	donateFrame:SetWidth(500)
-	donateFrame:SetHeight(200)
-	donateFrame:SetPoint("CENTER")
-	donateFrame:SetBackdrop({
-		bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
-		edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
-		tile = true, tileSize = 16, edgeSize = 16,
-		insets = { left = 5, right = 5, top = 5, bottom = 5 }
-	})
-	donateFrame:SetBackdropColor(0,0,0,1)
-
-	local text = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
-	text:SetPoint("TOP", 0, -5)
-	text:SetText(DONATE)
-
-	local howto = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
-	howto:SetPoint("TOP", text, "BOTTOM", 0, -5)
-	howto:SetPoint("LEFT", 16, 0)
-	howto:SetPoint("RIGHT", -16, 0)
-	if not IsMacClient() then
-		-- Windows or Linux
-		howto:SetText(HOWTO_DONATE_WINDOWS)
-	else
-		howto:SetText(HOWTO_DONATE_MAC)
-	end
-
-	local scrollFrame = CreateFrame("ScrollFrame", "AceAddon20FrameScrollFrame", donateFrame, "UIPanelScrollFrameTemplate")
-	scrollFrame:SetToplevel(true)
-	scrollFrame:SetPoint("TOP", -10, -76)
-	scrollFrame:SetWidth(455)
-	scrollFrame:SetHeight(70)
-	howto:SetPoint("BOTTOM", scrollFrame, "TOP")
-
-	local editBox = CreateFrame("EditBox", nil, scrollFrame)
-	donateFrame.editBox = editBox
-	scrollFrame:SetScrollChild(editBox)
-	editBox:SetFontObject(ChatFontNormal)
-	editBox:SetMultiLine(true)
-	editBox:SetMaxLetters(99999)
-	editBox:SetWidth(450)
-	editBox:SetHeight(54)
-	editBox:SetPoint("BOTTOM", 5, 0)
-	editBox:SetJustifyH("LEFT")
-	editBox:SetJustifyV("TOP")
-	editBox:SetAutoFocus(false)
-	editBox:SetScript("OnTextChanged", function(this)
-		if this:GetText() ~= this.text then
-			this:SetText(this.text)
-		end
-	end)
-	editBox:SetScript("OnEscapePressed", function(this)
-		this:ClearFocus()
-	end)
-	createDonateFrame = nil
-end
-
-local function fix(char)
-	return ("%%%02x"):format(char:byte())
-end
-
-local function urlencode(text)
-	return text:gsub("[^0-9A-Za-z]", fix)
-end
-
-function AceAddon.prototype:OpenDonationFrame()
-	if createDonateFrame then
-		createDonateFrame()
-	end
-	local donate = self.donate
-	if type(donate) ~= "string" then
-		donate = "Wowace"
-	end
-	local style, data = (":"):split(donate, 2)
-	style = style:lower()
-	if style ~= "website" and style ~= "paypal" then
-		style = "wowace"
-	end
-	if style == "wowace" then
-		donateFrame.editBox.text = "http://www.wowace.com/wiki/Donations"
-	elseif style == "website" then
-		donateFrame.editBox.text = data
-	else -- PayPal
-		local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data))
-		local name
-		if type(self.title) == "string" then
-			name = self.title
-		elseif type(self.name) == "string" then
-			name = self.name
-		end
-		if name then
-			name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
-			text = text .. "&item_name=" .. urlencode(name)
-		end
-		donateFrame.editBox.text = text
-	end
-	donateFrame.editBox:SetText(donateFrame.editBox.text)
-
-	if aboutFrame and aboutFrame:IsShown() then
-		aboutFrame:Hide()
-	end
-
-	donateFrame:Show()
-
-	donateFrame.editBox:SetFocus()
-end
-
-local options
-function AceAddon:GetAceOptionsDataTable(target)
-	return {
-		about = {
-			name = ABOUT,
-			desc = PRINT_ADDON_INFO,
-			type = "execute",
-			func = "PrintAddonInfo",
-			order = -1,
-		},
-		donate = {
-			name = DONATE,
-			desc = DONATE_DESC,
-			type = "execute",
-			func = "OpenDonationFrame",
-			order = -1,
-			hidden = function()
-				return not target.donate
-			end
-		}
-	}
-end
-
-function AceAddon:PLAYER_LOGIN()
-	self.playerLoginFired = true
-	if self.addonsToOnEnable then
-		while #self.addonsToOnEnable > 0 do
-			local addon = table.remove(self.addonsToOnEnable, 1)
-			self.addonsStarted[addon] = true
-			if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then
-				AceAddon:ManualEnable(addon)
-			end
-		end
-		self.addonsToOnEnable = nil
-	end
-end
-
-function AceAddon.prototype:Inject(t)
-	AceAddon:argCheck(t, 2, "table")
-	for k,v in pairs(t) do
-		self[k] = v
-	end
-end
-
-function AceAddon.prototype:init()
-	if not AceEvent then
-		error(MAJOR_VERSION .. " requires AceEvent-2.0", 4)
-	end
-	AceAddon.super.prototype.init(self)
-
-	self.super = self.class.prototype
-
-	AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED")
-	local names = {}
-	for i = 1, GetNumAddOns() do
-		if IsAddOnLoaded(i) then names[GetAddOnInfo(i)] = true end
-	end
-	self.possibleNames = names
-	table.insert(AceAddon.nextAddon, self)
-end
-
-function AceAddon.prototype:ToString()
-	local x
-	if type(self.title) == "string" then
-		x = self.title
-	elseif type(self.name) == "string" then
-		x = self.name
-	else
-		x = "<" .. tostring(self.class) .. " instance>"
-	end
-	if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then
-		x = x .. " " .. STANDBY
-	end
-	return x
-end
-
-AceAddon.new = function(self, ...)
-	local class = AceAddon:pcall(AceOO.Classpool, self, ...)
-	return class:new()
-end
-
-function AceAddon:ManualEnable(addon)
-	AceAddon:argCheck(addon, 2, "table")
-	local first = nil
-	if AceOO.inherits(addon, "AceAddon-2.0") then
-		if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[addon] then
-			first = true
-			AceAddon.addonsEnabled[addon] = true
-		end
-	end
-	local current = addon.class
-	while current and current ~= AceOO.Class do
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedEnable) == "function" then
-					safecall(mixin.OnEmbedEnable, mixin, addon, first)
-				end
-			end
-		end
-		current = current.super
-	end
-	if type(addon.OnEnable) == "function" then
-		safecall(addon.OnEnable, addon, first)
-	end
-	if AceEvent then
-		AceEvent:TriggerEvent("Ace2_AddonEnabled", addon, first)
-	end
-end
-
-function AceAddon:ManualDisable(addon)
-	AceAddon:argCheck(addon, 2, "table")
-	local current = addon.class
-	while current and current ~= AceOO.Class do
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedDisable) == "function" then
-					safecall(mixin.OnEmbedDisable, mixin, addon)
-				end
-			end
-		end
-		current = current.super
-	end
-	if type(module.OnDisable) == "function" then
-		safecall(module.OnDisable, addon)
-	end
-	if AceEvent then
-		AceEvent:TriggerEvent("Ace2_AddonDisabled", addon)
-	end
-end
-
-local function external(self, major, instance)
-	if major == "AceEvent-2.0" then
-		AceEvent = instance
-
-		AceEvent:embed(self)
-
-		self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true)
-	elseif major == "AceConsole-2.0" then
-		AceConsole = instance
-
-		local slashCommands = { "/ace2" }
-		local _,_,_,enabled,loadable = GetAddOnInfo("Ace")
-		if not enabled or not loadable then
-			table.insert(slashCommands, "/ace")
-		end
-		local function listAddon(addon, depth)
-			if not depth then
-				depth = 0
-			end
-
-			local s = ("  "):rep(depth) .. " - " .. tostring(addon)
-			if rawget(addon, 'version') then
-				s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r"
-			end
-			if rawget(addon, 'slashCommand') then
-				s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r"
-			end
-			print(s)
-			if type(rawget(addon, 'modules')) == "table" then
-				local i = 0
-				for k,v in pairs(addon.modules) do
-					i = i + 1
-					if i == 6 then
-						print(("  "):rep(depth + 1) .. " - more...")
-						break
-					else
-						listAddon(v, depth + 1)
-					end
-				end
-			end
-		end
-		local function listNormalAddon(i)
-			local name,_,_,enabled,loadable = GetAddOnInfo(i)
-			if not loadable then
-				enabled = false
-			end
-			if self.addons[name] then
-				listAddon(self.addons[name])
-			else
-				local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name)
-				local version = GetAddOnMetadata(i, "Version")
-				if version then
-					if version:find("%$Revision: (%d+) %$") then
-						version = version:gsub("%$Revision: (%d+) %$", "%1")
-					elseif version:find("%$Rev: (%d+) %$") then
-						version = version:gsub("%$Rev: (%d+) %$", "%1")
-					elseif version:find("%$LastChangedRevision: (%d+) %$") then
-						version = version:gsub("%$LastChangedRevision: (%d+) %$", "%1")
-					end
-					s = s .. " - |cffffff7f" .. version .. "|r"
-				end
-				if not enabled then
-					s = s .. " |cffff0000(disabled)|r"
-				end
-				if IsAddOnLoadOnDemand(i) then
-					s = s .. " |cff00ff00[LoD]|r"
-				end
-				print(s)
-			end
-		end
-		local function mySort(alpha, bravo)
-			return tostring(alpha) < tostring(bravo)
-		end
-		AceConsole.RegisterChatCommand(self, slashCommands, {
-			desc = "AddOn development framework",
-			name = "Ace2",
-			type = "group",
-			args = {
-				about = {
-					desc = "Get information about Ace2",
-					name = "About",
-					type = "execute",
-					func = function()
-						print("|cffffff7fAce2|r - |cffffff7f2.0." .. MINOR_VERSION:gsub("%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework")
-						print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team")
-						print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/")
-					end
-				},
-				list = {
-					desc = "List addons",
-					name = "List",
-					type = "group",
-					args = {
-						ace2 = {
-							desc = "List addons using Ace2",
-							name = "Ace2",
-							type = "execute",
-							func = function()
-								print("|cffffff7fAddon list:|r")
-								table.sort(self.addons, mySort)
-								for _,v in ipairs(self.addons) do
-									listAddon(v)
-								end
-							end
-						},
-						all = {
-							desc = "List all addons",
-							name = "All",
-							type = "execute",
-							func = function()
-								print("|cffffff7fAddon list:|r")
-								local count = GetNumAddOns()
-								for i = 1, count do
-									listNormalAddon(i)
-								end
-							end
-						},
-						enabled = {
-							desc = "List all enabled addons",
-							name = "Enabled",
-							type = "execute",
-							func = function()
-								print("|cffffff7fAddon list:|r")
-								local count = GetNumAddOns()
-								for i = 1, count do
-									local _,_,_,enabled,loadable = GetAddOnInfo(i)
-									if enabled and loadable then
-										listNormalAddon(i)
-									end
-								end
-							end
-						},
-						disabled = {
-							desc = "List all disabled addons",
-							name = "Disabled",
-							type = "execute",
-							func = function()
-								print("|cffffff7fAddon list:|r")
-								local count = GetNumAddOns()
-								for i = 1, count do
-									local _,_,_,enabled,loadable = GetAddOnInfo(i)
-									if not enabled or not loadable then
-										listNormalAddon(i)
-									end
-								end
-							end
-						},
-						lod = {
-							desc = "List all LoadOnDemand addons",
-							name = "LoadOnDemand",
-							type = "execute",
-							func = function()
-								print("|cffffff7fAddon list:|r")
-								local count = GetNumAddOns()
-								for i = 1, count do
-									if IsAddOnLoadOnDemand(i) then
-										listNormalAddon(i)
-									end
-								end
-							end
-						},
-						ace1 = {
-							desc = "List all addons using Ace1",
-							name = "Ace 1.x",
-							type = "execute",
-							func = function()
-								print("|cffffff7fAddon list:|r")
-								local count = GetNumAddOns()
-								for i = 1, count do
-									local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
-									if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
-										listNormalAddon(i)
-									end
-								end
-							end
-						},
-						libs = {
-							desc = "List all libraries using AceLibrary",
-							name = "Libraries",
-							type = "execute",
-							func = function()
-								if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
-									print("|cffffff7fLibrary list:|r")
-									for name, data in pairs(AceLibrary.libs) do
-										local s
-										if data.minor then
-											s = " - " .. tostring(name) .. "." .. tostring(data.minor)
-										else
-											s = " - " .. tostring(name)
-										end
-										if rawget(AceLibrary(name), 'slashCommand') then
-											s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)"
-										end
-										print(s)
-									end
-								end
-							end
-						},
-						search = {
-							desc = "Search by name",
-							name = "Search",
-							type = "text",
-							usage = "<keyword>",
-							input = true,
-							get = false,
-							set = function(...)
-								local arg = { ... }
-								for i,v in ipairs(arg) do
-									arg[i] = v:gsub('%*', '.*'):gsub('%%', '%%%%'):lower()
-								end
-								local count = GetNumAddOns()
-								for i = 1, count do
-									local name = GetAddOnInfo(i)
-									local good = true
-									for _,v in ipairs(arg) do
-										if not name:lower():find(v) then
-											good = false
-											break
-										end
-									end
-									if good then
-										listNormalAddon(i)
-									end
-								end
-							end
-						}
-					},
-				},
-				enable = {
-					desc = "Enable addon(s).",
-					name = "Enable",
-					type = "text",
-					usage = "<addon 1> <addon 2> ...",
-					get = false,
-					input = true,
-					set = function(...)
-						for i = 1, select("#", ...) do
-							local addon = select(i, ...)
-							local name, title, _, enabled, _, reason = GetAddOnInfo(addon)
-							if reason == "MISSING" then
-								print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon))
-							elseif not enabled then
-								EnableAddOn(addon)
-								print(("|cffffff7fAce2:|r %s is now enabled."):format(addon or name))
-							else
-								print(("|cffffff7fAce2:|r %s is already enabled."):format(addon or name))
-							end
-						end
-					end,
-				},
-				disable = {
-					desc = "Disable addon(s).",
-					name = "Disable",
-					type = "text",
-					usage = "<addon 1> <addon 2> ...",
-					get = false,
-					input = true,
-					set = function(...)
-						for i = 1, select("#", ...) do
-							local addon = select(i, ...)
-							local name, title, _, enabled, _, reason = GetAddOnInfo(addon)
-							if reason == "MISSING" then
-							print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon))
-							elseif enabled then
-								DisableAddOn(addon)
-								print(("|cffffff7fAce2:|r %s is now disabled."):format(addon or name))
-							else
-								print(("|cffffff7fAce2:|r %s is already disabled."):format(addon or name))
-							end
-						end
-					end,
-				},
-				load = {
-					desc = "Load addon(s).",
-					name = "Load",
-					type = "text",
-					usage = "<addon 1> <addon 2> ...",
-					get = false,
-					input = true,
-					set = function(...)
-						for i = 1, select("#", ...) do
-							local addon = select(i, ...)
-							local name, title, _, _, loadable, reason = GetAddOnInfo(addon)
-							if reason == "MISSING" then
-								print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon))
-							elseif not loadable then
-								print(("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s."):format(addon, reason))
-							else
-								LoadAddOn(addon)
-								print(("|cffffff7fAce2:|r %s is now loaded."):format(addon or name))
-							end
-						end
-					end
-				},
-				info = {
-					desc = "Display information",
-					name = "Information",
-					type = "execute",
-					func = function()
-						local mem, threshold = gcinfo()
-						print((" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r"):format(mem / 1024))
-						if threshold then
-							print((" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r"):format(threshold / 1024))
-						end
-						print((" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r"):format(GetFramerate()))
-						local bandwidthIn, bandwidthOut, latency = GetNetStats()
-						bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024)
-						print((" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r"):format(latency))
-						print((" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r"):format(bandwidthIn))
-						print((" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r"):format(bandwidthOut))
-						print((" - |cffffff7fTotal addons [|r%d|cffffff7f]|r"):format(GetNumAddOns()))
-						print((" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r"):format(#self.addons))
-						local ace = 0
-						local enabled = 0
-						local disabled = 0
-						local lod = 0
-						for i = 1, GetNumAddOns() do
-							local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
-							if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
-								ace = ace + 1
-							end
-							if IsAddOnLoadOnDemand(i) then
-								lod = lod + 1
-							end
-							local isActive, loadable = select(4, GetAddOnInfo(i))
-							if not isActive or not loadable then
-								disabled = disabled + 1
-							else
-								enabled = enabled + 1
-							end
-						end
-						print((" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r"):format(ace))
-						print((" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r"):format(lod))
-						print((" - |cffffff7fenabled addons [|r%d|cffffff7f]|r"):format(enabled))
-						print((" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r"):format(disabled))
-						local libs = 0
-						if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
-							for _ in pairs(AceLibrary.libs) do
-								libs = libs + 1
-							end
-						end
-						print((" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r"):format(libs))
-					end
-				}
-			}
-		})
-	elseif major == "AceModuleCore-2.0" then
-		AceModuleCore = instance
-	end
-end
-
-local function activate(self, oldLib, oldDeactivate)
-	AceAddon = self
-
-	self.playerLoginFired = oldLib and oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage
-	self.addonsToOnEnable = oldLib and oldLib.addonsToOnEnable
-	self.addons = oldLib and oldLib.addons or {}
-	self.nextAddon = oldLib and oldLib.nextAddon or {}
-	self.skipAddon = oldLib and oldLib.skipAddon or {}
-	self.addonsStarted = oldLib and oldLib.addonsStarted or {}
-	self.addonsEnabled = oldLib and oldLib.addonsEnabled or {}
-
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/lib/AceAddon-2.0/AceAddon-2.0.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceAddon-2.0
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary, AceOO-2.0
- 
-AceAddon-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceAddon-3.0/AceAddon-3.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,412 @@
+--[[ $Id: AceAddon-3.0.lua 63220 2008-02-29 11:29:58Z nevcairiel $ ]]
+local MAJOR, MINOR = "AceAddon-3.0", 3
+local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceAddon then return end -- No Upgrade needed.
+
+AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
+AceAddon.addons = AceAddon.addons or {} -- addons in general
+AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
+AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
+AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
+AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
+
+local tinsert, tconcat = table.insert, table.concat
+local fmt = string.format
+local pairs, next, type = pairs, next, type
+
+--[[
+	 xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+	return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+	local code = [[
+		local xpcall, eh = ...
+		local method, ARGS
+		local function call() return method(ARGS) end
+	
+		local function dispatch(func, ...)
+			 method = func
+			 if not method then return end
+			 ARGS = ...
+			 return xpcall(call, eh)
+		end
+	
+		return dispatch
+	]]
+	
+	local ARGS = {}
+	for i = 1, argCount do ARGS[i] = "arg"..i end
+	code = code:gsub("ARGS", tconcat(ARGS, ", "))
+	return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+	local dispatcher = CreateDispatcher(argCount)
+	rawset(self, argCount, dispatcher)
+	return dispatcher
+end})
+Dispatchers[0] = function(func)
+	return xpcall(func, errorhandler)
+end
+
+local function safecall(func, ...)
+	-- we check to see if the func is passed is actually a function here and don't error when it isn't
+	-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
+	-- present execution should continue without hinderance
+	if type(func) == "function" then
+		return Dispatchers[select('#', ...)](func, ...)
+	end
+end
+
+-- local functions that will be implemented further down
+local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
+
+-- used in the addon metatable
+local function addontostring( self ) return self.name end 
+
+-- AceAddon:NewAddon( name, [lib, lib, lib, ...] )
+-- name (string) - unique addon object name
+-- [lib] (string) - optional libs to embed in the addon object
+--
+-- returns the addon object when succesful
+function AceAddon:NewAddon(name, ...)
+	if type(name) ~= "string" then error(("Usage: NewAddon(name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
+	
+	if self.addons[name] then error(("Usage: NewAddon(name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2) end
+	
+	local addon = setmetatable( {name = name}, { __tostring = addontostring } )
+	self.addons[name] = addon
+	addon.modules = {}
+	addon.defaultModuleLibraries = {}
+	Embed( addon ) -- embed NewModule, GetModule methods
+	self:EmbedLibraries(addon, ...)
+	
+	-- add to queue of addons to be initialized upon ADDON_LOADED
+	tinsert(self.initializequeue, addon)
+	return addon
+end
+
+-- AceAddon:GetAddon( name, [silent])
+-- name (string) - unique addon object name
+-- silent (boolean) - if true, addon is optional, silently return nil if its not found
+--
+-- throws an error if the addon object can not be found (except silent is set)
+-- returns the addon object if found
+function AceAddon:GetAddon(name, silent)
+	if not silent and not self.addons[name] then
+		error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
+	end
+	return self.addons[name]
+end
+
+-- AceAddon:EmbedLibraries( addon, [lib, lib, lib, ...] )
+-- addon (object) - addon to embed the libs in
+-- [lib] (string) - optional libs to embed
+function AceAddon:EmbedLibraries(addon, ...)
+	for i=1,select("#", ... ) do
+		local libname = select(i, ...)
+		self:EmbedLibrary(addon, libname, false, 4)
+	end
+end
+
+-- AceAddon:EmbedLibrary( addon, libname, silent, offset )
+-- addon (object) - addon to embed the libs in
+-- libname (string) - lib to embed
+-- [silent] (boolean) - optional, marks an embed to fail silently if the library doesn't exist.
+-- [offset] (number) - will push the error messages back to said offset defaults to 2
+function AceAddon:EmbedLibrary(addon, libname, silent, offset)
+	local lib = LibStub:GetLibrary(libname, true)
+	if not lib and not silent then
+		error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
+	elseif lib and type(lib.Embed) == "function" then
+		lib:Embed(addon)
+		tinsert(self.embeds[addon], libname)
+		return true
+	elseif lib then
+		error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
+	end
+end
+
+-- addon:GetModule( name, [silent])
+-- name (string) - unique module object name
+-- silent (boolean) - if true, module is optional, silently return nil if its not found
+--
+-- throws an error if the addon object can not be found (except silent is set)
+-- returns the module object if found
+function GetModule(self, name, silent)
+	if not self.modules[name] and not silent then
+		error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
+	end
+	return self.modules[name]
+end
+
+local function IsModuleTrue(self) return true end
+
+-- addon:NewModule( name, [prototype, [lib, lib, lib, ...] )
+-- name (string) - unique module object name for this addon
+-- prototype (object) - object to derive this module from, methods and values from this table will be mixed into the module, if a string is passed a lib is assumed
+-- [lib] (string) - optional libs to embed in the addon object
+--
+-- returns the addon object when succesful
+function NewModule(self, name, prototype, ...)
+	if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
+	if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
+	
+	if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
+	
+	-- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
+	-- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
+	local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
+	
+	module.IsModule = IsModuleTrue
+	module:SetEnabledState(self.defaultModuleState)
+	module.moduleName = name
+
+	if type(prototype) == "string" then
+		AceAddon:EmbedLibraries(module, prototype, ...)
+	else
+		AceAddon:EmbedLibraries(module, ...)
+	end
+	AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
+
+	if not prototype or type(prototype) == "string" then
+		prototype = self.defaultModulePrototype or nil
+	end
+	
+	if type(prototype) == "table" then
+		local mt = getmetatable(module)
+		mt.__index = prototype
+		setmetatable(module, mt)  -- More of a Base class type feel.
+	end
+	
+	safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
+	self.modules[name] = module
+	
+	return module
+end
+
+--addon:GetName()
+-- Returns the real name of the addon or module, without any prefix
+function GetName(self)
+	return self.moduleName or self.name
+end
+
+--addon:Enable()
+-- Enables the Addon if possible, return true or false depending on success
+function Enable(self)
+	self:SetEnabledState(true)
+	return AceAddon:EnableAddon(self)
+end
+
+--addon:Disable()
+-- Disables the Addon if possible, return true or false depending on success
+function Disable(self)
+	self:SetEnabledState(false)
+	return AceAddon:DisableAddon(self)
+end
+
+-- addon:EnableModule( name )
+-- name (string) - unique module object name
+--
+-- Enables the Module if possible, return true or false depending on success
+function EnableModule(self, name)
+	local module = self:GetModule( name )
+	return module:Enable()
+end
+
+-- addon:DisableModule( name )
+-- name (string) - unique module object name
+--
+-- Disables the Module if possible, return true or false depending on success
+function DisableModule(self, name)
+	local module = self:GetModule( name )
+	return module:Disable()
+end
+
+-- addon:SetDefaultModuleLibraries( [lib, lib, lib, ...]  )
+-- [lib] (string) - libs to embed in every module
+function SetDefaultModuleLibraries(self, ...)
+	if next(self.modules) then
+		error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
+	end
+	self.defaultModuleLibraries = {...}
+end
+
+-- addon:SetDefaultModuleState( state )
+-- state (boolean) - default state for new modules (enabled=true, disabled=false)
+function SetDefaultModuleState(self, state)
+	if next(self.modules) then
+		error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
+	end
+	self.defaultModuleState = state
+end
+
+-- addon:SetDefaultModulePrototype( prototype )
+-- prototype (string or table) - the default prototype to use if none is specified on module creation
+function SetDefaultModulePrototype(self, prototype)
+	if next(self.modules) then
+		error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
+	end
+	if type(prototype) ~= "table" then
+		error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
+	end
+	self.defaultModulePrototype = prototype
+end
+
+-- addon:SetEnabledState ( state )
+-- state ( boolean ) - set the state of an addon or module  (enabled=true, disabled=false)
+--
+-- should only be called before any Enabling actually happend, aka in OnInitialize
+function SetEnabledState(self, state)
+	self.enabledState = state
+end
+
+
+local function IterateModules(self) return pairs(self.modules) end
+local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
+local function IsEnabled(self) return self.enabledState end
+local mixins = {
+	NewModule = NewModule,
+	GetModule = GetModule,
+	Enable = Enable,
+	Disable = Disable,
+	EnableModule = EnableModule,
+	DisableModule = DisableModule,
+	IsEnabled = IsEnabled,
+	SetDefaultModuleLibraries = SetDefaultModuleLibraries,
+	SetDefaultModuleState = SetDefaultModuleState,
+	SetDefaultModulePrototype = SetDefaultModulePrototype,
+	SetEnabledState = SetEnabledState,
+	IterateModules = IterateModules,
+	IterateEmbeds = IterateEmbeds,
+	GetName = GetName,
+}
+local function IsModule(self) return false end
+local pmixins = {
+	defaultModuleState = true,
+	enabledState = true,
+	IsModule = IsModule,
+}
+-- Embed( target )
+-- target (object) - target object to embed aceaddon in
+--
+-- this is a local function specifically since it's meant to be only called internally
+function Embed(target)
+	for k, v in pairs(mixins) do
+		target[k] = v
+	end
+	for k, v in pairs(pmixins) do
+		target[k] = target[k] or v
+	end
+end
+
+
+-- AceAddon:IntializeAddon( addon )
+-- addon (object) - addon to intialize
+--
+-- calls OnInitialize on the addon object if available
+-- calls OnEmbedInitialize on embedded libs in the addon object if available
+function AceAddon:InitializeAddon(addon)
+	safecall(addon.OnInitialize, addon)
+	
+	local embeds = self.embeds[addon]
+	for i = 1, #embeds do
+		local lib = LibStub:GetLibrary(embeds[i], true)
+		if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
+	end
+	
+	-- we don't call InitializeAddon on modules specifically, this is handled
+	-- from the event handler and only done _once_
+end
+
+-- AceAddon:EnableAddon( addon )
+-- addon (object) - addon to enable
+--
+-- calls OnEnable on the addon object if available
+-- calls OnEmbedEnable on embedded libs in the addon object if available
+function AceAddon:EnableAddon(addon)
+	if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
+	if self.statuses[addon.name] or not addon.enabledState then return false end
+	-- TODO: handle 'first'? Or let addons do it on their own?
+	safecall(addon.OnEnable, addon)
+	local embeds = self.embeds[addon]
+	for i = 1, #embeds do
+		local lib = LibStub:GetLibrary(embeds[i], true)
+		if lib then safecall(lib.OnEmbedEnable, lib, addon) end
+	end
+	self.statuses[addon.name] = addon.enabledState
+	
+	-- enable possible modules.
+	for name, module in pairs(addon.modules) do
+		self:EnableAddon(module)
+	end
+	
+	return true
+end
+
+-- AceAddon:DisableAddon( addon )
+-- addon (object|string) - addon to disable
+--
+-- calls OnDisable on the addon object if available
+-- calls OnEmbedDisable on embedded libs in the addon object if available
+function AceAddon:DisableAddon(addon)
+	if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
+	if not self.statuses[addon.name] then return false end
+	safecall( addon.OnDisable, addon )
+	local embeds = self.embeds[addon]
+	for i = 1, #embeds do
+		local lib = LibStub:GetLibrary(embeds[i], true)
+		if lib then safecall(lib.OnEmbedDisable, lib, addon) end
+	end
+	self.statuses[addon.name] = addon.enabledState
+	
+	-- disable possible modules.
+	for name, module in pairs(addon.modules) do
+		self:DisableAddon(module)
+	end
+	
+	return true
+end
+
+--The next few funcs are just because no one should be reaching into the internal registries
+--Thoughts?
+function AceAddon:IterateAddons() return pairs(self.addons) end
+function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
+function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
+function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
+
+-- Event Handling
+local function onEvent(this, event, arg1)
+	if event == "ADDON_LOADED" or event == "PLAYER_LOGIN" then
+		-- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
+		while(#AceAddon.initializequeue > 0) do
+			local addon = tremove(AceAddon.initializequeue, 1)
+			-- this might be an issue with recursion - TODO: validate
+			if event == "ADDON_LOADED" then addon.baseName = arg1 end
+			AceAddon:InitializeAddon(addon)
+			tinsert(AceAddon.enablequeue, addon)
+		end
+		
+		if IsLoggedIn() then
+			while(#AceAddon.enablequeue > 0) do
+				local addon = tremove(AceAddon.enablequeue, 1)
+				AceAddon:EnableAddon(addon)
+			end
+		end
+	end
+end
+
+AceAddon.frame:RegisterEvent("ADDON_LOADED")
+AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
+AceAddon.frame:SetScript("OnEvent", onEvent)
+
+-- upgrade embeded
+for name, addon in pairs(AceAddon.addons) do
+	Embed(addon)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceAddon-3.0/AceAddon-3.0.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="AceAddon-3.0.lua"/>
+</Ui>
\ No newline at end of file
--- a/lib/AceConsole-2.0/AceConsole-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2675 +0,0 @@
---[[
-Name: AceConsole-2.0
-Revision: $Rev: 48940 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceConsole-2.0
-SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceConsole-2.0
-Description: Mixin to allow for input/output capabilities. This uses the
-             AceOptions data table format to determine input.
-             http://www.wowace.com/index.php/AceOptions_data_table
-Dependencies: AceLibrary, AceOO-2.0
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "AceConsole-2.0"
-local MINOR_VERSION = "$Revision: 48940 $"
-
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
-
--- #AUTODOC_NAMESPACE AceConsole
-
-local MAP_ONOFF, USAGE, IS_CURRENTLY_SET_TO, IS_NOW_SET_TO, IS_NOT_A_VALID_OPTION_FOR, IS_NOT_A_VALID_VALUE_FOR, NO_OPTIONS_AVAILABLE, OPTION_HANDLER_NOT_FOUND, OPTION_HANDLER_NOT_VALID, OPTION_IS_DISABLED, KEYBINDING_USAGE, DEFAULT_CONFIRM_MESSAGE
-if GetLocale() == "deDE" then
-	MAP_ONOFF = { [false] = "|cffff0000Aus|r", [true] = "|cff00ff00An|r" }
-	USAGE = "Benutzung"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r steht momentan auf |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOW_SET_TO = "|cffffff7f%s|r ist nun auf |cffffff7f[|r%s|cffffff7f]|r gesetzt"
-	IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] ist keine g\195\188ltige Option f\195\188r |cffffff7f%s|r"
-	IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] ist kein g\195\188ltiger Wert f\195\188r |cffffff7f%s|r"
-	NO_OPTIONS_AVAILABLE = "Keine Optionen verfügbar"
-	OPTION_HANDLER_NOT_FOUND = "Optionen handler |cffffff7f%q|r nicht gefunden."
-	OPTION_HANDLER_NOT_VALID = "Optionen handler nicht g\195\188ltig."
-	OPTION_IS_DISABLED = "Option |cffffff7f%s|r deaktiviert."
-	KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix
-	DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix
-elseif GetLocale() == "frFR" then
-	MAP_ONOFF = { [false] = "|cffff0000Inactif|r", [true] = "|cff00ff00Actif|r" }
-	USAGE = "Utilisation"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est actuellement positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOW_SET_TO = "|cffffff7f%s|r est maintenant positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] n'est pas une option valide pour |cffffff7f%s|r"
-	IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] n'est pas une valeur valide pour |cffffff7f%s|r"
-	NO_OPTIONS_AVAILABLE = "Pas d'options disponibles"
-	OPTION_HANDLER_NOT_FOUND = "Le gestionnaire d'option |cffffff7f%q|r n'a pas \195\169t\195\169 trouv\195\169."
-	OPTION_HANDLER_NOT_VALID = "Le gestionnaire d'option n'est pas valide."
-	OPTION_IS_DISABLED = "L'option |cffffff7f%s|r est d\195\169sactiv\195\169e."
-	KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix
-	DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix
-elseif GetLocale() == "koKR" then
-	MAP_ONOFF = { [false] = "|cffff0000끔|r", [true] = "|cff00ff00켬|r" }
-	USAGE = "사용법"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r|1은;는; 현재 상태는 |cffffff7f[|r%s|cffffff7f]|r|1으로;로; 설정되어 있습니다."
-	IS_NOW_SET_TO = "|cffffff7f%s|r|1을;를; |cffffff7f[|r%s|cffffff7f]|r 상태로 변경합니다."
-	IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용 불가능한 설정입니다."
-	IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용 불가능한 설정 값입니다."
-	NO_OPTIONS_AVAILABLE = "가능한 설정이 없습니다."
-	OPTION_HANDLER_NOT_FOUND = "설정 조정 값인 |cffffff7f%q|r|1을;를; 찾지 못했습니다."
-	OPTION_HANDLER_NOT_VALID = "설정 조정 값이 올바르지 않습니다."
-	OPTION_IS_DISABLED = "|cffffff7f%s|r 설정은 사용할 수 없습니다."
-	KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>"
-	DEFAULT_CONFIRM_MESSAGE = "정말 당신은 `%s'|1을;를; 하시겠습니까?"
-elseif GetLocale() == "zhCN" then
-	MAP_ONOFF = { [false] = "|cffff0000\229\133\179\233\151\173|r", [true] = "|cff00ff00\229\188\128\229\144\175|r" }
-	USAGE = "\231\148\168\230\179\149"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r \229\189\147\229\137\141\232\162\171\232\174\190\231\189\174 |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOW_SET_TO = "|cffffff7f%s|r \231\142\176\229\156\168\232\162\171\232\174\190\231\189\174\228\184\186 |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\231\154\132\233\128\137\233\161\185 \228\184\186 |cffffff7f%s|r"
-	IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\229\128\188 \228\184\186 |cffffff7f%s|r"
-	NO_OPTIONS_AVAILABLE = "\230\178\161\230\156\137\233\128\137\233\161\185\229\143\175\231\148\168"
-	OPTION_HANDLER_NOT_FOUND = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 |cffffff7f%q|r \230\178\161\230\159\165\230\137\190."
-	OPTION_HANDLER_NOT_VALID = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 \230\151\160\230\149\136."
-	OPTION_IS_DISABLED = "\233\128\137\233\161\185 |cffffff7f%s|r \228\184\141\229\174\140\230\149\180."
-	KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix
-	DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix
-elseif GetLocale() == "zhTW" then
-	MAP_ONOFF = { [false] = "|cffff0000關閉|r", [true] = "|cff00ff00開啟|r" }
-	USAGE = "用法"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r目前的設定為|cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOW_SET_TO = "|cffffff7f%s|r現在被設定為|cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOT_A_VALID_OPTION_FOR = "對於|cffffff7f%2$s|r,[|cffffff7f%1$s|r]是一個不符合規定的選項"
-	IS_NOT_A_VALID_VALUE_FOR = "對於|cffffff7f%2$s|r,[|cffffff7f%1$s|r]是一個不符合規定的數值"
-	NO_OPTIONS_AVAILABLE = "沒有可用的選項"
-	OPTION_HANDLER_NOT_FOUND = "找不到|cffffff7f%q|r選項處理器。"
-	OPTION_HANDLER_NOT_VALID = "選項處理器不符合規定。"
-	OPTION_IS_DISABLED = "|cffffff7f%s|r已被停用。"
-	KEYBINDING_USAGE = "<Alt-Ctrl-Shift-鍵>"
-	DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?"
-elseif GetLocale() == "esES" then
-	MAP_ONOFF = { [false] = "|cffff0000Desactivado|r", [true] = "|cff00ff00Activado|r" }
-	USAGE = "Uso"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est\195\161 establecido actualmente a |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOW_SET_TO = "|cffffff7f%s|r se ha establecido a |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] no es una opci\195\179n valida para |cffffff7f%s|r"
-	IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] no es un valor v\195\161lido para |cffffff7f%s|r"
-	NO_OPTIONS_AVAILABLE = "No hay opciones disponibles"
-	OPTION_HANDLER_NOT_FOUND = "Gestor de opciones |cffffff7f%q|r no encontrado."
-	OPTION_HANDLER_NOT_VALID = "Gestor de opciones no v\195\161lido."
-	OPTION_IS_DISABLED = "La opci\195\179n |cffffff7f%s|r est\195\161 desactivada."
-	KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>"
-	DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix
-else -- enUS
-	MAP_ONOFF = { [false] = "|cffff0000Off|r", [true] = "|cff00ff00On|r" }
-	USAGE = "Usage"
-	IS_CURRENTLY_SET_TO = "|cffffff7f%s|r is currently set to |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOW_SET_TO = "|cffffff7f%s|r is now set to |cffffff7f[|r%s|cffffff7f]|r"
-	IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] is not a valid option for |cffffff7f%s|r"
-	IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] is not a valid value for |cffffff7f%s|r"
-	NO_OPTIONS_AVAILABLE = "No options available"
-	OPTION_HANDLER_NOT_FOUND = "Option handler |cffffff7f%q|r not found."
-	OPTION_HANDLER_NOT_VALID = "Option handler not valid."
-	OPTION_IS_DISABLED = "Option |cffffff7f%s|r is disabled."
-	KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>"
-	DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?"
-end
-
-local NONE = NONE or "None"
-
-local AceOO = AceLibrary("AceOO-2.0")
-local AceEvent
-
-local AceConsole = AceOO.Mixin { "Print", "PrintComma", "PrintLiteral", "CustomPrint", "RegisterChatCommand" }
-local Dewdrop
-
-local _G = getfenv(0)
-
-local function print(text, name, r, g, b, frame, delay)
-	if not text or text:len() == 0 then
-		text = " "
-	end
-	if not name or name == AceConsole then
-	else
-		text = "|cffffff78" .. tostring(name) .. ":|r " .. text
-	end
-	local last_color
-	for t in text:gmatch("[^\n]+") do
-		(frame or DEFAULT_CHAT_FRAME):AddMessage(last_color and "|cff" .. last_color .. t or t, r, g, b, nil, delay or 5)
-		if not last_color or t:find("|r") or t:find("|c") then
-			last_color = t:match(".*|c[fF][fF](%x%x%x%x%x%x)[^|]-$")
-		end
-	end
-	return text
-end
-
-local real_tostring = tostring
-
-local function tostring(t)
-	if type(t) == "table" then
-		if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then
-			return ("<%s:%s>"):format(t:GetObjectType(), t:GetName() or "(anon)")
-		end
-	end
-	return real_tostring(t)
-end
-
-local getkeystring
-
-local function isList(t)
-	local n = #t
-	for k,v in pairs(t) do
-		if type(k) ~= "number" then
-			return false
-		elseif k < 1 or k > n then
-			return false
-		end
-	end
-	return true
-end
-
-local findGlobal = setmetatable({}, {__index=function(self, t)
-	for k,v in pairs(_G) do
-		if v == t then
-			k = tostring(k)
-			self[v] = k
-			return k
-		end
-	end
-	self[t] = false
-	return false
-end})
-
-local recurse = {}
-local timeToEnd
-local GetTime = GetTime
-local type = type
-
-local new, del
-do
-	local cache = setmetatable({},{__mode='k'})
-	function new()
-		local t = next(cache)
-		if t then
-			cache[t] = nil
-			return t
-		else
-			return {}
-		end
-	end
-
-	function del(t)
-		for k in pairs(t) do
-			t[k] = nil
-		end
-		cache[t] = true
-		return nil
-	end
-end
-
-local function ignoreCaseSort(alpha, bravo)
-	if not alpha or not bravo then
-		return false
-	end
-	return tostring(alpha):lower() < tostring(bravo):lower()
-end
-
-local function specialSort(alpha, bravo)
-	if alpha == nil or bravo == nil then
-		return false
-	end
-	local type_alpha, type_bravo = type(alpha), type(bravo)
-	if type_alpha ~= type_bravo then
-		return type_alpha < type_bravo
-	end
-	if type_alpha == "string" then
-		return alpha:lower() < bravo:lower()
-	elseif type_alpha == "number" then
-		return alpha < bravo
-	elseif type_alpha == "table" then
-		return #alpha < #bravo
-	elseif type_alpha == "boolean" then
-		return not alpha
-	else
-		return false
-	end
-end
-
-local function escapeChar(c)
-    return ("\\%03d"):format(c:byte())
-end
-
-local function literal_tostring_prime(t, depth)
-	if type(t) == "string" then
-		return ("|cff00ff00%q|r"):format((t:gsub("|", "||"))):gsub("[\001-\012\014-\031\128-\255]", escapeChar)
-	elseif type(t) == "table" then
-		if t == _G then
-			return "|cffffea00_G|r"
-		end
-		if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then
-			return ("|cffffea00<%s:%s>|r"):format(t:GetObjectType(), t:GetName() or "(anon)")
-		end
-		if next(t) == nil then
-			local mt = getmetatable(t)
-			if type(mt) == "table" and type(mt.__raw) == "table" then
-				t = mt.__raw
-			end
-		end
-		if recurse[t] then
-			local g = findGlobal[t]
-			if g then
-				return ("|cff9f9f9f<Recursion _G[%q]>|r"):format(g)
-			else
-				return ("|cff9f9f9f<Recursion %s>|r"):format(real_tostring(t):gsub("|", "||"))
-			end
-		elseif GetTime() > timeToEnd then
-			local g = findGlobal[t]
-			if g then
-				return ("|cff9f9f9f<Timeout _G[%q]>|r"):format(g)
-			else
-				return ("|cff9f9f9f<Timeout %s>|r"):format(real_tostring(t):gsub("|", "||"))
-			end
-		elseif depth >= 2 then
-			local g = findGlobal[t]
-			if g then
-				return ("|cff9f9f9f<_G[%q]>|r"):format(g)
-			else
-				return ("|cff9f9f9f<%s>|r"):format(real_tostring(t):gsub("|", "||"))
-			end
-		end
-		recurse[t] = true
-		if next(t) == nil then
-			return "{}"
-		elseif next(t, (next(t))) == nil then
-			local k, v = next(t)
-			if k == 1 then
-				return "{ " .. literal_tostring_prime(v, depth+1) .. " }"
-			else
-				return "{ " .. getkeystring(k, depth+1) .. " = " .. literal_tostring_prime(v, depth+1) .. " }"
-			end
-		end
-		local s
-		local g = findGlobal[t]
-		if g then
-			s = ("{ |cff9f9f9f-- _G[%q]|r\n"):format(g)
-		else
-			s = "{ |cff9f9f9f-- " .. real_tostring(t):gsub("|", "||") .. "|r\n"
-		end
-		if isList(t) then
-			for i = 1, #t do
-				s = s .. ("    "):rep(depth+1) .. literal_tostring_prime(t[i], depth+1) .. (i == #t and "\n" or ",\n")
-			end
-		else
-			local tmp = new()
-			for k in pairs(t) do
-				tmp[#tmp+1] = k
-			end
-			table.sort(tmp, specialSort)
-			for i,k in ipairs(tmp) do
-				tmp[i] = nil
-				local v = t[k]
-				s = s .. ("    "):rep(depth+1) .. getkeystring(k, depth+1) .. " = " .. literal_tostring_prime(v, depth+1) .. (tmp[i+1] == nil and "\n" or ",\n")
-			end
-			tmp = del(tmp)
-		end
-		if g then
-			s = s .. ("    "):rep(depth) .. string.format("} |cff9f9f9f-- _G[%q]|r", g)
-		else
-			s = s .. ("    "):rep(depth) .. "} |cff9f9f9f-- " .. real_tostring(t):gsub("|", "||")
-		end
-		return s
-	end
-	if type(t) == "number" then
-		return "|cffff7fff" .. real_tostring(t) .. "|r"
-	elseif type(t) == "boolean" then
-		return "|cffff9100" .. real_tostring(t) .. "|r"
-	elseif t == nil then
-		return "|cffff7f7f" .. real_tostring(t) .. "|r"
-	else
-		return "|cffffea00" .. real_tostring(t) .. "|r"
-	end
-end
-
-function getkeystring(t, depth)
-	if type(t) == "string" then
-		if t:find("^[%a_][%a%d_]*$") then
-			return "|cff7fd5ff" .. t .. "|r"
-		end
-	end
-	return "[" .. literal_tostring_prime(t, depth) .. "]"
-end
-
-local get_stringed_args
-do
-	local function g(value, ...)
-		if select('#', ...) == 0 then
-			return literal_tostring_prime(value, 1)
-		end
-		return literal_tostring_prime(value, 1) .. ", " .. g(...)
-	end
-
-	local function f(success, ...)
-		if not success then
-			return
-		end
-		return g(...)
-	end
-
-	function get_stringed_args(func, ...)
-		return f(pcall(func, ...))
-	end
-end
-
-local function literal_tostring_frame(t)
-	local s = ("|cffffea00<%s:%s|r\n"):format(t:GetObjectType(), t:GetName() or "(anon)")
-	local __index = getmetatable(t).__index
-	local tmp, tmp2, tmp3 = new(), new(), new()
-	for k in pairs(t) do
-		if k ~= 0 then
-			tmp3[k] = true
-			tmp2[k] = true
-		end
-	end
-	for k in pairs(__index) do
-		tmp2[k] = true
-	end
-	for k in pairs(tmp2) do
-		tmp[#tmp+1] = k
-		tmp2[k] = nil
-	end
-	table.sort(tmp, ignoreCaseSort)
-	local first = true
-	for i,k in ipairs(tmp) do
-		local v = t[k]
-		local good = true
-		if k == "GetPoint" then
-			for i = 1, t:GetNumPoints() do
-				if not first then
-					s = s .. ",\n"
-				else
-					first = false
-				end
-				s = s .. "    " .. getkeystring(k, 1) .. "(" .. literal_tostring_prime(i, 1) .. ") => " .. get_stringed_args(v, t, i)
-			end
-		elseif type(v) == "function" and type(k) == "string" and (k:find("^Is") or k:find("^Get") or k:find("^Can")) then
-			local q = get_stringed_args(v, t)
-			if q then
-				if not first then
-					s = s .. ",\n"
-				else
-					first = false
-				end
-				s = s .. "    " .. getkeystring(k, 1) .. "() => " .. q
-			end
-		elseif type(v) ~= "function" or (type(v) == "function" and type(k) == "string" and tmp3[k]) then
-			if not first then
-				s = s .. ",\n"
-			else
-				first = false
-			end
-			s = s .. "    " .. getkeystring(k, 1) .. " = " .. literal_tostring_prime(v, 1)
-		else
-			good = false
-		end
-	end
-	tmp, tmp2, tmp3 = del(tmp), del(tmp2), del(tmp3)
-	s = s .. "\n|cffffea00>|r"
-	return s
-end
-
-local function literal_tostring(t, only)
-	timeToEnd = GetTime() + 0.2
-	local s
-	if only and type(t) == "table" and type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then
-		s = literal_tostring_frame(t)
-	else
-		s = literal_tostring_prime(t, 0)
-	end
-	for k,v in pairs(recurse) do
-		recurse[k] = nil
-	end
-	for k,v in pairs(findGlobal) do
-		findGlobal[k] = nil
-	end
-	return s
-end
-
-local function tostring_args(a1, ...)
-	if select('#', ...) < 1 then
-		return tostring(a1)
-	end
-	return tostring(a1), tostring_args(...)
-end
-
-local function literal_tostring_args(a1, ...)
-	if select('#', ...) < 1 then
-		return literal_tostring(a1)
-	end
-	return literal_tostring(a1), literal_tostring_args(...)
-end
-
-function AceConsole:CustomPrint(r, g, b, frame, delay, connector, a1, ...)
-	if connector == true then
-		local s
-		if select('#', ...) == 0 then
-			s = literal_tostring(a1, true)
-		else
-			s = (", "):join(literal_tostring_args(a1, ...))
-		end
-		return print(s, self, r, g, b, frame or self.printFrame, delay)
-	elseif tostring(a1):find("%%") and select('#', ...) >= 1 then
-		local success, text = pcall(string.format, tostring_args(a1, ...))
-		if success then
-			return print(text, self, r, g, b, frame or self.printFrame, delay)
-		end
-	end
-	return print((connector or " "):join(tostring_args(a1, ...)), self, r, g, b, frame or self.printFrame, delay)
-end
-
-function AceConsole:Print(...)
-	return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, " ", ...)
-end
-
-function AceConsole:PrintComma(...)
-	return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, ", ", ...)
-end
-
-function AceConsole:PrintLiteral(...)
-	return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, true, ...)
-end
-
-local work
-local argwork
-
-local function findTableLevel(self, options, chat, text, index, passTable)
-	if not index then
-		index = 1
-		if work then
-			for k,v in pairs(work) do
-				work[k] = nil
-			end
-			for k,v in pairs(argwork) do
-				argwork[k] = nil
-			end
-		else
-			work = {}
-			argwork = {}
-		end
-		local len = text:len()
-		local count
-		repeat
-			text, count = text:gsub("(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[[^%]]-) (.-%]|h|r)", "%1\001%2")
-		until count == 0
-		text = text:gsub("(%]|h|r)(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[)", "%1 %2")
-		for token in text:gmatch("([^%s]+)") do
-			local token = token
-			local num = tonumber(token)
-			if num then
-				token = num
-			else
-				token = token:gsub("\001", " ")
-			end
-			table.insert(work, token)
-		end
-	end
-
-	local path = chat
-	for i = 1, index - 1 do
-		path = path .. " " .. tostring(work[i])
-	end
-
-	local passValue = options.passValue or (passTable and work[index-1])
-	passTable = passTable or options
-
-	if type(options.args) == "table" then
-		local disabled, hidden = options.disabled, options.cmdHidden or options.hidden
-		if hidden then
-			if type(hidden) == "function" then
-				hidden = hidden(passValue)
-			elseif type(hidden) == "string" then
-				local handler = options.handler or self
-				local f = hidden
-				local neg = f:match("^~(.-)$")
-				if neg then
-					f = neg
-				end
-				if type(handler[f]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-				end
-				hidden = handler[f](handler, passValue)
-				if neg then
-					hidden = not hidden
-				end
-			end
-		end
-		if hidden then
-			disabled = true
-		elseif disabled then
-			if type(disabled) == "function" then
-				disabled = disabled(passValue)
-			elseif type(disabled) == "string" then
-				local handler = options.handler or self
-				local f = disabled
-				local neg = f:match("^~(.-)$")
-				if neg then
-					f = neg
-				end
-				if type(handler[f]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-				end
-				disabled = handler[f](handler, passValue)
-				if neg then
-					disabled = not disabled
-				end
-			end
-		end
-		if not disabled then
-			local next = work[index] and tostring(work[index]):lower()
-			local next_num = tonumber(next)
-			if next then
-				for k,v in pairs(options.args) do
-					local good = false
-					if tostring(k):gsub("%s", "-"):lower() == next then
-						good = true
-					elseif k == next_num then
-						good = true
-					elseif type(v.aliases) == "table" then
-						for _,alias in ipairs(v.aliases) do
-							if alias:gsub("%s", "-"):lower() == next then
-								good = true
-								break
-							end
-						end
-					elseif type(v.aliases) == "string" and v.aliases:gsub("%s", "-"):lower() == next then
-						good = true
-					end
-					if good then
-						work[index] = k -- revert it back to its original form as supplied in args
-						if options.pass then
-							passTable = passTable or options
-							if options.get and options.set then
-								passTable = options
-							end
-						else
-							passTable = nil
-						end
-						return findTableLevel(options.handler or self, v, chat, text, index + 1, passTable)
-					end
-				end
-			end
-		end
-	end
-	for i = index, #work do
-		table.insert(argwork, work[i])
-	end
-	return options, path, argwork, options.handler or self, passTable, passValue
-end
-
-local function validateOptionsMethods(self, options, position)
-	if type(options) ~= "table" then
-		return "Options must be a table.", position
-	end
-	self = options.handler or self
-	if options.type == "execute" then
-		if options.func and type(options.func) ~= "string" and type(options.func) ~= "function" then
-			return "func must be a string or function", position
-		end
-		if options.func and type(options.func) == "string" and type(self[options.func]) ~= "function" then
-			return ("%q is not a proper function"):format(tostring(options.func)), position
-		end
-	else
-		if options.get then
-			if type(options.get) ~= "string" and type(options.get) ~= "function" then
-				return "get must be a string or function", position
-			end
-			if type(options.get) == "string" then
-				local f = options.get
-				if options.type == "toggle" then
-					f = f:match("^~(.-)$") or f
-				end
-				if type(self[f]) ~= "function" then
-					return ("%q is not a proper function"):format(tostring(f)), position
-				end
-			end
-		end
-		if options.set then
-			if type(options.set) ~= "string" and type(options.set) ~= "function" then
-				return "set must be a string or function", position
-			end
-			if type(options.set) == "string" and type(self[options.set]) ~= "function" then
-				return ("%q is not a proper function"):format(tostring(options.set)), position
-			end
-		end
-		if options.validate and type(options.validate) ~= "table" and options.validate ~= "keybinding" then
-			if type(options.validate) ~= "string" and type(options.validate) ~= "function" then
-				return "validate must be a string or function", position
-			end
-			if type(options.validate) == "string" and type(self[options.validate]) ~= "function" then
-				return ("%q is not a proper function"):format(tostring(options.validate)), position
-			end
-		end
-	end
-	if options.disabled and type(options.disabled) == "string" then
-		local f = options.disabled
-		f = f:match("^~(.-)$") or f
-		if type(self[f]) ~= "function" then
-			return ("%q is not a proper function"):format(tostring(f)), position
-		end
-	end
-	if options.cmdHidden and type(options.cmdHidden) == "string" then
-		local f = options.cmdHidden
-		f = f:match("^~(.-)$") or f
-		if type(self[f]) ~= "function" then
-			return ("%q is not a proper function"):format(tostring(f)), position
-		end
-	end
-	if options.guiHidden and type(options.guiHidden) == "string" then
-		local f = options.guiHidden
-		f = f:match("^~(.-)$") or f
-		if type(self[f]) ~= "function" then
-			return ("%q is not a proper function"):format(tostring(f)), position
-		end
-	end
-	if options.hidden and type(options.hidden) == "string" then
-		local f = options.hidden
-		f = f:match("^~(.-)$") or f
-		if type(self[f]) ~= "function" then
-			return ("%q is not a proper function"):format(tostring(f)), position
-		end
-	end
-	if options.type == "group" and type(options.args) == "table" then
-		for k,v in pairs(options.args) do
-			if type(v) == "table" then
-				local newposition
-				if position then
-					newposition = position .. ".args." .. k
-				else
-					newposition = "args." .. k
-				end
-				local err, pos = validateOptionsMethods(self, v, newposition)
-				if err then
-					return err, pos
-				end
-			end
-		end
-	end
-end
-
-local function validateOptions(options, position, baseOptions, fromPass)
-	if not baseOptions then
-		baseOptions = options
-	end
-	if type(options) ~= "table" then
-		return "Options must be a table.", position
-	end
-	local kind = options.type
-	if type(kind) ~= "string" then
-		return '"type" must be a string.', position
-	elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then
-		return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position
-	end
-	if options.aliases then
-		if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then
-			return '"alias" must be a table or string', position
-		end
-	end
-	if not fromPass then
-		if kind == "execute" then
-			if type(options.func) ~= "string" and type(options.func) ~= "function" then
-				return '"func" must be a string or function', position
-			end
-		elseif kind == "range" or kind == "text" or kind == "toggle" then
-			if type(options.set) ~= "string" and type(options.set) ~= "function" then
-				return '"set" must be a string or function', position
-			end
-			if kind == "text" and options.get == false then
-			elseif type(options.get) ~= "string" and type(options.get) ~= "function" then
-				return '"get" must be a string or function', position
-			end
-		elseif kind == "group" and options.pass then
-			if options.pass ~= true then
-				return '"pass" must be either nil, true, or false', position
-			end
-			if not options.func then
-				if type(options.set) ~= "string" and type(options.set) ~= "function" then
-					return '"set" must be a string or function', position
-				end
-				if type(options.get) ~= "string" and type(options.get) ~= "function" then
-					return '"get" must be a string or function', position
-				end
-			elseif type(options.func) ~= "string" and type(options.func) ~= "function" then
-				return '"func" must be a string or function', position
-			end
-		end
-	end
-	if options ~= baseOptions then
-		if kind == "header" then
-		elseif type(options.desc) ~= "string" then
-			return '"desc" must be a string', position
-		elseif options.desc:len() == 0 then
-			return '"desc" cannot be a 0-length string', position
-		end
-	end
-
-	if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then
-		if options.type == "header" and not options.cmdName and not options.name then
-		elseif options.cmdName then
-			if type(options.cmdName) ~= "string" then
-				return '"cmdName" must be a string or nil', position
-			elseif options.cmdName:len() == 0 then
-				return '"cmdName" cannot be a 0-length string', position
-			end
-			if type(options.guiName) ~= "string" then
-				if not options.guiNameIsMap then
-					return '"guiName" must be a string or nil', position
-				end
-			elseif options.guiName:len() == 0 then
-				return '"guiName" cannot be a 0-length string', position
-			end
-		else
-			if type(options.name) ~= "string" then
-				return '"name" must be a string', position
-			elseif options.name:len() == 0 then
-				return '"name" cannot be a 0-length string', position
-			end
-		end
-	end
-	if options.guiNameIsMap then
-		if type(options.guiNameIsMap) ~= "boolean" then
-			return '"guiNameIsMap" must be a boolean or nil', position
-		elseif options.type ~= "toggle" then
-			return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position
-		elseif type(options.map) ~= "table" then
-			return '"map" must be a table', position
-		end
-	end
-	if options.message and type(options.message) ~= "string" then
-		return '"message" must be a string or nil', position
-	end
-	if options.error and type(options.error) ~= "string" then
-		return '"error" must be a string or nil', position
-	end
-	if options.current and type(options.current) ~= "string" then
-		return '"current" must be a string or nil', position
-	end
-	if options.order then
-		if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then
-			return '"order" must be a non-zero number or nil', position
-		end
-	end
-	if options.disabled then
-		if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then
-			return '"disabled" must be a function, string, or boolean', position
-		end
-	end
-	if options.cmdHidden then
-		if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then
-			return '"cmdHidden" must be a function, string, or boolean', position
-		end
-	end
-	if options.guiHidden then
-		if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then
-			return '"guiHidden" must be a function, string, or boolean', position
-		end
-	end
-	if options.hidden then
-		if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then
-			return '"hidden" must be a function, string, or boolean', position
-		end
-	end
-	if kind == "text" then
-		if type(options.validate) == "table" then
-			local t = options.validate
-			local iTable = nil
-			for k,v in pairs(t) do
-				if type(k) == "number" then
-					if iTable == nil then
-						iTable = true
-					elseif not iTable then
-						return '"validate" must either have all keys be indexed numbers or strings', position
-					elseif k < 1 or k > #t then
-						return '"validate" numeric keys must be indexed properly. >= 1 and <= #validate', position
-					end
-				else
-					if iTable == nil then
-						iTable = false
-					elseif iTable then
-						return '"validate" must either have all keys be indexed numbers or strings', position
-					end
-				end
-				if type(v) ~= "string" then
-					return '"validate" values must all be strings', position
-				end
-			end
-			if options.multiToggle and options.multiToggle ~= true then
-				return '"multiToggle" must be a boolean or nil if "validate" is a table', position
-			end
-		elseif options.validate == "keybinding" then
-
-		else
-			if type(options.usage) ~= "string" then
-				return '"usage" must be a string', position
-			elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then
-				return '"validate" must be a string, function, or table', position
-			end
-		end
-		if options.multiToggle and type(options.validate) ~= "table" then
-			return '"validate" must be a table if "multiToggle" is true', position
-		end
-	elseif kind == "range" then
-		if options.min or options.max then
-			if type(options.min) ~= "number" then
-				return '"min" must be a number', position
-			elseif type(options.max) ~= "number" then
-				return '"max" must be a number', position
-			elseif options.min >= options.max then
-				return '"min" must be less than "max"', position
-			end
-		end
-		if options.step then
-			if type(options.step) ~= "number" then
-				return '"step" must be a number', position
-			elseif options.step < 0 then
-				return '"step" must be nonnegative', position
-			end
-		end
-		if options.isPercent and options.isPercent ~= true then
-			return '"isPercent" must either be nil, true, or false', position
-		end
-	elseif kind == "toggle" then
-		if options.map then
-			if type(options.map) ~= "table" then
-				return '"map" must be a table', position
-			elseif type(options.map[true]) ~= "string" then
-				return '"map[true]" must be a string', position
-			elseif type(options.map[false]) ~= "string" then
-				return '"map[false]" must be a string', position
-			end
-		end
-	elseif kind == "color" then
-		if options.hasAlpha and options.hasAlpha ~= true then
-			return '"hasAlpha" must be nil, true, or false', position
-		end
-	elseif kind == "group" then
-		if options.pass and options.pass ~= true then
-			return '"pass" must be nil, true, or false', position
-		end
-		if type(options.args) ~= "table" then
-			return '"args" must be a table', position
-		end
-		for k,v in pairs(options.args) do
-			if type(k) ~= "number" then
-				if type(k) ~= "string" then
-					return '"args" keys must be strings or numbers', position
-				elseif k:len() == 0 then
-					return '"args" keys must not be 0-length strings.', position
-				end
-			end
-			if type(v) ~= "table" then
-				if type(k) == "number" then
-					return '"args" values must be tables', position and position .. "[" .. k .. "]" or "[" .. k .. "]"
-				else
-					return '"args" values must be tables', position and position .. "." .. k or k
-				end
-			end
-			local newposition
-			if type(k) == "number" then
-				newposition = position and position .. ".args[" .. k .. "]" or "args[" .. k .. "]"
-			else
-				newposition = position and position .. ".args." .. k or "args." .. k
-			end
-			local err, pos = validateOptions(v, newposition, baseOptions, options.pass)
-			if err then
-				return err, pos
-			end
-		end
-	elseif kind == "execute" then
-		if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then
-			return '"confirm" must be a string, boolean, or nil', position
-		end
-	end
-end
-
-local colorTable
-local colorFunc
-local colorCancelFunc
-
-local function keybindingValidateFunc(text)
-	if text == nil or text == "NONE" then
-		return nil
-	end
-	text = text:upper()
-	local shift, ctrl, alt
-	local modifier
-	while true do
-		if text == "-" then
-			break
-		end
-		modifier, text = strsplit('-', text, 2)
-		if text then
-			if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
-				return false
-			end
-			if modifier == "SHIFT" then
-				if shift then
-					return false
-				end
-				shift = true
-			end
-			if modifier == "CTRL" then
-				if ctrl then
-					return false
-				end
-				ctrl = true
-			end
-			if modifier == "ALT" then
-				if alt then
-					return false
-				end
-				alt = true
-			end
-		else
-			text = modifier
-			break
-		end
-	end
-	if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then
-		return false
-	end
-	local s = text
-	if shift then
-		s = "SHIFT-" .. s
-	end
-	if ctrl then
-		s = "CTRL-" .. s
-	end
-	if alt then
-		s = "ALT-" .. s
-	end
-	return s
-end
-AceConsole.keybindingValidateFunc = keybindingValidateFunc
-
-local order
-
-local mysort_args
-local mysort
-
-local function icaseSort(alpha, bravo)
-	if type(alpha) == "number" and type(bravo) == "number" then
-		return alpha < bravo
-	end
-	return tostring(alpha):lower() < tostring(bravo):lower()
-end
-
-local tmp = {}
-local function printUsage(self, handler, realOptions, options, path, args, passValue, quiet, filter)
-	if filter then
-		filter = "^" .. filter:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
-	end
-	local hidden, disabled = options.cmdHidden or options.hidden, options.disabled
-	if hidden then
-		if type(hidden) == "function" then
-			hidden = hidden(options.passValue)
-		elseif type(hidden) == "string" then
-			local f = hidden
-			local neg = f:match("^~(.-)$")
-			if neg then
-				f = neg
-			end
-			if type(handler[f]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-			end
-			hidden = handler[f](handler, options.passValue)
-			if neg then
-				hidden = not hidden
-			end
-		end
-	end
-	if hidden then
-		disabled = true
-	elseif disabled then
-		if type(disabled) == "function" then
-			disabled = disabled(options.passValue)
-		elseif type(disabled) == "string" then
-			local f = disabled
-			local neg = f:match("^~(.-)$")
-			if neg then
-				f = neg
-			end
-			if type(handler[f]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-			end
-			disabled = handler[f](handler, options.passValue)
-			if neg then
-				disabled = not disabled
-			end
-		end
-	end
-	local kind = (options.type or "group"):lower()
-	if disabled then
-		print(OPTION_IS_DISABLED:format(path), realOptions.cmdName or realOptions.name or self)
-	elseif kind == "text" then
-		local var
-		local multiToggle
-		for k in pairs(tmp) do
-			tmp[k] = nil
-		end
-		if passTable then
-			multiToggle = passTable.multiToggle
-			if not passTable.get then
-			elseif type(passTable.get) == "function" then
-				if not multiToggle then
-					var = passTable.get(passValue)
-				else
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue == nil then
-							var[val] = passTable.get(val) or nil
-						else
-							var[val] = passTable.get(passValue, val) or nil
-						end
-					end
-				end
-			else
-				local handler = passTable.handler or handler
-				if type(handler[passTable.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(passTable.get)))
-				end
-				var = handler[passTable.get](handler, passValue)
-				if not multiToggle then
-					var = handler[passTable.get](handler, passValue)
-				else
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue == nil then
-							var[val] = handler[passTable.get](handler, val) or nil
-						else
-							var[val] = handler[passTable.get](handler, passValue, val) or nil
-						end
-					end
-				end
-			end
-		else
-			multiToggle = options.multiToggle
-			if not options.get then
-			elseif type(options.get) == "function" then
-				if not multiToggle then
-					var = options.get(passValue)
-				else
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue == nil then
-							var[val] = options.get(val) or nil
-						else
-							var[val] = options.get(passValue, val) or nil
-						end
-					end
-				end
-			else
-				local handler = options.handler or handler
-				if type(handler[options.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.get)))
-				end
-				if not multiToggle then
-					var = handler[options.get](handler, passValue)
-				else
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue == nil then
-							var[val] = handler[options.get](handler, val) or nil
-						else
-							var[val] = handler[options.get](handler, passValue, val) or nil
-						end
-					end
-				end
-			end
-		end
-
-		local usage
-		if type(options.validate) == "table" then
-			if filter then
-				if not order then
-					order = {}
-				end
-				for k,v in pairs(options.validate) do
-					if v:find(filter) then
-						table.insert(order, v)
-					end
-				end
-				table.sort(order, icaseSort)
-				usage = "{" .. table.concat(order, " || ") .. "}"
-				for k in pairs(order) do
-					order[k] = nil
-				end
-			else
-				if not order then
-					order = {}
-				end
-				for k,v in pairs(options.validate) do
-					table.insert(order, v)
-				end
-				table.sort(order, icaseSort)
-				usage = "{" .. table.concat(order, " || ") .. "}"
-				for k in pairs(order) do
-					order[k] = nil
-				end
-			end
-			if multiToggle then
-				if not next(var) then
-					var = NONE
-				else
-					if not order then
-						order = {}
-					end
-					for k in pairs(var) do
-						if options.validate[k] then
-							order[#order+1] = options.validate[k]
-						else
-							for _,v in pairs(options.validate) do
-								if v == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then
-									order[#order+1] = v
-									break
-								end
-							end
-						end
-					end
-					table.sort(order, icaseSort)
-					var = table.concat(order, ", ")
-					for k in pairs(order) do
-						order[k] = nil
-					end
-				end
-			else
-				var = options.validate[var] or var
-			end
-		elseif options.validate == "keybinding" then
-			usage = KEYBINDING_USAGE
-		else
-			usage = options.usage or "<value>"
-		end
-		if not quiet then
-			print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage), realOptions.cmdName or realOptions.name or self)
-		end
-		if (passTable and passTable.get) or options.get then
-			print((options.current or IS_CURRENTLY_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)))
-		end
-	elseif kind == "range" then
-		local var
-		if passTable then
-			if type(passTable.get) == "function" then
-				var = passTable.get(passValue)
-			else
-				local handler = passTable.handler or handler
-				if type(handler[passTable.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(passTable.get)))
-				end
-				var = handler[passTable.get](handler, passValue)
-			end
-		else
-			if type(options.get) == "function" then
-				var = options.get(passValue)
-			else
-				local handler = options.handler or handler
-				if type(handler[options.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.get)))
-				end
-				var = handler[options.get](handler, passValue)
-			end
-		end
-
-		local usage
-		local min = options.min or 0
-		local max = options.max or 1
-		if options.isPercent then
-			min, max = min * 100, max * 100
-			var = tostring(var * 100) .. "%"
-		end
-		local bit = "-"
-		if min < 0 or max < 0 then
-			bit = " - "
-		end
-		usage = ("(%s%s%s)"):format(min, bit, max)
-		if not quiet then
-			print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage), realOptions.cmdName or realOptions.name or self)
-		end
-		print((options.current or IS_CURRENTLY_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)))
-	elseif kind == "group" then
-		local usage
-		if next(options.args) then
-			if not order then
-				order = {}
-			end
-			for k,v in pairs(options.args) do
-				if v.type ~= "header" then
-					local hidden = v.cmdHidden or v.hidden
-					if hidden then
-						if type(hidden) == "function" then
-							hidden = hidden()
-						elseif type(hidden) == "string" then
-							local f = hidden
-							local neg = f:match("^~(.-)$")
-							if neg then
-								f = neg
-							end
-							if type(handler[f]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-							end
-							hidden = handler[f](handler)
-							if neg then
-								hidden = not hidden
-							end
-						end
-					end
-					if not hidden then
-						if filter then
-							if k:find(filter) then
-								table.insert(order, k)
-							elseif type(v.aliases) == "table" then
-								for _,bit in ipairs(v.aliases) do
-									if bit:find(filter) then
-										table.insert(order, k)
-										break
-									end
-								end
-							elseif type(v.aliases) == "string" then
-								if v.aliases:find(filter) then
-									table.insert(order, k)
-								end
-							end
-						else
-							table.insert(order, k)
-						end
-					end
-				end
-			end
-			if not mysort then
-				mysort = function(a, b)
-					local alpha, bravo = mysort_args[a], mysort_args[b]
-					local alpha_order = alpha and alpha.order or 100
-					local bravo_order = bravo and bravo.order or 100
-					if alpha_order == bravo_order then
-						return tostring(a):lower() < tostring(b):lower()
-					else
-						if alpha_order < 0 then
-							if bravo_order > 0 then
-								return false
-							end
-						else
-							if bravo_order < 0 then
-								return true
-							end
-						end
-						if alpha_order > 0 and bravo_order > 0 then
-							return tostring(a):lower() < tostring(b):lower()
-						end
-						return alpha_order < bravo_order
-					end
-				end
-			end
-			mysort_args = options.args
-			table.sort(order, mysort)
-			mysort_args = nil
-			if not quiet then
-				if options == realOptions then
-					if options.desc then
-						print(tostring(options.desc), realOptions.cmdName or realOptions.name or self)
-						print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"))
-					elseif self.description or self.notes then
-						print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self)
-						print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"))
-					else
-						print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self)
-					end
-				else
-					if options.desc then
-						print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self)
-						print(tostring(options.desc))
-					else
-						print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self)
-					end
-				end
-			end
-			local passTable = options.pass and options or nil
-			for _,k in ipairs(order) do
-				local passValue = passTable and k or nil
-				local real_k = k
-				local v = options.args[k]
-				if v then
-					local v_p = passTable or v
-					if v.get and v.set then
-						v_p = v
-						passValue = nil
-					end
-					if v.passValue then
-						passValue = v.passValue
-					end
-					local k = tostring(k):gsub("%s", "-")
-					local disabled = v.disabled
-					if disabled then
-						if type(disabled) == "function" then
-							disabled = disabled(passValue)
-						elseif type(disabled) == "string" then
-							local f = disabled
-							local neg = f:match("^~(.-)$")
-							if neg then
-								f = neg
-							end
-							if type(handler[f]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-							end
-							disabled = handler[f](handler, passValue)
-							if neg then
-								disabled = not disabled
-							end
-						end
-					end
-					if type(v.aliases) == "table" then
-						for _,s in ipairs(v.aliases) do
-							k = k .. " || " .. s:gsub("%s", "-")
-						end
-					elseif type(v.aliases) == "string" then
-						k = k .. " || " .. v.aliases:gsub("%s", "-")
-					end
-					if v_p.get then
-						local a1,a2,a3,a4
-						local multiToggle = v_p.type == "text" and v_p.multiToggle
-						for k in pairs(tmp) do
-							tmp[k] = nil
-						end
-						if type(v_p.get) == "function" then
-							if multiToggle then
-								a1 = tmp
-								for k,v in pairs(v.validate) do
-									local val = type(k) ~= "number" and k or v
-									if passValue == nil then
-										a1[val] = v_p.get(val) or nil
-									else
-										a1[val] = v_p.get(passValue, val) or nil
-									end
-								end
-							else
-								a1,a2,a3,a4 = v_p.get(passValue)
-							end
-						else
-							local handler = v_p.handler or handler
-							local f = v_p.get
-							local neg
-							if v.type == "toggle" then
-								neg = f:match("^~(.-)$")
-								if neg then
-									f = neg
-								end
-							end
-							if type(handler[f]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-							end
-							if multiToggle then
-								a1 = tmp
-								for k,v in pairs(v.validate) do
-									local val = type(k) ~= "number" and k or v
-									if passValue == nil then
-										a1[val] = handler[f](handler, val) or nil
-									else
-										a1[val] = handler[f](handler, passValue, val) or nil
-									end
-								end
-							else
-								a1,a2,a3,a4 = handler[f](handler, passValue)
-							end
-							if neg then
-								a1 = not a1
-							end
-						end
-						local s
-						if v.type == "color" then
-							if v.hasAlpha then
-								if not a1 or not a2 or not a3 or not a4 then
-									s = NONE
-								else
-									s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a4*255, a1*255, a2*255, a3*255, a4*255, a1*255, a2*255, a3*255)
-								end
-							else
-								if not a1 or not a2 or not a3 then
-									s = NONE
-								else
-									s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(a1*255, a2*255, a3*255, a1*255, a2*255, a3*255)
-								end
-							end
-						elseif v.type == "toggle" then
-							if v.map then
-								s = tostring(v.map[a1 and true or false] or NONE)
-							else
-								s = tostring(MAP_ONOFF[a1 and true or false] or NONE)
-							end
-						elseif v.type == "range" then
-							if v.isPercent then
-								s = tostring(a1 * 100) .. "%"
-							else
-								s = tostring(a1)
-							end
-						elseif v.type == "text" and type(v.validate) == "table" then
-							if multiToggle then
-								if not next(a1) then
-									s = NONE
-								else
-									s = ''
-									for k in pairs(a1) do
-										if v.validate[k] then
-											if s == '' then
-												s = v.validate[k]
-											else
-												s = s .. ', ' .. v.validate[k]
-											end
-										else
-											for _,u in pairs(v.validate) do
-												if u == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then
-													if s == '' then
-														s = u
-													else
-														s = s .. ', ' .. u
-													end
-													break
-												end
-											end
-										end
-									end
-								end
-							else
-								s = tostring(v.validate[a1] or a1 or NONE)
-							end
-						else
-							s = tostring(a1 or NONE)
-						end
-						if disabled then
-							local s = s:gsub("|cff%x%x%x%x%x%x(.-)|r", "%1")
-							local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1")
-							print(("|cffcfcfcf - %s: [%s] %s|r"):format(k, s, desc))
-						else
-							print((" - |cffffff7f%s: [|r%s|cffffff7f]|r %s"):format(k, s, v.desc or NONE))
-						end
-					else
-						if disabled then
-							local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1")
-							print(("|cffcfcfcf - %s: %s"):format(k, desc))
-						else
-							print((" - |cffffff7f%s:|r %s"):format(k, v.desc or NONE))
-						end
-					end
-				end
-			end
-			for k in pairs(order) do
-				order[k] = nil
-			end
-		else
-			if options.desc then
-				print(("|cffffff7f%s:|r %s"):format(USAGE, path), realOptions.cmdName or realOptions.name or self)
-				print(tostring(options.desc))
-			elseif options == realOptions and (self.description or self.notes) then
-				print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self)
-				print(("|cffffff7f%s:|r %s"):format(USAGE, path))
-			else
-				print(("|cffffff7f%s:|r %s"):format(USAGE, path), realOptions.cmdName or realOptions.name or self)
-			end
-			print(NO_OPTIONS_AVAILABLE)
-		end
-	end
-end
-
-local function confirmPopup(message, func, ...)
-	if not StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] then
-		StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] = {}
-	end
-	local t = StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"]
-	for k in pairs(t) do
-		t[k] = nil
-	end
-	t.text = message
-	t.button1 = ACCEPT or "Accept"
-	t.button2 = CANCEL or "Cancel"
-	t.OnAccept = function()
-		func(unpack(t))
-	end
-	for i = 1, select('#', ...) do
-		t[i] = select(i, ...)
-	end
-	t.timeout = 0
-	t.whileDead = 1
-	t.hideOnEscape = 1
-
-	StaticPopup_Show("ACECONSOLE20_CONFIRM_DIALOG")
-end
-
-local function handlerFunc(self, chat, msg, options)
-	if not msg then
-		msg = ""
-	else
-		msg = msg:gsub("^%s*(.-)%s*$", "%1")
-		msg = msg:gsub("%s+", " ")
-	end
-
-	local realOptions = options
-	local options, path, args, handler, passTable, passValue = findTableLevel(self, options, chat, msg)
-	if options.type == "execute" then
-		if options.func then
-			passTable = nil
-		end
-	else
-		if options.get and options.set then
-			passTable = nil
-		end
-	end
-	passValue = options.passValue or passTable and passValue
-
-	local hidden, disabled = options.cmdHidden or options.hidden, options.disabled
-	if hidden then
-		if type(hidden) == "function" then
-			hidden = hidden(passValue)
-		elseif type(hidden) == "string" then
-			local f = hidden
-			local neg = f:match("^~(.-)$")
-			if neg then
-				f = neg
-			end
-			if type(handler[f]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-			end
-			hidden = handler[f](handler, passValue)
-			if neg then
-				hidden = not hidden
-			end
-		end
-	end
-	if hidden then
-		disabled = true
-	elseif disabled then
-		if type(disabled) == "function" then
-			disabled = disabled(passValue)
-		elseif type(disabled) == "string" then
-			local f = disabled
-			local neg = f:match("^~(.-)$")
-			if neg then
-				f = neg
-			end
-			if type(handler[f]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-			end
-			disabled = handler[f](handler, passValue)
-			if neg then
-				disabled = not disabled
-			end
-		end
-	end
-	local _G_this = this
-	local kind = (options.type or "group"):lower()
-	local options_p = passTable or options
-	if disabled then
-		print(OPTION_IS_DISABLED:format(path), realOptions.cmdName or realOptions.name or self)
-	elseif kind == "text" then
-		if #args > 0 then
-			if (type(options.validate) == "table" and #args > 1) or (type(options.validate) ~= "table" and not options.input) then
-				local arg = table.concat(args, " ")
-				for k,v in pairs(args) do
-					args[k] = nil
-				end
-				args[1] = arg
-			end
-			if options.validate then
-				local good
-				if type(options.validate) == "function" then
-					good = options.validate(unpack(args))
-				elseif type(options.validate) == "table" then
-					local arg = args[1]
-					arg = tostring(arg):lower()
-					for k,v in pairs(options.validate) do
-						if v:lower() == arg then
-							args[1] = type(k) == "string" and k or v
-							good = true
-							break
-						end
-					end
-					if not good and type((next(options.validate))) == "string" then
-						for k,v in pairs(options.validate) do
-							if type(k) == "string" and k:lower() == arg then
-								args[1] = k
-								good = true
-								break
-							end
-						end
-					end
-				elseif options.validate == "keybinding" then
-					good = keybindingValidateFunc(unpack(args))
-					if good ~= false then
-						args[1] = good
-					end
-				else
-					if type(handler[options.validate]) ~= "function" then
-						AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.validate)))
-					end
-					good = handler[options.validate](handler, unpack(args))
-				end
-				if not good then
-					local usage
-					if type(options.validate) == "table" then
-						if not order then
-							order = {}
-						end
-						for k,v in pairs(options.validate) do
-							table.insert(order, v)
-						end
-						usage = "{" .. table.concat(order, " || ") .. "}"
-						for k in pairs(order) do
-							order[k] = nil
-						end
-					elseif options.validate == "keybinding" then
-						usage = KEYBINDING_USAGE
-					else
-						usage = options.usage or "<value>"
-					end
-					print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(tostring(table.concat(args, " ")), path), realOptions.cmdName or realOptions.name or self)
-					print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage))
-					return
-				end
-			end
-
-			local var
-			local multiToggle
-			for k in pairs(tmp) do
-				tmp[k] = nil
-			end
-			multiToggle = options_p.multiToggle
-			if not options_p.get then
-			elseif type(options_p.get) == "function" then
-				if multiToggle then
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue then
-							var[val] = options_p.get(passValue, val) or nil
-						else
-							var[val] = options_p.get(val) or nil
-						end
-					end
-				else
-					var = options_p.get(passValue)
-				end
-			else
-				if type(handler[options_p.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get)))
-				end
-				if multiToggle then
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue then
-							var[val] = handler[options_p.get](handler, passValue, val) or nil
-						else
-							var[val] = handler[options_p.get](handler, val) or nil
-						end
-					end
-				else
-					var = handler[options_p.get](handler, passValue)
-				end
-			end
-
-			if multiToggle or var ~= args[1] then
-				if multiToggle then
-					local current = var[args[1]]
-					if current == nil and type(args[1]) == "string" then
-						for k in pairs(var) do
-							if type(k) == "string" and k:lower() == args[1]:lower() then
-								current = true
-								break
-							end
-						end
-					end
-					args[2] = not current
-				end
-				if type(options_p.set) == "function" then
-					if passValue then
-						options_p.set(passValue, unpack(args))
-					else
-						options_p.set(unpack(args))
-					end
-				else
-					if type(handler[options_p.set]) ~= "function" then
-						AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set)))
-					end
-					if passValue then
-						handler[options_p.set](handler, passValue, unpack(args))
-					else
-						handler[options_p.set](handler, unpack(args))
-					end
-				end
-			end
-		end
-
-		if #args > 0 then
-			local var
-			local multiToggle
-			for k in pairs(tmp) do
-				tmp[k] = nil
-			end
-			multiToggle = options_p.multiToggle
-			if not options_p.get then
-			elseif type(options_p.get) == "function" then
-				if multiToggle then
-					var = tmp
-					for k,v in pairs(options_p.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue then
-							var[val] = options_p.get(passValue, val) or nil
-						else
-							var[val] = options_p.get(val) or nil
-						end
-					end
-				else
-					var = options_p.get(passValue)
-				end
-			else
-				if type(handler[options_p.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get)))
-				end
-				if multiToggle then
-					var = tmp
-					for k,v in pairs(options.validate) do
-						local val = type(k) ~= "number" and k or v
-						if passValue then
-							var[val] = handler[options_p.get](handler, passValue, val) or nil
-						else
-							var[val] = handler[options_p.get](handler, val) or nil
-						end
-					end
-				else
-					var = handler[options_p.get](handler, passValue)
-				end
-			end
-			if multiToggle then
-				if not next(var) then
-					var = NONE
-				else
-					if not order then
-						order = {}
-					end
-					for k in pairs(var) do
-						if options.validate[k] then
-							order[#order+1] = options.validate[k]
-						else
-							for _,v in pairs(options.validate) do
-								if v == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then
-									order[#order+1] = v
-									break
-								end
-							end
-						end
-					end
-					table.sort(order, icaseSort)
-					var = table.concat(order, ", ")
-					for k in pairs(order) do
-						order[k] = nil
-					end
-				end
-			elseif type(options.validate) == "table" then
-				var = options.validate[var] or var
-			end
-			if options_p.get then
-				print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self)
-			end
-			if var == args[1] then
-				return
-			end
-		else
-			printUsage(self, handler, realOptions, options, path, args, passValue)
-			return
-		end
-	elseif kind == "execute" then
-		local confirm = options.confirm
-		if confirm == true then
-			confirm = DEFAULT_CONFIRM_MESSAGE:format(options.desc or options.name or UNKNOWN or "Unknown")
-		end
-		if type(options_p.func) == "function" then
-			if confirm then
-				confirmPopup(confirm, options_p.func, passValue)
-			else
-				options_p.func(passValue)
-			end
-		else
-			if type(handler[options_p.func]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.func)))
-			end
-			if confirm then
-				confirmPopup(confirm, handler[options_p.func], handler, passValue)
-			else
-				handler[options_p.func](handler, passValue)
-			end
-		end
-	elseif kind == "toggle" then
-		local var
-		if type(options_p.get) == "function" then
-			var = options_p.get(passValue)
-		else
-			local f = options_p.get
-			local neg = f:match("^~(.-)$")
-			if neg then
-				f = neg
-			end
-			if type(handler[f]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-			end
-			var = handler[f](handler, passValue)
-			if neg then
-				var = not var
-			end
-		end
-		if type(options_p.set) == "function" then
-			if passValue then
-				options_p.set(passValue, not var)
-			else
-				options_p.set(not var)
-			end
-		else
-			if type(handler[options_p.set]) ~= "function" then
-				AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set)))
-			end
-			if passValue then
-				handler[options_p.set](handler, passValue, not var)
-			else
-				handler[options_p.set](handler, not var)
-			end
-		end
-		if type(options_p.get) == "function" then
-			var = options_p.get(passValue)
-		else
-			local f = options_p.get
-			local neg = f:match("^~(.-)$")
-			if neg then
-				f = neg
-			end
-			var = handler[f](handler, passValue)
-			if neg then
-				var = not var
-			end
-		end
-
-		print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), (options.map or MAP_ONOFF)[var and true or false] or NONE), realOptions.cmdName or realOptions.name or self)
-	elseif kind == "range" then
-		local arg
-		if #args <= 1 then
-			arg = args[1]
-		else
-			arg = table.concat(args, " ")
-		end
-
-		if arg then
-			local min = options.min or 0
-			local max = options.max or 1
-			local good = false
-			if type(arg) == "number" then
-				if options.isPercent then
-					arg = arg / 100
-				end
-
-				if arg >= min and arg <= max then
-					good = true
-				end
-
-				if good and type(options.step) == "number" and options.step > 0 then
-					local step = options.step
-					arg = math.floor((arg - min) / step + 0.5) * step + min
-					if arg > max then
-						arg = max
-					elseif arg < min then
-						arg = min
-					end
-				end
-			end
-			if not good then
-				local usage
-				local min = options.min or 0
-				local max = options.max or 1
-				if options.isPercent then
-					min, max = min * 100, max * 100
-				end
-				local bit = "-"
-				if min < 0 or max < 0 then
-					bit = " - "
-				end
-				usage = ("(%s%s%s)"):format(min, bit, max)
-				print((options.error or IS_NOT_A_VALID_VALUE_FOR):format(tostring(arg), path), realOptions.cmdName or realOptions.name or self)
-				print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage))
-				return
-			end
-
-			local var
-			if type(options_p.get) == "function" then
-				var = options_p.get(passValue)
-			else
-				if type(handler[options_p.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get)))
-				end
-				var = handler[options_p.get](handler, passValue)
-			end
-
-			if var ~= arg then
-				if type(options_p.set) == "function" then
-					if passValue then
-						options_p.set(passValue, arg)
-					else
-						options_p.set(arg)
-					end
-				else
-					if type(handler[options_p.set]) ~= "function" then
-						AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set)))
-					end
-					if passValue then
-						handler[options_p.set](handler, passValue, arg)
-					else
-						handler[options_p.set](handler, arg)
-					end
-				end
-			end
-		end
-
-		if arg then
-			local var
-			if type(options_p.get) == "function" then
-				var = options_p.get(passValue)
-			else
-				if type(handler[options_p.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get)))
-				end
-				var = handler[options_p.get](handler, passValue)
-			end
-
-			if var and options.isPercent then
-				var = tostring(var * 100) .. "%"
-			end
-			print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self)
-			if var == arg then
-				return
-			end
-		else
-			printUsage(self, handler, realOptions, options, path, args, passValue)
-			return
-		end
-	elseif kind == "color" then
-		if #args > 0 then
-			local r,g,b,a
-			if #args == 1 then
-				local arg = tostring(args[1])
-				if options.hasAlpha then
-					if arg:len() == 8 and arg:find("^%x*$")  then
-						r,g,b,a = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255, tonumber(arg:sub(7, 8), 16) / 255
-					end
-				else
-					if arg:len() == 6 and arg:find("^%x*$") then
-						r,g,b = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255
-					end
-				end
-			elseif #args == 4 and options.hasAlpha then
-				local a1,a2,a3,a4 = args[1], args[2], args[3], args[4]
-				if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and type(a4) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 and a4 <= 1 then
-					r,g,b,a = a1,a2,a3,a4
-				elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") and (type(a4) == "number" or a4:len() == 2) and a4:find("^%x*$") then
-					r,g,b,a = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255, tonumber(a4, 16) / 255
-				end
-			elseif #args == 3 and not options.hasAlpha then
-				local a1,a2,a3 = args[1], args[2], args[3]
-				if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 then
-					r,g,b = a1,a2,a3
-				elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") then
-					r,g,b = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255
-				end
-			end
-			if not r then
-				print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(table.concat(args, ' '), path), realOptions.cmdName or realOptions.name or self)
-				print(("|cffffff7f%s:|r %s {0-1} {0-1} {0-1}%s"):format(USAGE, path, options.hasAlpha and " {0-1}" or ""))
-				return
-			end
-
-			if type(options_p.set) == "function" then
-				if passValue then
-					options_p.set(passValue, r,g,b,a)
-				else
-					options_p.set(r,g,b,a)
-				end
-			else
-				if type(handler[options_p.set]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set)))
-				end
-				if passValue then
-					handler[options_p.set](handler, passValue, r,g,b,a)
-				else
-					handler[options_p.set](handler, r,g,b,a)
-				end
-			end
-
-			local r,g,b,a
-			if type(options_p.get) == "function" then
-				r,g,b,a = options_p.get(passValue)
-			else
-				if type(handler[options_p.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get)))
-				end
-				r,g,b,a = handler[options_p.get](handler, passValue)
-			end
-
-			local s
-			if type(r) == "number" and type(g) == "number" and type(b) == "number" then
-				if options.hasAlpha and type(a) == "number" then
-					s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255)
-				else
-					s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(r*255, g*255, b*255, r*255, g*255, b*255)
-				end
-			else
-				s = NONE
-			end
-			print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), s), realOptions.cmdName or realOptions.name or self)
-		else
-			local r,g,b,a
-			if type(options_p.get) == "function" then
-				r,g,b,a = options_p.get(passValue)
-			else
-				if type(handler[options_p.get]) ~= "function" then
-					AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get)))
-				end
-				r,g,b,a = handler[options_p.get](handler, passValue)
-			end
-
-			if not colorTable then
-				colorTable = {}
-				local t = colorTable
-
-				if ColorPickerOkayButton then
-					local ColorPickerOkayButton_OnClick = ColorPickerOkayButton:GetScript("OnClick")
-					ColorPickerOkayButton:SetScript("OnClick", function()
-						if ColorPickerOkayButton_OnClick then
-							ColorPickerOkayButton_OnClick()
-						end
-						if t.active then
-							ColorPickerFrame.cancelFunc = nil
-							ColorPickerFrame.func = nil
-							ColorPickerFrame.opacityFunc = nil
-							local r,g,b,a
-							if t.passValue then
-								if type(t.get) == "function" then
-									r,g,b,a = t.get(t.passValue)
-								else
-									if type(t.handler[t.get]) ~= "function" then
-										AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get)))
-									end
-									r,g,b,a = t.handler[t.get](t.handler, t.passValue)
-								end
-							else
-								if type(t.get) == "function" then
-									r,g,b,a = t.get()
-								else
-									if type(t.handler[t.get]) ~= "function" then
-										AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get)))
-									end
-									r,g,b,a = t.handler[t.get](t.handler)
-								end
-							end
-							if r ~= t.r or g ~= t.g or b ~= t.b or (t.hasAlpha and a ~= t.a) then
-								local s
-								if type(r) == "number" and type(g) == "number" and type(b) == "number" then
-									if t.hasAlpha and type(a) == "number" then
-										s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255)
-									else
-										s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(r*255, g*255, b*255, r*255, g*255, b*255)
-									end
-								else
-									s = NONE
-								end
-								print(t.message:format(tostring(t.name), s), t.realOptions.cmdName or t.realOptions.name or self)
-							end
-							for k,v in pairs(t) do
-								t[k] = nil
-							end
-						end
-					end)
-				end
-			else
-				for k,v in pairs(colorTable) do
-					colorTable[k] = nil
-				end
-			end
-
-			if type(r) ~= "number" or type(g) ~= "number" or type(b) ~= "number" then
-				r,g,b = 1, 1, 1
-			end
-			if type(a) ~= "number" then
-				a = 1
-			end
-			local t = colorTable
-			t.r = r
-			t.g = g
-			t.b = b
-			if hasAlpha then
-				t.a = a
-			end
-			t.realOptions = realOptions
-			t.hasAlpha = options.hasAlpha
-			t.handler = handler
-			t.set = options_p.set
-			t.get = options_p.get
-			t.name = options.cmdName or options.name
-			t.message = options.message or IS_NOW_SET_TO
-			t.passValue = passValue
-			t.active = true
-
-			if not colorFunc then
-				colorFunc = function()
-					local r,g,b = ColorPickerFrame:GetColorRGB()
-					if t.hasAlpha then
-						local a = 1 - OpacitySliderFrame:GetValue()
-						if type(t.set) == "function" then
-							if t.passValue then
-								t.set(t.passValue, r,g,b,a)
-							else
-								t.set(r,g,b,a)
-							end
-						else
-							if type(t.handler[t.set]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set)))
-							end
-							if t.passValue then
-								t.handler[t.set](t.handler, t.passValue, r,g,b,a)
-							else
-								t.handler[t.set](t.handler, r,g,b,a)
-							end
-						end
-					else
-						if type(t.set) == "function" then
-							if t.passValue then
-								t.set(t.passValue, r,g,b)
-							else
-								t.set(r,g,b)
-							end
-						else
-							if type(t.handler[t.set]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set)))
-							end
-							if t.passValue then
-								t.handler[t.set](t.handler, t.passValue, r,g,b)
-							else
-								t.handler[t.set](t.handler, r,g,b)
-							end
-						end
-					end
-				end
-			end
-
-			ColorPickerFrame.func = colorFunc
-			ColorPickerFrame.hasOpacity = options.hasAlpha
-			if options.hasAlpha then
-				ColorPickerFrame.opacityFunc = ColorPickerFrame.func
-				ColorPickerFrame.opacity = 1 - a
-			end
-			ColorPickerFrame:SetColorRGB(r,g,b)
-
-			if not colorCancelFunc then
-				colorCancelFunc = function()
-					if t.hasAlpha then
-						if type(t.set) == "function" then
-							if t.passValue then
-								t.set(t.passValue, t.r,t.g,t.b,t.a)
-							else
-								t.set(t.r,t.g,t.b,t.a)
-							end
-						else
-							if type(t.handler[t.get]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get)))
-							end
-							if t.passValue then
-								t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b,t.a)
-							else
-								t.handler[t.set](t.handler, t.r,t.g,t.b,t.a)
-							end
-						end
-					else
-						if type(t.set) == "function" then
-							if t.passValue then
-								t.set(t.passValue, t.r,t.g,t.b)
-							else
-								t.set(t.r,t.g,t.b)
-							end
-						else
-							if type(t.handler[t.set]) ~= "function" then
-								AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set)))
-							end
-							if t.passValue then
-								t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b)
-							else
-								t.handler[t.set](t.handler, t.r,t.g,t.b)
-							end
-						end
-					end
-					for k,v in pairs(t) do
-						t[k] = nil
-					end
-					ColorPickerFrame.cancelFunc = nil
-					ColorPickerFrame.func = nil
-					ColorPickerFrame.opacityFunc = nil
-				end
-			end
-
-			ColorPickerFrame.cancelFunc = colorCancelFunc
-
-			ShowUIPanel(ColorPickerFrame)
-		end
-		return
-	elseif kind == "group" then
-		if #args == 0 then
-			printUsage(self, handler, realOptions, options, path, args, passValue)
-		else
-			-- invalid argument
-			print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(args[1], path), realOptions.cmdName or realOptions.name or self)
-		end
-		return
-	end
-	this = _G_this
-	if Dewdrop then
-		Dewdrop:Refresh()
-	end
-end
-
-local external
-local tmp
-function AceConsole:RegisterChatCommand(...) -- slashCommands, options, name
-	local slashCommands, options, name
-	if type((...)) == "string" then
-		if not tmp then
-			tmp = {}
-		else
-			for i in ipairs(tmp) do
-				tmp[i] = nil
-			end
-		end
-		for i = 1, select('#', ...)+1 do
-			local v = select(i, ...)
-			if type(v) == "string" then
-				tmp[#tmp+1] = v
-			else
-				slashCommands = tmp
-				options = v
-				name = select(i+1, ...)
-				break
-			end
-		end
-	else
-		slashCommands, options, name = ...
-	end
-	if type(slashCommands) ~= "table" and slashCommands ~= false then
-		AceConsole:error("Bad argument #2 to `RegisterChatCommand' (expected table, got %s)", type(slashCommands))
-	end
-	if not slashCommands and type(name) ~= "string" then
-		AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string, got %s)", type(name))
-	end
-	if type(options) ~= "table" and type(options) ~= "function" and options ~= nil then
-		AceConsole:error("Bad argument #3 to `RegisterChatCommand' (expected table, function, or nil, got %s)", type(options))
-	end
-	if name then
-		if type(name) ~= "string" then
-			AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string or nil, got %s)", type(name))
-		elseif not name:find("^%w+$") or name:upper() ~= name or name:len() == 0 then
-			AceConsole:error("Argument #4 must be an uppercase, letters-only string with at least 1 character")
-		end
-	end
-	if slashCommands then
-		if #slashCommands == 0 then
-			AceConsole:error("Argument #2 to `RegisterChatCommand' must include at least one string")
-		end
-
-		for k,v in pairs(slashCommands) do
-			if type(k) ~= "number" then
-				AceConsole:error("All keys in argument #2 to `RegisterChatCommand' must be numbers")
-			end
-			if type(v) ~= "string" then
-				AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be strings")
-			elseif not v:find("^/[A-Za-z][A-Za-z0-9_]*$") then
-				AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be in the form of \"/word\"")
-			end
-		end
-	end
-
-	if not options then
-		options = {
-			type = 'group',
-			args = {},
-			handler = self
-		}
-	end
-
-	if type(options) == "table" then
-		local err, position = validateOptions(options)
-		if err then
-			if position then
-				AceConsole:error(position .. ": " .. err)
-			else
-				AceConsole:error(err)
-			end
-		end
-
-		if not options.handler then
-			options.handler = self
-		end
-
-		if options.handler == self and options.type:lower() == "group" and self.class then
-			AceConsole:InjectAceOptionsTable(self, options)
-		end
-	end
-
-	local chat
-	if slashCommands then
-		chat = slashCommands[1]
-	else
-		chat = _G["SLASH_"..name..1]
-	end
-
-	local handler
-	if type(options) == "function" then
-		handler = options
-		for k,v in pairs(_G) do
-			if handler == v then
-				local k = k
-				handler = function(msg)
-					return _G[k](msg)
-				end
-			end
-		end
-	else
-		function handler(msg)
-			handlerFunc(self, chat, msg, options)
-		end
-	end
-
-	if not _G.SlashCmdList then
-		_G.SlashCmdList = {}
-	end
-
-	if not name and type(slashCommands) == "table" and type(slashCommands[1]) == "string" then
-		name = slashCommands[1]:gsub("%A", ""):upper()
-	end
-
-	if not name then
-		local A = ('A'):byte()
-		repeat
-			name = string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1)
-		until not _G.SlashCmdList[name]
-	end
-
-	if slashCommands then
-		if _G.SlashCmdList[name] then
-			local i = 0
-			while true do
-				i = i + 1
-				if _G["SLASH_"..name..i] then
-					_G["SLASH_"..name..i] = nil
-				else
-					break
-				end
-			end
-		end
-
-		local i = 0
-		for _,command in ipairs(slashCommands) do
-			i = i + 1
-			_G["SLASH_"..name..i] = command
-			if command:lower() ~= command then
-				i = i + 1
-				_G["SLASH_"..name..i] = command:lower()
-			end
-		end
-	end
-	_G.SlashCmdList[name] = handler
-	if self ~= AceConsole and self.slashCommand == nil then
-		self.slashCommand = chat
-	end
-
-	if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then
-		external(AceConsole, "AceEvent-2.0", AceLibrary("AceEvent-2.0"))
-	end
-	if AceEvent then
-		if not AceConsole.nextAddon then
-			AceConsole.nextAddon = {}
-		end
-		if type(options) == "table" then
-			AceConsole.nextAddon[self] = options
-			if not self.playerLogin then
-				AceConsole:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true)
-			end
-		end
-	end
-
-	AceConsole.registry[name] = options
-
-	if slashCommands == tmp then
-		for i in ipairs(tmp) do
-			tmp[i] = nil
-		end
-	end
-end
-
-function AceConsole:InjectAceOptionsTable(handler, options)
-	self:argCheck(handler, 2, "table")
-	self:argCheck(options, 3, "table")
-	if options.type:lower() ~= "group" then
-		self:error('Cannot inject into options table argument #3 if its type is not "group"')
-	end
-	if options.handler ~= nil and options.handler ~= handler then
-		self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2")
-	end
-	options.handler = handler
-	local class = handler.class
-	if not AceLibrary:HasInstance("AceOO-2.0") or not class then
-		if Rock then
-			-- possible Rock object
-			for mixin in Rock:IterateObjectMixins(handler) do
-				if type(mixin.GetAceOptionsDataTable) == "function" then
-					local t = mixin:GetAceOptionsDataTable(handler)
-					for k,v in pairs(t) do
-						if type(options.args) ~= "table" then
-							options.args = {}
-						end
-						if options.args[k] == nil then
-							options.args[k] = v
-						end
-					end
-				end
-			end
-		end
-	else
-		-- Ace2 object
-		while class and class ~= AceLibrary("AceOO-2.0").Class do
-			if type(class.GetAceOptionsDataTable) == "function" then
-				local t = class:GetAceOptionsDataTable(handler)
-				for k,v in pairs(t) do
-					if type(options.args) ~= "table" then
-						options.args = {}
-					end
-					if options.args[k] == nil then
-						options.args[k] = v
-					end
-				end
-			end
-			local mixins = class.mixins
-			if mixins then
-				for mixin in pairs(mixins) do
-					if type(mixin.GetAceOptionsDataTable) == "function" then
-						local t = mixin:GetAceOptionsDataTable(handler)
-						for k,v in pairs(t) do
-							if type(options.args) ~= "table" then
-								options.args = {}
-							end
-							if options.args[k] == nil then
-								options.args[k] = v
-							end
-						end
-					end
-				end
-			end
-			class = class.super
-		end
-	end
-	
-	return options
-end
-
-function AceConsole:PLAYER_LOGIN()
-	self.playerLogin = true
-	for addon, options in pairs(self.nextAddon) do
-		local err, position = validateOptionsMethods(addon, options)
-		if err then
-			if position then
-				geterrorhandler()(tostring(addon) .. ": AceConsole: " .. position .. ": " .. err)
-			else
-				geterrorhandler()(tostring(addon) .. ": AceConsole: " .. err)
-			end
-		end
-		self.nextAddon[addon] = nil
-	end
-end
-
-function AceConsole:TabCompleteInfo(cmdpath)
-	local cmd =  cmdpath:match("(/%S+)")
-	if not cmd then
-		return
-	end
-	local path = cmdpath:sub(cmd:len() + 2)
-	for name in pairs(SlashCmdList) do --global
-		if AceConsole.registry[name] then
-			local i = 0
-			while true do
-				i = i + 1
-				local scmd = _G["SLASH_"..name..i]
-				if not scmd then break end
-				if cmd == scmd then
-					return name, cmd, path
-				end
-			end
-		end
-	end
-end
-
-function external(self, major, instance)
-	if major == "AceEvent-2.0" then
-		if not AceEvent then
-			AceEvent = instance
-
-			AceEvent:embed(self)
-		end
-	elseif major == "AceTab-2.0" then
-		instance:RegisterTabCompletion("AceConsole", "%/.*", function(t, cmdpath, pos)
-			local name, cmd, path = self:TabCompleteInfo(cmdpath:sub(1, pos))
-
-			if not self.registry[name] then
-				return false
-			else
-				local validArgs, _, _, handler = findTableLevel(self, self.registry[name], cmd, path or "")
-				if validArgs.args then
-					for arg, v in pairs(validArgs.args) do
-						local hidden = v.hidden
-						local handler = v.handler or handler
-						if hidden then
-							if type(hidden) == "function" then
-								hidden = hidden(v.passValue)
-							elseif type(hidden) == "string" then
-								local f = hidden
-								local neg = f:match("^~(.-)$")
-								if neg then
-									f = neg
-								end
-								if type(handler[f]) ~= "function" then
-									self:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-								end
-								hidden = handler[f](handler, v.passValue)
-								if neg then
-									hidden = not hidden
-								end
-							end
-						end
-						local disabled = hidden or v.disabled
-						if disabled then
-							if type(disabled) == "function" then
-								disabled = disabled(v.passValue)
-							elseif type(disabled) == "string" then
-								local f = disabled
-								local neg = f:match("^~(.-)$")
-								if neg then
-									f = neg
-								end
-								if type(handler[f]) ~= "function" then
-									self:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f)))
-								end
-								disabled = handler[f](handler, v.passValue)
-								if neg then
-									disabled = not disabled
-								end
-							end
-						end
-						if not hidden and not disabled and v.type ~= "header" then
-							table.insert(t, (tostring(arg):gsub("%s", "-")))
-						end
-					end
-				end
-			end
-		end, function(u, matches, gcs, cmdpath)
-			local name, cmd, path = self:TabCompleteInfo(cmdpath)
-			if self.registry[name] then
-				local validArgs, path2, argwork, handler = findTableLevel(self, self.registry[name], cmd, path)
-				printUsage(self, validArgs.handler or handler, self.registry[name], validArgs, path2, argwork, argwork[#argwork], not gcs or gcs ~= "", gcs)
-			end
-		end)
-	elseif major == "Dewdrop-2.0" then
-		Dewdrop = instance
-	end
-end
-
-local function activate(self, oldLib, oldDeactivate)
-	AceConsole = self
-
-	if oldLib then
-		self.registry = oldLib.registry
-		self.nextAddon = oldLib.nextAddon
-	end
-
-	if not self.registry then
-		self.registry = {}
-	else
-		for name,options in pairs(self.registry) do
-			self:RegisterChatCommand(false, options, name)
-		end
-	end
-
-	self:RegisterChatCommand("/reload", "/rl", "/reloadui", ReloadUI, "RELOAD")
-	self:RegisterChatCommand("/gm", ToggleHelpFrame, "GM")
-	local t = { "/print", "/echo" }
-	local _,_,_,enabled,loadable = GetAddOnInfo("DevTools")
-	if not enabled and not loadable then
-		table.insert(t, "/dump")
-	end
-	self:RegisterChatCommand(t, function(text)
-		text = text:trim():match("^(.-);*$")
-		local f, err = loadstring("AceLibrary('AceConsole-2.0'):PrintLiteral(" .. text .. ")")
-		if not f then
-			self:Print("|cffff0000Error:|r", err)
-		else
-			f()
-		end
-	end, "PRINT")
-
-	self:activate(oldLib, oldDeactivate)
-
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-AceLibrary:Register(AceConsole, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/lib/AceConsole-2.0/AceConsole-2.0.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceConsole-2.0
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary, AceEvent-2.0, AceOO-2.0
- 
-AceConsole-2.0.lua
--- a/lib/AceDB-2.0/AceDB-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2187 +0,0 @@
---[[
-Name: AceDB-2.0
-Revision: $Rev: 46764 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceDB-2.0
-SVN: http://svn.wowace.com/root/trunk/Ace2/AceDB-2.0
-Description: Mixin to allow for fast, clean, and featureful saved variable
-             access.
-Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "AceDB-2.0"
-local MINOR_VERSION = "$Revision: 46764 $"
-
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
-
-local function safecall(func,...)
-	local success, err = pcall(func,...)
-	if not success then geterrorhandler()(err) end
-end
-
-local ACTIVE, ENABLED, STATE, TOGGLE_ACTIVE, MAP_ACTIVESUSPENDED, SET_PROFILE, SET_PROFILE_USAGE, PROFILE, PLAYER_OF_REALM, CHOOSE_PROFILE_DESC, CHOOSE_PROFILE_GUI, COPY_PROFILE_DESC, COPY_PROFILE_GUI, OTHER_PROFILE_DESC, OTHER_PROFILE_GUI, OTHER_PROFILE_USAGE, RESET_PROFILE, RESET_PROFILE_DESC, CHARACTER_COLON, REALM_COLON, CLASS_COLON, DEFAULT, ALTERNATIVE
-
--- Move these into "enUS" when they've been translated in all other locales
-local DELETE_PROFILE = "Delete"
-local DELETE_PROFILE_DESC = "Deletes a profile. Note that no check is made whether this profile is in use by other characters or not."
-local DELETE_PROFILE_USAGE = "<profile name>"
-
-if GetLocale() == "deDE" then
-	ACTIVE = "Aktiv"
-	ENABLED = "Aktiviert"
-	STATE = "Status"
-	TOGGLE_ACTIVE = "Stoppt/Aktiviert dieses Addon."
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Aktiv|r", [false] = "|cffff0000Gestoppt|r" }
-	SET_PROFILE = "Setzt das Profil f\195\188r dieses Addon."
-	SET_PROFILE_USAGE = "{Charakter || Klasse || Realm || <Profilname>}"
-	PROFILE = "Profil"
-	PLAYER_OF_REALM = "%s von %s"
-	CHOOSE_PROFILE_DESC = "W\195\164hle ein Profil."
-	CHOOSE_PROFILE_GUI = "W\195\164hle"
-	COPY_PROFILE_DESC = "Kopiert Einstellungen von einem anderem Profil."
-	COPY_PROFILE_GUI = "Kopiere von"
-	OTHER_PROFILE_DESC = "W\195\164hle ein anderes Profil."
-	OTHER_PROFILE_GUI = "Anderes"
-	OTHER_PROFILE_USAGE = "<Profilname>"
-	RESET_PROFILE = "Reset profile" -- fix
-	RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
-
-	CHARACTER_COLON = "Charakter: "
-	REALM_COLON = "Realm: "
-	CLASS_COLON = "Klasse: "
-
-	DEFAULT = "Default" -- fix
-	ALTERNATIVE = "Alternative" -- fix
-elseif GetLocale() == "frFR" then
-	ACTIVE = "Actif"
-	ENABLED = "Activ\195\169"
-	STATE = "Etat"
-	TOGGLE_ACTIVE = "Suspend/active cet addon."
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Actif|r", [false] = "|cffff0000Suspendu|r" }
-	SET_PROFILE = "S\195\169lectionne le profil pour cet addon."
-	SET_PROFILE_USAGE = "{perso || classe || royaume || <nom de profil>}"
-	PROFILE = "Profil"
-	PLAYER_OF_REALM = "%s de %s"
-	CHOOSE_PROFILE_DESC = "Choisissez un profil."
-	CHOOSE_PROFILE_GUI = "Choix"
-	COPY_PROFILE_DESC = "Copier les param\195\168tres d'un autre profil."
-	COPY_PROFILE_GUI = "Copier \195\160 partir de"
-	OTHER_PROFILE_DESC = "Choisissez un autre profil."
-	OTHER_PROFILE_GUI = "Autre"
-	OTHER_PROFILE_USAGE = "<nom de profil>"
-	RESET_PROFILE = "Reset profile" -- fix
-	RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
-
-	CHARACTER_COLON = "Personnage: "
-	REALM_COLON = "Royaume: "
-	CLASS_COLON = "Classe: "
-
-	DEFAULT = "Default" -- fix
-	ALTERNATIVE = "Alternative" -- fix
-elseif GetLocale() == "koKR" then
-	DELETE_PROFILE = "삭제"
-	DELETE_PROFILE_DESC = "프로필을 삭제합니다."
-	DELETE_PROFILE_USAGE = "<프로필명>"
-
-	ACTIVE = "사용"
-	ENABLED = "사용"
-	STATE = "상태"
-	TOGGLE_ACTIVE = "이 애드온 중지/다시 시작"
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00사용|r", [false] = "|cffff0000중지|r" }
-	SET_PROFILE = "이 애드온에 프로필 설정"
-	SET_PROFILE_USAGE = "{캐릭터명 || 직업 || 서버명 || <프로필명>}"
-	PROFILE = "프로필"
-	PLAYER_OF_REALM = "%s (%s 서버)"
-	CHOOSE_PROFILE_DESC = "프로필을 선택합니다."
-	CHOOSE_PROFILE_GUI = "선택"
-	COPY_PROFILE_DESC = "다른 프로필 설정을 복사합니다."
-	COPY_PROFILE_GUI = "복사"
-	OTHER_PROFILE_DESC = "다른 프로필을 선택합니다."
-	OTHER_PROFILE_GUI = "기타"
-	OTHER_PROFILE_USAGE = "<프로필명>"
-	RESET_PROFILE = "프로필 초기화"
-	RESET_PROFILE_DESC = "모든 세팅에서 현재 프로필을 초기화 합니다."
-
-	CHARACTER_COLON = "캐릭터: "
-	REALM_COLON = "서버: "
-	CLASS_COLON = "직업: "
-
-	DEFAULT = "기본값"
-	ALTERNATIVE = "대체"
-elseif GetLocale() == "zhTW" then
-	DELETE_PROFILE = "刪除"
-	DELETE_PROFILE_DESC = "刪除記錄檔。注意,有可能別的角色也使用這個記錄檔。"
-	DELETE_PROFILE_USAGE = "<記錄檔名稱>"
-
-	ACTIVE = "啟動"
-	ENABLED = "啟用"
-	STATE = "狀態"
-	TOGGLE_ACTIVE = "暫停/繼續使用這個插件。"
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00啟動|r", [false] = "|cffff0000已暫停|r" }
-	SET_PROFILE = "設定這插件的記錄檔。"
-	SET_PROFILE_USAGE = "{角色 || 職業 || 伺服器 || <記錄檔名稱>}"
-	PROFILE = "記錄檔"
-	PLAYER_OF_REALM = "%s - %s"
-	CHOOSE_PROFILE_DESC = "選擇一個記錄檔。"
-	CHOOSE_PROFILE_GUI = "選擇"
-	COPY_PROFILE_DESC = "由其他記錄檔複製設定。"
-	COPY_PROFILE_GUI = "複製自"
-	OTHER_PROFILE_DESC = "選擇其他記錄檔。"
-	OTHER_PROFILE_GUI = "其他"
-	OTHER_PROFILE_USAGE = "<記錄檔名稱>"
-	RESET_PROFILE = "重設記錄檔"
-	RESET_PROFILE_DESC = "清除目前的記錄檔上的所有設定。"
-
-	CHARACTER_COLON = "角色: "
-	REALM_COLON = "伺服器: "
-	CLASS_COLON = "職業: "
-
-	DEFAULT = "預設"
-	ALTERNATIVE = "替代"
-elseif GetLocale() == "zhCN" then
-	ACTIVE = "\230\156\137\230\149\136"
-	ENABLED = "\229\144\175\231\148\168"
-	STATE = "\231\138\182\230\128\129"
-	TOGGLE_ACTIVE = "\230\154\130\229\129\156/\230\129\162\229\164\141 \230\173\164\230\143\146\228\187\182."
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00\230\156\137\230\149\136|r", [false] = "|cffff0000\230\154\130\229\129\156|r" }
-	SET_PROFILE = "\232\174\190\231\189\174\233\133\141\231\189\174\230\150\135\228\187\182\228\184\186\232\191\153\230\143\146\228\187\182."
-	SET_PROFILE_USAGE = "{\229\173\151\231\172\166 || \233\128\137\228\187\182\231\177\187 || \229\159\159 || <\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>}"
-	PROFILE = "\233\133\141\231\189\174\230\150\135\228\187\182"
-	PLAYER_OF_REALM = "%s \231\154\132 %s"
-	CHOOSE_PROFILE_DESC = "\233\128\137\230\139\169\233\133\141\231\189\174\230\150\135\228\187\182."
-	CHOOSE_PROFILE_GUI = "\233\128\137\230\139\169"
-	COPY_PROFILE_DESC = "\229\164\141\229\136\182\232\174\190\231\189\174\228\187\142\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182."
-	COPY_PROFILE_GUI = "\229\164\141\229\136\182\228\187\142"
-	OTHER_PROFILE_DESC = "\233\128\137\230\139\169\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182."
-	OTHER_PROFILE_GUI = "\229\133\182\228\187\150"
-	OTHER_PROFILE_USAGE = "<\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>"
-	RESET_PROFILE = "Reset profile" -- fix
-	RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
-
-	CHARACTER_COLON = "\229\173\151\231\172\166: "
-	REALM_COLON = "\229\159\159: "
-	CLASS_COLON = "\233\128\137\228\187\182\231\177\187: "
-
-	DEFAULT = "Default" -- fix
-	ALTERNATIVE = "Alternative" -- fix
-elseif GetLocale() == "esES" then
-	ACTIVE = "Activo"
-	ENABLED = "Activado"
-	STATE = "Estado"
-	TOGGLE_ACTIVE = "Parar/Continuar este accesorio"
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Activo|r", [false] = "|cffff0000Parado|r" }
-	SET_PROFILE = "Selecciona el perfil para este accesorio."
-	SET_PROFILE_USAGE = "{perso || clase || reino || <nombre del perfil>}"
-	PROFILE = "Perfil"
-	PLAYER_OF_REALM = "%s de %s"
-	CHOOSE_PROFILE_DESC = "Elige un perfil."
-	CHOOSE_PROFILE_GUI = "Elige"
-	COPY_PROFILE_DESC = "Copiar de un perfil a otro"
-	COPY_PROFILE_GUI = "Copiar desde"
-	OTHER_PROFILE_DESC = "Elige otro perfil."
-	OTHER_PROFILE_GUI = "Otro"
-	OTHER_PROFILE_USAGE = "<nombre del perfil>"
-	RESET_PROFILE = "Reset profile" -- fix
-	RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
-
-	CHARACTER_COLON = "Personaje: "
-	REALM_COLON = "Reino: "
-	CLASS_COLON = "Clase: "
-
-	DEFAULT = "Por defecto"
-	ALTERNATIVE = "Alternativo"
-else -- enUS
-	ACTIVE = "Active"
-	ENABLED = "Enabled"
-	STATE = "State"
-	TOGGLE_ACTIVE = "Suspend/resume this addon."
-	MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" }
-	SET_PROFILE = "Set profile for this addon."
-	SET_PROFILE_USAGE = "{char || class || realm || <profile name>}"
-	PROFILE = "Profile"
-	PLAYER_OF_REALM = "%s of %s"
-	CHOOSE_PROFILE_DESC = "Choose a profile."
-	CHOOSE_PROFILE_GUI = "Choose"
-	COPY_PROFILE_DESC = "Copy settings from another profile."
-	COPY_PROFILE_GUI = "Copy from"
-	OTHER_PROFILE_DESC = "Choose another profile."
-	OTHER_PROFILE_GUI = "Other"
-	OTHER_PROFILE_USAGE = "<profile name>"
-	RESET_PROFILE = "Reset profile"
-	RESET_PROFILE_DESC = "Clear all settings of the current profile."
-
-	CHARACTER_COLON = "Character: "
-	REALM_COLON = "Realm: "
-	CLASS_COLON = "Class: "
-
-	DEFAULT = "Default"
-	ALTERNATIVE = "Alternative"
-end
-local convertFromOldCharID
-do
-	local matchStr = "^" .. PLAYER_OF_REALM:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1"):gsub("%%s", "(.+)") .. "$"
-	function convertFromOldCharID(str)
-		local player, realm = str:match(matchStr)
-		if not player then
-			return str
-		end
-		return player .. " - " .. realm
-	end
-end
-
-local AceOO = AceLibrary("AceOO-2.0")
-local AceEvent
-local Mixin = AceOO.Mixin
-local AceDB = Mixin {
-						"RegisterDB",
-						"RegisterDefaults",
-						"ResetDB",
-						"SetProfile",
-						"GetProfile",
-						"CopyProfileFrom",
-						"DeleteProfile",
-						"ToggleActive",
-						"IsActive",
-						"AcquireDBNamespace",
-					}
-local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0")
-
-local _G = getfenv(0)
-
-local function inheritDefaults(t, defaults)
-	if not defaults then
-		return t
-	end
-	for k,v in pairs(defaults) do
-		if k == "*" or k == "**" then
-			local v = v
-			if type(v) == "table" then
-				setmetatable(t, {
-					__index = function(self, key)
-						if key == nil then
-							return nil
-						end
-						self[key] = {}
-						inheritDefaults(self[key], v)
-						return self[key]
-					end
-				} )
-			else
-				setmetatable(t, {
-					__index = function(self, key)
-						if key == nil then
-							return nil
-						end
-						self[key] = v
-						return self[key]
-					end
-				} )
-			end
-			for key in pairs(t) do
-				if (defaults[key] == nil or key == k) and type(t[key]) == "table" then
-					inheritDefaults(t[key], v)
-				end
-			end
-		else
-			if type(v) == "table" then
-				if type(rawget(t, k)) ~= "table" then
-					t[k] = {}
-				end
-				inheritDefaults(t[k], v)
-				if defaults["**"] then
-					inheritDefaults(t[k], defaults["**"])
-				end
-			elseif rawget(t, k) == nil then
-				t[k] = v
-			end
-		end
-	end
-	return t
-end
-
-local _,race = UnitRace("player")
-local faction
-if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" or race == "BloodElf" then
-	faction = FACTION_HORDE
-else
-	faction = FACTION_ALLIANCE
-end
-local server = GetRealmName():trim()
-local charID = UnitName("player") .. " - " .. server
-local realmID = server .. " - " .. faction
-local classID = UnitClass("player")
-
-AceDB.CHAR_ID = charID
-AceDB.REALM_ID = realmID
-AceDB.CLASS_ID = classID
-
-AceDB.FACTION = faction
-AceDB.REALM = server
-AceDB.NAME = UnitName("player")
-
-local new, del
-do
-	local list = setmetatable({}, {__mode="k"})
-	function new()
-		local t = next(list)
-		if t then
-			list[t] = nil
-			return t
-		else
-			return {}
-		end
-	end
-
-	function del(t)
-		setmetatable(t, nil)
-		for k in pairs(t) do
-			t[k] = nil
-		end
-		list[t] = true
-	end
-end
-
-local caseInsensitive_mt = {
-	__index = function(self, key)
-		if type(key) ~= "string" then
-			return nil
-		end
-		local lowerKey = key:lower()
-		for k,v in pairs(self) do
-			if k:lower() == lowerKey then
-				return self[k]
-			end
-		end
-	end,
-	__newindex = function(self, key, value)
-		if type(key) ~= "string" then
-			return error("table index is nil", 2)
-		end
-		local lowerKey = key:lower()
-		for k in pairs(self) do
-			if k:lower() == lowerKey then
-				rawset(self, k, nil)
-				rawset(self, key, value)
-				return
-			end
-		end
-		rawset(self, key, value)
-	end
-}
-
-local db_mt = { __index = function(db, key)
-	if key == "char" then
-		if db.charName then
-			if type(_G[db.charName]) ~= "table" then
-				_G[db.charName] = {}
-			end
-			if type(_G[db.charName].global) ~= "table" then
-				_G[db.charName].global = {}
-			end
-			rawset(db, 'char', _G[db.charName].global)
-		else
-			if type(db.raw.chars) ~= "table" then
-				db.raw.chars = {}
-			end
-			local id = charID
-			if type(db.raw.chars[id]) ~= "table" then
-				db.raw.chars[id] = {}
-			end
-			rawset(db, 'char', db.raw.chars[id])
-		end
-		if db.defaults and db.defaults.char then
-			inheritDefaults(db.char, db.defaults.char)
-		end
-		return db.char
-	elseif key == "realm" then
-		if type(db.raw.realms) ~= "table" then
-			db.raw.realms = {}
-		end
-		local id = realmID
-		if type(db.raw.realms[id]) ~= "table" then
-			db.raw.realms[id] = {}
-		end
-		rawset(db, 'realm', db.raw.realms[id])
-		if db.defaults and db.defaults.realm then
-			inheritDefaults(db.realm, db.defaults.realm)
-		end
-		return db.realm
-	elseif key == "server" then
-		if type(db.raw.servers) ~= "table" then
-			db.raw.servers = {}
-		end
-		local id = server
-		if type(db.raw.servers[id]) ~= "table" then
-			db.raw.servers[id] = {}
-		end
-		rawset(db, 'server', db.raw.servers[id])
-		if db.defaults and db.defaults.server then
-			inheritDefaults(db.server, db.defaults.server)
-		end
-		return db.server
-	elseif key == "account" then
-		if type(db.raw.account) ~= "table" then
-			db.raw.account = {}
-		end
-		rawset(db, 'account', db.raw.account)
-		if db.defaults and db.defaults.account then
-			inheritDefaults(db.account, db.defaults.account)
-		end
-		return db.account
-	elseif key == "faction" then
-		if type(db.raw.factions) ~= "table" then
-			db.raw.factions = {}
-		end
-		local id = faction
-		if type(db.raw.factions[id]) ~= "table" then
-			db.raw.factions[id] = {}
-		end
-		rawset(db, 'faction', db.raw.factions[id])
-		if db.defaults and db.defaults.faction then
-			inheritDefaults(db.faction, db.defaults.faction)
-		end
-		return db.faction
-	elseif key == "class" then
-		if type(db.raw.classes) ~= "table" then
-			db.raw.classes = {}
-		end
-		local id = classID
-		if type(db.raw.classes[id]) ~= "table" then
-			db.raw.classes[id] = {}
-		end
-		rawset(db, 'class', db.raw.classes[id])
-		if db.defaults and db.defaults.class then
-			inheritDefaults(db.class, db.defaults.class)
-		end
-		return db.class
-	elseif key == "profile" then
-		if type(db.raw.profiles) ~= "table" then
-			db.raw.profiles = setmetatable({}, caseInsensitive_mt)
-		else
-			setmetatable(db.raw.profiles, caseInsensitive_mt)
-		end
-		local id = db.raw.currentProfile[charID]
-		if id == "char" then
-			id = "char/" .. charID
-		elseif id == "class" then
-			id = "class/" .. classID
-		elseif id == "realm" then
-			id = "realm/" .. realmID
-		end
-		if type(db.raw.profiles[id]) ~= "table" then
-			db.raw.profiles[id] = {}
-		end
-		rawset(db, 'profile', db.raw.profiles[id])
-		if db.defaults and db.defaults.profile then
-			inheritDefaults(db.profile, db.defaults.profile)
-		end
-		return db.profile
-	elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then
-		return nil
-	end
-	error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
-end, __newindex = function(db, key, value)
-	error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
-end }
-
-local function RecalculateAceDBCopyFromList(target)
-	local db = target.db
-	local t = target['acedb-profile-copylist']
-	for k,v in pairs(t) do
-		t[k] = nil
-	end
-	local _,currentProfile = AceDB.GetProfile(target)
-	if db and db.raw then
-		if db.raw.profiles then
-			for k in pairs(db.raw.profiles) do
-				if currentProfile ~= k then
-					if k:find("^char/") then
-						local name = k:sub(6)
-						local player, realm = name:match("^(.*) %- (.*)$")
-						if player then
-							name = PLAYER_OF_REALM:format(player, realm)
-						end
-						t[k] = CHARACTER_COLON .. name
-					elseif k:find("^realm/") then
-						local name = k:sub(7)
-						t[k] = REALM_COLON .. name
-					elseif k:find("^class/") then
-						local name = k:sub(7)
-						t[k] = CLASS_COLON .. name
-					else
-						t[k] = k
-					end
-				end
-			end
-		end
-		if db.raw.namespaces then
-			for _,n in pairs(db.raw.namespaces) do
-				if n.profiles then
-					for k in pairs(n.profiles) do
-						if currentProfile ~= k then
-							if k:find('^char/') then
-								local name = k:sub(6)
-								local player, realm = name:match("^(.*) %- (.*)$")
-								if player then
-									name = PLAYER_OF_REALM:format(player, realm)
-								end
-								t[k] = CHARACTER_COLON .. name
-							elseif k:find('^realm/') then
-								local name = k:sub(7)
-								t[k] = REALM_COLON .. name
-							elseif k:find('^class/') then
-								local name = k:sub(7)
-								t[k] = CLASS_COLON .. name
-							else
-								t[k] = k
-							end
-						end
-					end
-				end
-			end
-		end
-	end
-	if t.Default then
-		t.Default = DEFAULT
-	end
-	if t.Alternative then
-		t.Alternative = ALTERNATIVE
-	end
-end
-
-local function RecalculateAceDBProfileList(target)
-	local t = target['acedb-profile-list']
-	for k,v in pairs(t) do
-		t[k] = nil
-	end
-	t.char = CHARACTER_COLON .. PLAYER_OF_REALM:format(UnitName("player"), server)
-	t.realm = REALM_COLON .. realmID
-	t.class = CLASS_COLON .. classID
-	t.Default = DEFAULT
-	local db = target.db
-	if db and db.raw then
-		if db.raw.profiles then
-			for k in pairs(db.raw.profiles) do
-				if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then
-					t[k] = k
-				end
-			end
-		end
-		if db.raw.namespaces then
-			for _,n in pairs(db.raw.namespaces) do
-				if n.profiles then
-					for k in pairs(n.profiles) do
-						if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then
-							t[k] = k
-						end
-					end
-				end
-			end
-		end
-		local curr = db.raw.currentProfile and db.raw.currentProfile[charID]
-		if curr and not t[curr] then
-			t[curr] = curr
-		end
-	end
-	if t.Alternative then
-		t.Alternative = ALTERNATIVE
-	end
-end
-
-local CrawlForSerialization
-local CrawlForDeserialization
-
-local function SerializeObject(o)
-	local t = { o:Serialize() }
-	CrawlForSerialization(t)
-	t[0] = o.class:GetLibraryVersion()
-	return t
-end
-
-local function DeserializeObject(t)
-	CrawlForDeserialization(t)
-	local className = t[0]
-	t[0] = nil
-	return AceLibrary(className):Deserialize(unpack(t))
-end
-
-local function IsSerializable(t)
-	return AceOO.inherits(t, AceOO.Class) and t.class and type(t.class.Deserialize) == "function" and type(t.Serialize) == "function" and type(t.class.GetLibraryVersion) == "function"
-end
-
-function CrawlForSerialization(t)
-	local tmp = new()
-	for k,v in pairs(t) do
-		tmp[k] = v
-	end
-	for k,v in pairs(tmp) do
-		if type(v) == "table" and type(rawget(v, 0)) ~= "userdata" then
-			if IsSerializable(v) then
-				v = SerializeObject(v)
-				t[k] = v
-			else
-				CrawlForSerialization(v)
-			end
-		end
-		if type(k) == "table" and type(rawget(k, 0)) ~= "userdata" then
-			if IsSerializable(k) then
-				t[k] = nil
-				t[SerializeObject(k)] = v
-			else
-				CrawlForSerialization(k)
-			end
-		end
-		tmp[k] = nil
-		k = nil
-	end
-	tmp = del(tmp)
-end
-
-local function IsDeserializable(t)
-	return type(rawget(t, 0)) == "string" and AceLibrary:HasInstance(rawget(t, 0))
-end
-
-function CrawlForDeserialization(t)
-	local tmp = new()
-	for k,v in pairs(t) do
-		tmp[k] = v
-	end
-	for k,v in pairs(tmp) do
-		if type(v) == "table" then
-			if IsDeserializable(v) then
-				t[k] = DeserializeObject(v)
-				del(v)
-				v = t[k]
-			elseif type(rawget(v, 0)) ~= "userdata" then
-				CrawlForDeserialization(v)
-			end
-		end
-		if type(k) == "table" then
-			if IsDeserializable(k) then
-				t[k] = nil
-				t[DeserializeObject(k)] = v
-				del(k)
-			elseif type(rawget(k, 0)) ~= "userdata" then
-				CrawlForDeserialization(k)
-			end
-		end
-		tmp[k] = nil
-		k = nil
-	end
-	tmp = del(tmp)
-end
-
-local namespace_mt = { __index = function(namespace, key)
-	local db = namespace.db
-	local name = namespace.name
-	if key == "char" then
-		if db.charName then
-			if type(_G[db.charName]) ~= "table" then
-				_G[db.charName] = {}
-			end
-			if type(_G[db.charName].namespaces) ~= "table" then
-				_G[db.charName].namespaces = {}
-			end
-			if type(_G[db.charName].namespaces[name]) ~= "table" then
-				_G[db.charName].namespaces[name] = {}
-			end
-			rawset(namespace, 'char', _G[db.charName].namespaces[name])
-		else
-			if type(db.raw.namespaces) ~= "table" then
-				db.raw.namespaces = {}
-			end
-			if type(db.raw.namespaces[name]) ~= "table" then
-				db.raw.namespaces[name] = {}
-			end
-			if type(db.raw.namespaces[name].chars) ~= "table" then
-				db.raw.namespaces[name].chars = {}
-			end
-			local id = charID
-			if type(db.raw.namespaces[name].chars[id]) ~= "table" then
-				db.raw.namespaces[name].chars[id] = {}
-			end
-			rawset(namespace, 'char', db.raw.namespaces[name].chars[id])
-		end
-		if namespace.defaults and namespace.defaults.char then
-			inheritDefaults(namespace.char, namespace.defaults.char)
-		end
-		return namespace.char
-	elseif key == "realm" then
-		if type(db.raw.namespaces) ~= "table" then
-			db.raw.namespaces = {}
-		end
-		if type(db.raw.namespaces[name]) ~= "table" then
-			db.raw.namespaces[name] = {}
-		end
-		if type(db.raw.namespaces[name].realms) ~= "table" then
-			db.raw.namespaces[name].realms = {}
-		end
-		local id = realmID
-		if type(db.raw.namespaces[name].realms[id]) ~= "table" then
-			db.raw.namespaces[name].realms[id] = {}
-		end
-		rawset(namespace, 'realm', db.raw.namespaces[name].realms[id])
-		if namespace.defaults and namespace.defaults.realm then
-			inheritDefaults(namespace.realm, namespace.defaults.realm)
-		end
-		return namespace.realm
-	elseif key == "server" then
-		if type(db.raw.namespaces) ~= "table" then
-			db.raw.namespaces = {}
-		end
-		if type(db.raw.namespaces[name]) ~= "table" then
-			db.raw.namespaces[name] = {}
-		end
-		if type(db.raw.namespaces[name].servers) ~= "table" then
-			db.raw.namespaces[name].servers = {}
-		end
-		local id = server
-		if type(db.raw.namespaces[name].servers[id]) ~= "table" then
-			db.raw.namespaces[name].servers[id] = {}
-		end
-		rawset(namespace, 'server', db.raw.namespaces[name].servers[id])
-		if namespace.defaults and namespace.defaults.server then
-			inheritDefaults(namespace.server, namespace.defaults.server)
-		end
-		return namespace.server
-	elseif key == "account" then
-		if type(db.raw.namespaces) ~= "table" then
-			db.raw.namespaces = {}
-		end
-		if type(db.raw.namespaces[name]) ~= "table" then
-			db.raw.namespaces[name] = {}
-		end
-		if type(db.raw.namespaces[name].account) ~= "table" then
-			db.raw.namespaces[name].account = {}
-		end
-		rawset(namespace, 'account', db.raw.namespaces[name].account)
-		if namespace.defaults and namespace.defaults.account then
-			inheritDefaults(namespace.account, namespace.defaults.account)
-		end
-		return namespace.account
-	elseif key == "faction" then
-		if type(db.raw.namespaces) ~= "table" then
-			db.raw.namespaces = {}
-		end
-		if type(db.raw.namespaces[name]) ~= "table" then
-			db.raw.namespaces[name] = {}
-		end
-		if type(db.raw.namespaces[name].factions) ~= "table" then
-			db.raw.namespaces[name].factions = {}
-		end
-		local id = faction
-		if type(db.raw.namespaces[name].factions[id]) ~= "table" then
-			db.raw.namespaces[name].factions[id] = {}
-		end
-		rawset(namespace, 'faction', db.raw.namespaces[name].factions[id])
-		if namespace.defaults and namespace.defaults.faction then
-			inheritDefaults(namespace.faction, namespace.defaults.faction)
-		end
-		return namespace.faction
-	elseif key == "class" then
-		if type(db.raw.namespaces) ~= "table" then
-			db.raw.namespaces = {}
-		end
-		if type(db.raw.namespaces[name]) ~= "table" then
-			db.raw.namespaces[name] = {}
-		end
-		if type(db.raw.namespaces[name].classes) ~= "table" then
-			db.raw.namespaces[name].classes = {}
-		end
-		local id = classID
-		if type(db.raw.namespaces[name].classes[id]) ~= "table" then
-			db.raw.namespaces[name].classes[id] = {}
-		end
-		rawset(namespace, 'class', db.raw.namespaces[name].classes[id])
-		if namespace.defaults and namespace.defaults.class then
-			inheritDefaults(namespace.class, namespace.defaults.class)
-		end
-		return namespace.class
-	elseif key == "profile" then
-		if type(db.raw.namespaces) ~= "table" then
-			db.raw.namespaces = {}
-		end
-		if type(db.raw.namespaces[name]) ~= "table" then
-			db.raw.namespaces[name] = {}
-		end
-		if type(db.raw.namespaces[name].profiles) ~= "table" then
-			db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt)
-		else
-			setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt)
-		end
-		local id = db.raw.currentProfile[charID]
-		if id == "char" then
-			id = "char/" .. charID
-		elseif id == "class" then
-			id = "class/" .. classID
-		elseif id == "realm" then
-			id = "realm/" .. realmID
-		end
-		if type(db.raw.namespaces[name].profiles[id]) ~= "table" then
-			db.raw.namespaces[name].profiles[id] = {}
-		end
-		rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id])
-		if namespace.defaults and namespace.defaults.profile then
-			inheritDefaults(namespace.profile, namespace.defaults.profile)
-		end
-		return namespace.profile
-	elseif key == "defaults" or key == "name" or key == "db" then
-		return nil
-	end
-	error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
-end, __newindex = function(db, key, value)
-	error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
-end }
-
-local tmp = {}
-function AceDB:InitializeDB(addonName)
-	local db = self.db
-
-	if not db then
-		if addonName then
-			AceDB.addonsLoaded[addonName] = true
-		end
-		return
-	end
-
-	if db.raw then
-		-- someone manually initialized
-		return
-	end
-
-	if type(_G[db.name]) ~= "table" then
-		_G[db.name] = {}
-	else
-		CrawlForDeserialization(_G[db.name])
-	end
-	if db.charName then
-		if type(_G[db.charName]) ~= "table" then
-			_G[db.charName] = {}
-		else
-			CrawlForDeserialization(_G[db.charName])
-		end
-	end
-	rawset(db, 'raw', _G[db.name])
-	if not db.raw.currentProfile then
-		db.raw.currentProfile = {}
-	else
-		for k,v in pairs(db.raw.currentProfile) do
-			tmp[convertFromOldCharID(k)] = v
-			db.raw.currentProfile[k] = nil
-		end
-		for k,v in pairs(tmp) do
-			db.raw.currentProfile[k] = v
-			tmp[k] = nil
-		end
-	end
-	if not db.raw.currentProfile[charID] then
-		db.raw.currentProfile[charID] = AceDB.registry[self] or "Default"
-	end
-	if db.raw.profiles then
-		for k,v in pairs(db.raw.profiles) do
-			local new_k = k
-			if k:find("^char/") then
-				new_k = "char/" .. convertFromOldCharID(k:sub(6))
-			end
-			tmp[new_k] = v
-			db.raw.profiles[k] = nil
-		end
-		for k,v in pairs(tmp) do
-			db.raw.profiles[k] = v
-			tmp[k] = nil
-		end
-	end
-	if db.raw.disabledModules then -- AceModuleCore-2.0
-		for k,v in pairs(db.raw.disabledModules) do
-			local new_k = k
-			if k:find("^char/") then
-				new_k = "char/" .. convertFromOldCharID(k:sub(6))
-			end
-			tmp[new_k] = v
-			db.raw.disabledModules[k] = nil
-		end
-		for k,v in pairs(tmp) do
-			db.raw.disabledModules[k] = v
-			tmp[k] = nil
-		end
-	end
-	if db.raw.chars then
-		for k,v in pairs(db.raw.chars) do
-			tmp[convertFromOldCharID(k)] = v
-			db.raw.chars[k] = nil
-		end
-		for k,v in pairs(tmp) do
-			db.raw.chars[k] = v
-			tmp[k] = nil
-		end
-	end
-	if db.raw.namespaces then
-		for l,u in pairs(db.raw.namespaces) do
-			if u.chars then
-				for k,v in pairs(u.chars) do
-					tmp[convertFromOldCharID(k)] = v
-					u.chars[k] = nil
-				end
-				for k,v in pairs(tmp) do
-					u.chars[k] = v
-					tmp[k] = nil
-				end
-			end
-		end
-	end
-	if db.raw.disabled then
-		setmetatable(db.raw.disabled, caseInsensitive_mt)
-	end
-	if self['acedb-profile-copylist'] then
-		RecalculateAceDBCopyFromList(self)
-	end
-	if self['acedb-profile-list'] then
-		RecalculateAceDBProfileList(self)
-	end
-	setmetatable(db, db_mt)
-end
-
-function AceDB:OnEmbedInitialize(target, name)
-	if name then
-		self:ADDON_LOADED(name)
-	end
-	self.InitializeDB(target, name)
-end
-
-function AceDB:RegisterDB(name, charName, defaultProfile)
-	AceDB:argCheck(name, 2, "string")
-	AceDB:argCheck(charName, 3, "string", "nil")
-	AceDB:argCheck(defaultProfile, 4, "string", "nil")
-	if self.db then
-		AceDB:error("Cannot call \"RegisterDB\" if self.db is set.")
-	end
-	local stack = debugstack()
-	local addonName = stack:gsub(".-\n.-\\AddOns\\(.-)\\.*", "%1")
-	self.db = {
-		name = name,
-		charName = charName
-	}
-	AceDB.registry[self] = defaultProfile or "Default"
-	if AceDB.addonsLoaded[addonName] then
-		AceDB.InitializeDB(self, addonName)
-	else
-		AceDB.addonsToBeInitialized[self] = addonName
-	end
-end
-
-function AceDB:RegisterDefaults(kind, defaults, a3)
-	local name
-	if a3 then
-		name, kind, defaults = kind, defaults, a3
-		AceDB:argCheck(name, 2, "string")
-		AceDB:argCheck(kind, 3, "string")
-		AceDB:argCheck(defaults, 4, "table")
-	else
-		AceDB:argCheck(kind, 2, "string")
-		AceDB:argCheck(defaults, 3, "table")
-	end
-	if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then
-		AceDB:error("Bad argument #%d to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", \"realm\", \"server\", or \"faction\" expected, got %q)", a3 and 3 or 2, kind)
-	end
-	if type(self.db) ~= "table" or type(self.db.name) ~= "string" then
-		AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.")
-	end
-	local db
-	if name then
-		local namespace = self:AcquireDBNamespace(name)
-		if namespace.defaults and namespace.defaults[kind] then
-			AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind)
-		end
-		db = namespace
-	else
-		if self.db.defaults and self.db.defaults[kind] then
-			AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind)
-		end
-		db = self.db
-	end
-	if not db.defaults then
-		rawset(db, 'defaults', {})
-	end
-	db.defaults[kind] = defaults
-	if rawget(db, kind) then
-		inheritDefaults(db[kind], defaults)
-	end
-end
-
-function AceDB:ResetDB(kind, a2)
-	local name
-	if a2 then
-		name, kind = kind, a2
-		AceDB:argCheck(name, 2, "nil", "string")
-		AceDB:argCheck(kind, 3, "nil", "string")
-	else
-		AceDB:argCheck(kind, 2, "nil", "string")
-		if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then
-			name, kind = kind, nil
-		end
-	end
-	if not self.db or not self.db.raw then
-		AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
-	end
-	local db = self.db
-	if not kind then
-		if not name then
-			if db.charName then
-				_G[db.charName] = nil
-			end
-			_G[db.name] = nil
-			rawset(db, 'raw', nil)
-			AceDB.InitializeDB(self)
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'account', nil)
-					rawset(v, 'char', nil)
-					rawset(v, 'class', nil)
-					rawset(v, 'profile', nil)
-					rawset(v, 'realm', nil)
-					rawset(v, 'server', nil)
-					rawset(v, 'faction', nil)
-				end
-			end
-		else
-			if db.raw.namespaces then
-				db.raw.namespaces[name] = nil
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'account', nil)
-					rawset(v, 'char', nil)
-					rawset(v, 'class', nil)
-					rawset(v, 'profile', nil)
-					rawset(v, 'realm', nil)
-					rawset(v, 'server', nil)
-					rawset(v, 'faction', nil)
-				end
-			end
-		end
-	elseif kind == "account" then
-		if name then
-			db.raw.account = nil
-			rawset(db, 'account', nil)
-			if db.raw.namespaces then
-				for name,v in pairs(db.raw.namespaces) do
-					v.account = nil
-				end
-			end
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'account', nil)
-				end
-			end
-		else
-			if db.raw.namespaces and db.raw.namespaces[name] then
-				db.raw.namespaces[name].account = nil
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'account', nil)
-				end
-			end
-		end
-	elseif kind == "char" then
-		if name then
-			if db.charName then
-				_G[db.charName] = nil
-			else
-				if db.raw.chars then
-					db.raw.chars[charID] = nil
-				end
-				if db.raw.namespaces then
-					for name,v in pairs(db.raw.namespaces) do
-						if v.chars then
-							v.chars[charID] = nil
-						end
-					end
-				end
-			end
-			rawset(db, 'char', nil)
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'char', nil)
-				end
-			end
-		else
-			if db.charName then
-				local x = _G[db.charName]
-				if x.namespaces then
-					x.namespaces[name] = nil
-				end
-			else
-				if db.raw.namespaces then
-					local v = db.namespaces[name]
-					if v and v.chars then
-						v.chars[charID] = nil
-					end
-				end
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'char', nil)
-				end
-			end
-		end
-	elseif kind == "realm" then
-		if not name then
-			if db.raw.realms then
-				db.raw.realms[realmID] = nil
-			end
-			rawset(db, 'realm', nil)
-			if db.raw.namespaces then
-				for name,v in pairs(db.raw.namespaces) do
-					if v.realms then
-						v.realms[realmID] = nil
-					end
-				end
-			end
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'realm', nil)
-				end
-			end
-		else
-			if db.raw.namespaces then
-				local v = db.raw.namespaces[name]
-				if v and v.realms then
-					v.realms[realmID] = nil
-				end
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'realm', nil)
-				end
-			end
-		end
-	elseif kind == "server" then
-		if not name then
-			if db.raw.servers then
-				db.raw.servers[server] = nil
-			end
-			rawset(db, 'server', nil)
-			if db.raw.namespaces then
-				for name,v in pairs(db.raw.namespaces) do
-					if v.servers then
-						v.servers[server] = nil
-					end
-				end
-			end
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'server', nil)
-				end
-			end
-		else
-			if db.raw.namespaces then
-				local v = db.raw.namespaces[name]
-				if v and v.servers then
-					v.servers[server] = nil
-				end
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'server', nil)
-				end
-			end
-		end
-	elseif kind == "faction" then
-		if not name then
-			if db.raw.factions then
-				db.raw.factions[faction] = nil
-			end
-			rawset(db, 'faction', nil)
-			if db.raw.namespaces then
-				for name,v in pairs(db.raw.namespaces) do
-					if v.factions then
-						v.factions[faction] = nil
-					end
-				end
-			end
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'faction', nil)
-				end
-			end
-		else
-			if db.raw.namespaces then
-				local v = db.raw.namespaces[name]
-				if v and v.factions then
-					v.factions[faction] = nil
-				end
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'faction', nil)
-				end
-			end
-		end
-	elseif kind == "class" then
-		if not name then
-			if db.raw.realms then
-				db.raw.realms[classID] = nil
-			end
-			rawset(db, 'class', nil)
-			if db.raw.namespaces then
-				for name,v in pairs(db.raw.namespaces) do
-					if v.classes then
-						v.classes[classID] = nil
-					end
-				end
-			end
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'class', nil)
-				end
-			end
-		else
-			if db.raw.namespaces then
-				local v = db.raw.namespaces[name]
-				if v and v.classes then
-					v.classes[classID] = nil
-				end
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'class', nil)
-				end
-			end
-		end
-	elseif kind == "profile" then
-		local id = db.raw.currentProfile and db.raw.currentProfile[charID] or AceDB.registry[self] or "Default"
-		if id == "char" then
-			id = "char/" .. charID
-		elseif id == "class" then
-			id = "class/" .. classID
-		elseif id == "realm" then
-			id = "realm/" .. realmID
-		end
-
-		local current = self.class
-		while current and current ~= AceOO.Class do
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnEmbedProfileDisable) == "function" then
-						safecall(mixin.OnEmbedProfileDisable, mixin, self, id)
-					end
-				end
-			end
-			current = current.super
-		end
-		if type(self.OnProfileDisable) == "function" then
-			safecall(self.OnProfileDisable, self, id)
-		end
-		local active = self:IsActive()
-
-		if not name then
-			if db.raw.profiles then
-				db.raw.profiles[id] = nil
-			end
-			rawset(db, 'profile', nil)
-			if db.raw.namespaces then
-				for name,v in pairs(db.raw.namespaces) do
-					if v.profiles then
-						v.profiles[id] = nil
-					end
-				end
-			end
-			if db.namespaces then
-				for name,v in pairs(db.namespaces) do
-					rawset(v, 'profile', nil)
-				end
-			end
-		else
-			if db.raw.namespaces then
-				local v = db.raw.namespaces[name]
-				if v and v.profiles then
-					v.profiles[id] = nil
-				end
-			end
-			if db.namespaces then
-				local v = db.namespaces[name]
-				if v then
-					rawset(v, 'profile', nil)
-				end
-			end
-		end
-
-		local current = self.class
-		while current and current ~= AceOO.Class do
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnEmbedProfileEnable) == "function" then
-						safecall(mixin.OnEmbedProfileEnable, mixin, self, id)
-					end
-				end
-			end
-			current = current.super
-		end
-		if type(self.OnProfileEnable) == "function" then
-			safecall(self.OnProfileEnable, self, id)
-		end
-		local newactive = self:IsActive()
-		if active ~= newactive then
-			if newactive then
-				local first = nil
-				if AceOO.inherits(self, "AceAddon-2.0") then
-					local AceAddon = AceLibrary("AceAddon-2.0")
-					if not AceAddon.addonsStarted[self] then
-						return
-					end
-					if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then
-						AceAddon.addonsEnabled[self] = true
-						first = true
-					end
-				end
-				local current = self.class
-				while current and current ~= AceOO.Class do
-					if current.mixins then
-						for mixin in pairs(current.mixins) do
-							if type(mixin.OnEmbedEnable) == "function" then
-								safecall(mixin.OnEmbedEnable, mixin, self, first)
-							end
-						end
-					end
-					current = current.super
-				end
-				if type(self.OnEnable) == "function" then
-					safecall(self.OnEnable, self, first)
-				end
-				if AceEvent then
-					AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first)
-				end
-			else
-				local current = self.class
-				while current and current ~= AceOO.Class do
-					if current.mixins then
-						for mixin in pairs(current.mixins) do
-							if type(mixin.OnEmbedDisable) == "function" then
-								safecall(mixin.OnEmbedDisable, mixin, self)
-							end
-						end
-					end
-					current = current.super
-				end
-				if type(self.OnDisable) == "function" then
-					safecall(self.OnDisable, self)
-				end
-				if AceEvent then
-					AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
-				end
-			end
-		end
-	else
-		return -- skip event
-	end
-	if AceEvent then
-		AceEvent:TriggerEvent("AceDB20_ResetDB", self, self.db.name, kind)
-	end
-end
-
-local function cleanDefaults(t, defaults, blocker)
-	if defaults then
-		for k,v in pairs(t) do
-			if (not blocker or (blocker[k] == nil and blocker['*'] == nil and blocker['**'] == nil)) and (defaults[k] ~= nil or defaults['*'] ~= nil or defaults['**'] ~= nil) then
-				local u = defaults[k]
-				if u == nil then
-					u = defaults['*']
-					if u == nil then
-						u = defaults['**']
-					end
-				end
-				if v == u then
-					t[k] = nil
-				elseif type(v) == "table" and type(u) == "table" then
-					if cleanDefaults(v, u) then
-						t[k] = nil
-					else
-						local w = defaults['**']
-						if w ~= u then
-							if cleanDefaults(v, w, u) then
-								t[k] = nil
-							end
-						end
-					end
-				end
-			end
-		end
-	end
-	return t and next(t) == nil
-end
-
-function AceDB:GetProfile()
-	if not self.db or not self.db.raw then
-		return nil
-	end
-	if not self.db.raw.currentProfile then
-		self.db.raw.currentProfile = {}
-	end
-	if not self.db.raw.currentProfile[charID] then
-		self.db.raw.currentProfile[charID] = AceDB.registry[self] or "Default"
-	end
-	local profile = self.db.raw.currentProfile[charID]
-	if profile == "char" then
-		return "char", "char/" .. charID
-	elseif profile == "class" then
-		return "class", "class/" .. classID
-	elseif profile == "realm" then
-		return "realm", "realm/" .. realmID
-	end
-	return profile, profile
-end
-
-local function copyTable(to, from)
-	setmetatable(to, nil)
-	for k,v in pairs(from) do
-		if type(k) == "table" then
-			k = copyTable({}, k)
-		end
-		if type(v) == "table" then
-			v = copyTable({}, v)
-		end
-		to[k] = v
-	end
-	setmetatable(to, from)
-	return to
-end
-
-function AceDB:SetProfile(name)
-	AceDB:argCheck(name, 2, "string")
-	if not self.db or not self.db.raw then
-		AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
-	end
-	local db = self.db
-	local lowerName = name:lower()
-	if lowerName:find("^char/") or lowerName:find("^realm/") or lowerName:find("^class/") then
-		if lowerName:find("^char/") then
-			name = "char"
-		else
-			name = lowerName:sub(1, 5)
-		end
-		lowerName = name:lower()
-	end
-	local oldName = db.raw.currentProfile[charID]
-	if oldName:lower() == name:lower() then
-		return
-	end
-	local oldProfileData = db.profile
-	local realName = name
-	if lowerName == "char" then
-		realName = name .. "/" .. charID
-	elseif lowerName == "realm" then
-		realName = name .. "/" .. realmID
-	elseif lowerName == "class" then
-		realName = name .. "/" .. classID
-	end
-	local current = self.class
-	while current and current ~= AceOO.Class do
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedProfileDisable) == "function" then
-					safecall(mixin.OnEmbedProfileDisable, mixin, self, realName)
-				end
-			end
-		end
-		current = current.super
-	end
-	if type(self.OnProfileDisable) == "function" then
-		safecall(self.OnProfileDisable, self, realName)
-	end
-	local active = self:IsActive()
-	db.raw.currentProfile[charID] = name
-	rawset(db, 'profile', nil)
-	if db.namespaces then
-		for k,v in pairs(db.namespaces) do
-			rawset(v, 'profile', nil)
-		end
-	end
-	local current = self.class
-	while current and current ~= AceOO.Class do
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedProfileEnable) == "function" then
-					safecall(mixin.OnEmbedProfileEnable, mixin, self, oldName, oldProfileData)
-				end
-			end
-		end
-		current = current.super
-	end
-	if type(self.OnProfileEnable) == "function" then
-		safecall(self.OnProfileEnable, self, oldName, oldProfileData)
-	end
-	if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then
-		db.raw.profiles[oldName] = nil
-		if not next(db.raw.profiles) then
-			db.raw.profiles = nil
-		end
-	end
-	local newactive = self:IsActive()
-	if active ~= newactive then
-		local first = nil
-		if AceOO.inherits(self, "AceAddon-2.0") then
-			local AceAddon = AceLibrary("AceAddon-2.0")
-			if not AceAddon.addonsStarted[self] then
-				return
-			end
-			if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then
-				first = true
-			end
-		end
-		if newactive then
-			local current = self.class
-			while current and current ~= AceOO.Class do
-				if current.mixins then
-					for mixin in pairs(current.mixins) do
-						if type(mixin.OnEmbedEnable) == "function" then
-							safecall(mixin.OnEmbedEnable, mixin, self, first)
-						end
-					end
-				end
-				current = current.super
-			end
-			if type(self.OnEnable) == "function" then
-				safecall(self.OnEnable, self, first)
-			end
-			if AceEvent then
-				AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first)
-			end
-		else
-			local current = self.class
-			while current and current ~= AceOO.Class do
-				if current.mixins then
-					for mixin in pairs(current.mixins) do
-						if type(mixin.OnEmbedDisable) == "function" then
-							safecall(mixin.OnEmbedDisable, mixin, self)
-						end
-					end
-				end
-				current = current.super
-			end
-			if type(self.OnDisable) == "function" then
-				safecall(self.OnDisable, self)
-			end
-			if AceEvent then
-				AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
-			end
-		end
-	end
-	if self['acedb-profile-list'] then
-		RecalculateAceDBProfileList(self)
-	end
-	if self['acedb-profile-copylist'] then
-		RecalculateAceDBCopyFromList(self)
-	end
-	if Dewdrop then
-		Dewdrop:Refresh()
-	end
-end
-
-function AceDB:CopyProfileFrom(copyFrom)
-	AceDB:argCheck(copyFrom, 2, "string")
-	if not self.db or not self.db.raw then
-		AceDB:error("Cannot call \"CopyProfileFrom\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
-	end
-	local db = self.db
-	local lowerCopyFrom = copyFrom:lower()
-	if not db.raw.profiles or not db.raw.profiles[copyFrom] then
-		local good = false
-		if db.raw.namespaces then
-			for _,n in pairs(db.raw.namespaces) do
-				if n.profiles and n.profiles[copyFrom] then
-					good = true
-					break
-				end
-			end
-		end
-		if not good then
-			AceDB:error("Cannot copy from profile %q, it does not exist.", copyFrom)
-		end
-	end
-	local currentProfile = db.raw.currentProfile[charID]
-	if currentProfile:lower() == lowerCopyFrom then
-		AceDB:error("Cannot copy from profile %q, it is currently in use.", copyFrom)
-	end
-	local oldProfileData = db.profile
-	local current = self.class
-	while current and current ~= AceOO.Class do
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedProfileDisable) == "function" then
-					safecall(mixin.OnEmbedProfileDisable, mixin, self, currentProfile)
-				end
-			end
-		end
-		current = current.super
-	end
-	if type(self.OnProfileDisable) == "function" then
-		safecall(self.OnProfileDisable, self, realName)
-	end
-	local active = self:IsActive()
-	for k,v in pairs(db.profile) do
-		db.profile[k] = nil
-	end
-	if db.raw.profiles[copyFrom] then
-		copyTable(db.profile, db.raw.profiles[copyFrom])
-	end
-	inheritDefaults(db.profile, db.defaults and db.defaults.profile)
-	if db.namespaces then
-		for l,u in pairs(db.namespaces) do
-			for k,v in pairs(u.profile) do
-				u.profile[k] = nil
-			end
-			if db.raw.namespaces[l].profiles[copyFrom] then
-				copyTable(u.profile, db.raw.namespaces[l].profiles[copyFrom])
-			end
-			inheritDefaults(u.profile, u.defaults and u.defaults.profile)
-		end
-	end
-	local current = self.class
-	while current and current ~= AceOO.Class do
-		if current.mixins then
-			for mixin in pairs(current.mixins) do
-				if type(mixin.OnEmbedProfileEnable) == "function" then
-					safecall(mixin.OnEmbedProfileEnable, mixin, self, copyFrom, oldProfileData, copyFrom)
-				end
-			end
-		end
-		current = current.super
-	end
-	if type(self.OnProfileEnable) == "function" then
-		safecall(self.OnProfileEnable, self, copyFrom, oldProfileData, copyFrom)
-	end
-	local newactive = self:IsActive()
-	if active ~= newactive then
-		if AceOO.inherits(self, "AceAddon-2.0") then
-			local AceAddon = AceLibrary("AceAddon-2.0")
-			if not AceAddon.addonsStarted[self] then
-				return
-			end
-		end
-		if newactive then
-			local current = self.class
-			while current and current ~= AceOO.Class do
-				if current.mixins then
-					for mixin in pairs(current.mixins) do
-						if type(mixin.OnEmbedEnable) == "function" then
-							safecall(mixin.OnEmbedEnable, mixin, self)
-						end
-					end
-				end
-				current = current.super
-			end
-			if type(self.OnEnable) == "function" then
-				safecall(self.OnEnable, self)
-			end
-			if AceEvent then
-				AceEvent:TriggerEvent("Ace2_AddonEnabled", self)
-			end
-		else
-			local current = self.class
-			while current and current ~= AceOO.Class do
-				if current.mixins then
-					for mixin in pairs(current.mixins) do
-						if type(mixin.OnEmbedDisable) == "function" then
-							safecall(mixin.OnEmbedDisable, mixin, self)
-						end
-					end
-				end
-				current = current.super
-			end
-			if type(self.OnDisable) == "function" then
-				safecall(self.OnDisable, self)
-			end
-			if AceEvent then
-				AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
-			end
-		end
-	end
-	if self['acedb-profile-list'] then
-		RecalculateAceDBProfileList(self)
-	end
-	if self['acedb-profile-copylist'] then
-		RecalculateAceDBCopyFromList(self)
-	end
-	if Dewdrop then
-		Dewdrop:Refresh()
-	end
-end
-
-function AceDB:DeleteProfile(profile, noconfirm)
-	AceDB:argCheck(profile , 2, "string")
-	if not self.db or not self.db.raw then
-		AceDB:error("Cannot call \"DeleteProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
-	end
-	local db = self.db
-
-	local currentProfile = db.raw.currentProfile[charID]
-	if currentProfile:lower() == profile:lower() then
-		AceDB:error("Cannot delete profile %q, it is currently in use.", profile)
-	end
-
-	if not (noconfirm or IsShiftKeyDown()) then
-		if not StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] then
-			StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] = {}
-		end
-		local t = StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"]
-		t.text = format("%s: %s?", DELETE_PROFILE, profile)
-		t.button1 = DELETE_PROFILE
-		t.button2 = CANCEL or "Cancel"
-		t.OnAccept = function()
-			self:DeleteProfile(profile, true)
-		end
-		t.timeout = 0
-		t.whileDead = 1
-		t.hideOnEscape = 1
-
-		StaticPopup_Show("ACEDB20_CONFIRM_DELETE_DIALOG")
-		return;
-	end
-
-	local good = false
-	if db.raw.profiles and db.raw.profiles[profile] then
-		good = true;
-		db.raw.profiles[profile] = nil;
-	end
-
-	if db.raw.namespaces then
-		for _,n in pairs(db.raw.namespaces) do
-			if n.profiles and n.profiles[profile] then
-				n.profiles[profile] = nil;
-				good = true
-			end
-		end
-	end
-
-	if not good then
-		AceDB:error("Cannot delete profile %q, it does not exist.", profile)
-	end
-
-	if self['acedb-profile-list'] then
-		RecalculateAceDBProfileList(self)
-	end
-	if self['acedb-profile-copylist'] then
-		RecalculateAceDBCopyFromList(self)
-	end
-
-	if Dewdrop then
-		Dewdrop:Refresh()
-	end
-end
-
-function AceDB:IsActive()
-	return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]]
-end
-
-function AceDB:ToggleActive(state)
-	AceDB:argCheck(state, 2, "boolean", "nil")
-	if not self.db or not self.db.raw then
-		AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
-	end
-	local db = self.db
-	if not db.raw.disabled then
-		db.raw.disabled = setmetatable({}, caseInsensitive_mt)
-	end
-	local profile = db.raw.currentProfile[charID]
-	local disable
-	if state == nil then
-		disable = not db.raw.disabled[profile]
-	else
-		disable = not state
-		if disable == db.raw.disabled[profile] then
-			return
-		end
-	end
-	db.raw.disabled[profile] = disable or nil
-	if AceOO.inherits(self, "AceAddon-2.0") then
-		local AceAddon = AceLibrary("AceAddon-2.0")
-		if not AceAddon.addonsStarted[self] then
-			return
-		end
-	end
-	if not disable then
-		local current = self.class
-		while current and current ~= AceOO.Class do
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnEmbedEnable) == "function" then
-						safecall(mixin.OnEmbedEnable, mixin, self)
-					end
-				end
-			end
-			current = current.super
-		end
-		if type(self.OnEnable) == "function" then
-			safecall(self.OnEnable, self)
-		end
-		if AceEvent then
-			AceEvent:TriggerEvent("Ace2_AddonEnabled", self)
-		end
-	else
-		local current = self.class
-		while current and current ~= AceOO.Class do
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnEmbedDisable) == "function" then
-						safecall(mixin.OnEmbedDisable, mixin, self)
-					end
-				end
-			end
-			current = current.super
-		end
-		if type(self.OnDisable) == "function" then
-			safecall(self.OnDisable, self)
-		end
-		if AceEvent then
-			AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
-		end
-	end
-	return not disable
-end
-
-function AceDB:embed(target)
-	self.super.embed(self, target)
-	if not AceEvent then
-		AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0")
-	end
-end
-
-function AceDB:ADDON_LOADED(name)
-	AceDB.addonsLoaded[name] = true
-	for addon, addonName in pairs(AceDB.addonsToBeInitialized) do
-		if name == addonName then
-			AceDB.InitializeDB(addon, name)
-			AceDB.addonsToBeInitialized[addon] = nil
-		end
-	end
-end
-
-function AceDB:PLAYER_LOGOUT()
-	for addon, defaultProfile in pairs(AceDB.registry) do
-		local db = addon.db
-		if db then
-			if type(addon.OnDatabaseCleanup) == "function" then
-				safecall(addon.OnDatabaseCleanup, addon)
-			end
-			setmetatable(db, nil)
-			CrawlForSerialization(db.raw)
-			if type(_G[db.charName]) == "table" then
-				CrawlForSerialization(_G[db.charName])
-			end
-			if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then
-				if db.charName and _G[db.charName] and _G[db.charName].global == db.char then
-					_G[db.charName].global = nil
-					if not next(_G[db.charName]) then
-						_G[db.charName] = nil
-					end
-				else
-					if db.raw.chars then
-						db.raw.chars[charID] = nil
-						if not next(db.raw.chars) then
-							db.raw.chars = nil
-						end
-					end
-				end
-			end
-			if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then
-				if db.raw.realms then
-					db.raw.realms[realmID] = nil
-					if not next(db.raw.realms) then
-						db.raw.realms = nil
-					end
-				end
-			end
-			if db.server and cleanDefaults(db.server, db.defaults and db.defaults.server) then
-				if db.raw.servers then
-					db.raw.servers[server] = nil
-					if not next(db.raw.servers) then
-						db.raw.servers = nil
-					end
-				end
-			end
-			if db.faction and cleanDefaults(db.faction, db.defaults and db.defaults.faction) then
-				if db.raw.factions then
-					db.raw.factions[faction] = nil
-					if not next(db.raw.factions) then
-						db.raw.factions = nil
-					end
-				end
-			end
-			if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then
-				if db.raw.classes then
-					db.raw.classes[classID] = nil
-					if not next(db.raw.classes) then
-						db.raw.classes = nil
-					end
-				end
-			end
-			if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then
-				db.raw.account = nil
-			end
-			if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then
-				if db.raw.profiles then
-					db.raw.profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil
-					if not next(db.raw.profiles) then
-						db.raw.profiles = nil
-					end
-				end
-			end
-			if db.namespaces and db.raw.namespaces then
-				for name,v in pairs(db.namespaces) do
-					if db.raw.namespaces[name] then
-						setmetatable(v, nil)
-						if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then
-							if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then
-								_G[db.charName].namespaces[name] = nil
-								if not next(_G[db.charName].namespaces) then
-									_G[db.charName].namespaces = nil
-									if not next(_G[db.charName]) then
-										_G[db.charName] = nil
-									end
-								end
-							else
-								if db.raw.namespaces[name].chars then
-									db.raw.namespaces[name].chars[charID] = nil
-									if not next(db.raw.namespaces[name].chars) then
-										db.raw.namespaces[name].chars = nil
-									end
-								end
-							end
-						end
-						if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then
-							if db.raw.namespaces[name].realms then
-								db.raw.namespaces[name].realms[realmID] = nil
-								if not next(db.raw.namespaces[name].realms) then
-									db.raw.namespaces[name].realms = nil
-								end
-							end
-						end
-						if v.server and cleanDefaults(v.server, v.defaults and v.defaults.server) then
-							if db.raw.namespaces[name].servers then
-								db.raw.namespaces[name].servers[server] = nil
-								if not next(db.raw.namespaces[name].servers) then
-									db.raw.namespaces[name].servers = nil
-								end
-							end
-						end
-						if v.faction and cleanDefaults(v.faction, v.defaults and v.defaults.faction) then
-							if db.raw.namespaces[name].factions then
-								db.raw.namespaces[name].factions[faction] = nil
-								if not next(db.raw.namespaces[name].factions) then
-									db.raw.namespaces[name].factions = nil
-								end
-							end
-						end
-						if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then
-							if db.raw.namespaces[name].classes then
-								db.raw.namespaces[name].classes[classID] = nil
-								if not next(db.raw.namespaces[name].classes) then
-									db.raw.namespaces[name].classes = nil
-								end
-							end
-						end
-						if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then
-							db.raw.namespaces[name].account = nil
-						end
-						if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then
-							if db.raw.namespaces[name].profiles then
-								db.raw.namespaces[name].profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil
-								if not next(db.raw.namespaces[name].profiles) then
-									db.raw.namespaces[name].profiles = nil
-								end
-							end
-						end
-						if not next(db.raw.namespaces[name]) then
-							db.raw.namespaces[name] = nil
-						end
-					end
-				end
-				if not next(db.raw.namespaces) then
-					db.raw.namespaces = nil
-				end
-			end
-			if db.raw.disabled and not next(db.raw.disabled) then
-				db.raw.disabled = nil
-			end
-			if db.raw.currentProfile then
-				for k,v in pairs(db.raw.currentProfile) do
-					if v:lower() == (defaultProfile or "Default"):lower() then
-						db.raw.currentProfile[k] = nil
-					end
-				end
-				if not next(db.raw.currentProfile) then
-					db.raw.currentProfile = nil
-				end
-			end
-			if _G[db.name] and not next(_G[db.name]) then
-				_G[db.name] = nil
-			end
-		end
-	end
-end
-
-function AceDB:AcquireDBNamespace(name)
-	AceDB:argCheck(name, 2, "string")
-	local db = self.db
-	if not db then
-		AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2)
-	end
-	if not db.namespaces then
-		rawset(db, 'namespaces', {})
-	end
-	if not db.namespaces[name] then
-		local namespace = {}
-		db.namespaces[name] = namespace
-		namespace.db = db
-		namespace.name = name
-		setmetatable(namespace, namespace_mt)
-	end
-	return db.namespaces[name]
-end
-
-function AceDB:GetAceOptionsDataTable(target)
-	if not target['acedb-profile-list'] then
-		target['acedb-profile-list'] = setmetatable({}, caseInsensitive_mt)
-		RecalculateAceDBProfileList(target)
-	end
-	if not target['acedb-profile-copylist'] then
-		target['acedb-profile-copylist'] = setmetatable({}, caseInsensitive_mt)
-		RecalculateAceDBCopyFromList(target)
-	end
-	return {
-		standby = {
-			cmdName = STATE,
-			guiName = ENABLED,
-			name = ACTIVE,
-			desc = TOGGLE_ACTIVE,
-			type = "toggle",
-			get = "IsActive",
-			set = "ToggleActive",
-			map = MAP_ACTIVESUSPENDED,
-			order = -3,
-		},
-		profile = {
-			type = 'group',
-			name = PROFILE,
-			desc = SET_PROFILE,
-			order = -3.5,
-			get = "GetProfile",
-			args = {
-				choose = {
-					guiName = CHOOSE_PROFILE_GUI,
-					cmdName = PROFILE,
-					desc = CHOOSE_PROFILE_DESC,
-					type = 'text',
-					get = "GetProfile",
-					set = "SetProfile",
-					validate = target['acedb-profile-list']
-				},
-				copy = {
-					guiName = COPY_PROFILE_GUI,
-					cmdName = PROFILE,
-					desc = COPY_PROFILE_DESC,
-					type = 'text',
-					get = false,
-					set = "CopyProfileFrom",
-					validate = target['acedb-profile-copylist'],
-					disabled = function()
-						return not next(target['acedb-profile-copylist'])
-					end,
-				},
-				other = {
-					guiName = OTHER_PROFILE_GUI,
-					cmdName = PROFILE,
-					desc = OTHER_PROFILE_DESC,
-					usage = OTHER_PROFILE_USAGE,
-					type = 'text',
-					get = "GetProfile",
-					set = "SetProfile",
-				},
-				delete = {
-					name = DELETE_PROFILE,
-					desc = DELETE_PROFILE_DESC,
-					usage = DELETE_PROFILE_USAGE,
-					type = 'text',
-					set = "DeleteProfile",
-					get = false,
-					validate = target['acedb-profile-copylist'],
-					disabled = function()
-						return not next(target['acedb-profile-copylist'])
-					end,
-				},
-				reset = {
-					name = RESET_PROFILE,
-					desc = RESET_PROFILE_DESC,
-					type = 'execute',
-					func = function()
-						target:ResetDB('profile')
-					end,
-					confirm = true,
-				}
-			}
-		},
-	}
-end
-
-local function activate(self, oldLib, oldDeactivate)
-	AceDB = self
-	AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0")
-
-	self.addonsToBeInitialized = oldLib and oldLib.addonsToBeInitialized or {}
-	self.addonsLoaded = oldLib and oldLib.addonsLoaded or {}
-	self.registry = oldLib and oldLib.registry or {}
-	for k, v in pairs(self.registry) do
-		if v == true then
-			self.registry[k] = "Default"
-		end
-	end
-
-	self:activate(oldLib, oldDeactivate)
-
-	for t in pairs(self.embedList) do
-		if t.db then
-			rawset(t.db, 'char', nil)
-			rawset(t.db, 'realm', nil)
-			rawset(t.db, 'class', nil)
-			rawset(t.db, 'account', nil)
-			rawset(t.db, 'server', nil)
-			rawset(t.db, 'faction', nil)
-			rawset(t.db, 'profile', nil)
-			setmetatable(t.db, db_mt)
-		end
-	end
-
-	if oldLib then
-		oldDeactivate(oldLib)
-	end
-end
-
-local function external(self, major, instance)
-	if major == "AceEvent-2.0" then
-		AceEvent = instance
-
-		AceEvent:embed(self)
-
-		self:RegisterEvent("ADDON_LOADED")
-		self:RegisterEvent("PLAYER_LOGOUT")
-	elseif major == "Dewdrop-2.0" then
-		Dewdrop = instance
-	end
-end
-
-AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
-AceDB = AceLibrary(MAJOR_VERSION)
--- a/lib/AceDB-2.0/AceDB-2.0.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceDB-2.0
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary, AceEvent-2.0, AceOO-2.0
- 
-AceDB-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceDB-3.0/AceDB-3.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,623 @@
+--[[ $Id: AceDB-3.0.lua 63886 2008-03-08 12:43:31Z nevcairiel $ ]]
+local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 5
+local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
+
+if not AceDB then return end -- No upgrade needed
+
+local type = type
+local pairs, next = pairs, next
+local rawget, rawset = rawget, rawset
+local setmetatable = setmetatable
+
+AceDB.db_registry = AceDB.db_registry or {}
+AceDB.frame = AceDB.frame or CreateFrame("Frame")
+
+local CallbackHandler
+local CallbackDummy = { Fire = function() end }
+
+local DBObjectLib = {}
+
+--[[-------------------------------------------------------------------------
+	AceDB Utility Functions
+---------------------------------------------------------------------------]]
+
+-- Simple shallow copy for copying defaults
+local function copyTable(src, dest)
+	if type(dest) ~= "table" then dest = {} end
+	if type(src) == "table" then
+		for k,v in pairs(src) do
+			if type(v) == "table" then
+				-- try to index the key first so that the metatable creates the defaults, if set, and use that table
+				v = copyTable(v, dest[k])
+			end
+			dest[k] = v
+		end
+	end
+	return dest
+end
+
+-- Called to add defaults to a section of the database
+--
+-- When a ["*"] default section is indexed with a new key, a table is returned
+-- and set in the host table.  These tables must be cleaned up by removeDefaults
+-- in order to ensure we don't write empty default tables.
+local function copyDefaults(dest, src)
+	-- this happens if some value in the SV overwrites our default value with a non-table
+	--if type(dest) ~= "table" then return end
+	for k, v in pairs(src) do
+		if k == "*" or k == "**" then
+			if type(v) == "table" then
+				-- This is a metatable used for table defaults
+				local mt = {
+					-- This handles the lookup and creation of new subtables
+					__index = function(t,k)
+							if k == nil then return nil end
+							local tbl = {}
+							copyDefaults(tbl, v)
+							rawset(t, k, tbl)
+							return tbl
+						end,
+				}
+				setmetatable(dest, mt)
+				-- handle already existing tables in the SV
+				for dk, dv in pairs(dest) do
+					if not rawget(src, dk) and type(dv) == "table" then
+						copyDefaults(dv, v)
+					end
+				end
+			else
+				-- Values are not tables, so this is just a simple return
+				local mt = {__index = function(t,k) return k~=nil and v or nil end}
+				setmetatable(dest, mt)
+			end
+		elseif type(v) == "table" then
+			if not rawget(dest, k) then rawset(dest, k, {}) end
+			if type(dest[k]) == "table" then
+				copyDefaults(dest[k], v)
+				if src['**'] then
+					copyDefaults(dest[k], src['**'])
+				end
+			end
+		else
+			if rawget(dest, k) == nil then
+				rawset(dest, k, v)
+			end
+		end
+	end
+end
+
+-- Called to remove all defaults in the default table from the database
+local function removeDefaults(db, defaults, blocker)
+	for k,v in pairs(defaults) do
+		if k == "*" or k == "**" then
+			if type(v) == "table" then
+				-- Loop through all the actual k,v pairs and remove
+				for key, value in pairs(db) do
+					if type(value) == "table" then
+						-- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
+						if defaults[key] == nil then
+							removeDefaults(value, v)
+							-- if the table is empty afterwards, remove it
+							if not next(value) then
+								db[key] = nil
+							end
+						-- if it was specified, only strip ** content, but block values which were set in the key table
+						elseif k == "**" then 
+							removeDefaults(value, v, defaults[key])
+						end
+					end
+				end
+			elseif k == "*" then
+				-- check for non-table default
+				for key, value in pairs(db) do
+					if defaults[key] == nil and v == value then
+						db[key] = nil
+					end
+				end
+			end
+		elseif type(v) == "table" and type(db[k]) == "table" then
+			-- if a blocker was set, dive into it, to allow multi-level defaults
+			removeDefaults(db[k], v, blocker and blocker[k])
+			if not next(db[k]) then
+				db[k] = nil
+			end
+		else
+			-- check if the current value matches the default, and that its not blocked by another defaults table
+			if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
+				db[k] = nil
+			end
+		end
+	end
+	-- remove all metatables from the db
+	setmetatable(db, nil)
+end
+
+-- This is called when a table section is first accessed, to set up the defaults
+local function initSection(db, section, svstore, key, defaults)
+	local sv = rawget(db, "sv")
+	
+	local tableCreated
+	if not sv[svstore] then sv[svstore] = {} end
+	if not sv[svstore][key] then
+		sv[svstore][key] = {}
+		tableCreated = true
+	end
+	
+	local tbl = sv[svstore][key]
+	
+	if defaults then
+		copyDefaults(tbl, defaults)
+	end
+	rawset(db, section, tbl)
+	
+	return tableCreated, tbl
+end
+
+-- Metatable to handle the dynamic creation of sections and copying of sections.
+local dbmt = {
+	__index = function(t, section)
+			local keys = rawget(t, "keys")
+			local key = keys[section]
+			if key then
+				local defaultTbl = rawget(t, "defaults")
+				local defaults = defaultTbl and defaultTbl[section]
+				
+				if section == "profile" then
+					local new = initSection(t, section, "profiles", key, defaults)
+					if new then
+						-- Callback: OnNewProfile, database, newProfileKey
+						t.callbacks:Fire("OnNewProfile", t, key)
+					end
+				elseif section == "profiles" then
+					local sv = rawget(t, "sv")
+					if not sv.profiles then sv.profiles = {} end
+					rawset(t, "profiles", sv.profiles)
+				elseif section == "global" then
+					local sv = rawget(t, "sv")
+					if not sv.global then sv.global = {} end
+					if defaults then
+						copyDefaults(sv.global, defaults)
+					end
+					rawset(t, section, sv.global)
+				else
+					initSection(t, section, section, key, defaults)
+				end
+			end
+			
+			return rawget(t, section)
+		end
+}
+
+local function validateDefaults(defaults, keyTbl, offset)
+	if not defaults then return end
+	offset = offset or 0
+	for k in pairs(defaults) do
+		if not keyTbl[k] or k == "profiles" then
+			error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
+		end
+	end
+end
+
+local preserve_keys = {
+	["callbacks"] = true,
+	["RegisterCallback"] = true,
+	["UnregisterCallback"] = true,
+	["UnregisterAllCallbacks"] = true,
+	["children"] = true,
+}
+
+local realmKey = GetRealmName()
+local charKey = UnitName("player") .. " - " .. realmKey
+local _, classKey = UnitClass("player")
+local _, raceKey = UnitRace("player")
+local factionKey = UnitFactionGroup("player")
+local factionrealmKey = factionKey .. " - " .. realmKey
+-- Actual database initialization function
+local function initdb(sv, defaults, defaultProfile, olddb, parent)
+	-- Generate the database keys for each section
+	
+	-- Make a container for profile keys
+	if not sv.profileKeys then sv.profileKeys = {} end
+	
+	-- Try to get the profile selected from the char db
+	local profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
+	sv.profileKeys[charKey] = profileKey
+	
+	-- This table contains keys that enable the dynamic creation 
+	-- of each section of the table.  The 'global' and 'profiles'
+	-- have a key of true, since they are handled in a special case
+	local keyTbl= {
+		["char"] = charKey,
+		["realm"] = realmKey,
+		["class"] = classKey,
+		["race"] = raceKey,
+		["faction"] = factionKey,
+		["factionrealm"] = factionrealmKey,
+		["profile"] = profileKey,
+		["global"] = true,
+		["profiles"] = true,
+	}
+	
+	validateDefaults(defaults, keyTbl, 1)
+	
+	-- This allows us to use this function to reset an entire database
+	-- Clear out the old database
+	if olddb then
+		for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
+	end
+	
+	-- Give this database the metatable so it initializes dynamically
+	local db = setmetatable(olddb or {}, dbmt)
+	
+	if not rawget(db, "callbacks") then 
+		-- try to load CallbackHandler-1.0 if it loaded after our library
+		if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
+		db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
+	end
+	
+	-- Copy methods locally into the database object, to avoid hitting
+	-- the metatable when calling methods
+	
+	if not parent then
+		for name, func in pairs(DBObjectLib) do
+			db[name] = func
+		end
+	else
+		-- hack this one in
+		db.RegisterDefaults = DBObjectLib.RegisterDefaults
+	end
+	
+	-- Set some properties in the database object
+	db.profiles = sv.profiles
+	db.keys = keyTbl
+	db.sv = sv
+	--db.sv_name = name
+	db.defaults = defaults
+	db.parent = parent
+	
+	-- store the DB in the registry
+	AceDB.db_registry[db] = true
+	
+	return db
+end
+
+-- handle PLAYER_LOGOUT
+-- strip all defaults from all databases
+local function logoutHandler(frame, event)
+	if event == "PLAYER_LOGOUT" then
+		for db in pairs(AceDB.db_registry) do
+			db.callbacks:Fire("OnDatabaseShutdown", db)
+			for section, key in pairs(db.keys) do
+				if db.defaults and db.defaults[section] and rawget(db, section) then
+					removeDefaults(db[section], db.defaults[section])
+				end
+			end
+		end
+	end
+end
+
+AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
+AceDB.frame:SetScript("OnEvent", logoutHandler)
+
+
+--[[-------------------------------------------------------------------------
+	AceDB Object Method Definitions
+---------------------------------------------------------------------------]]
+
+-- DBObject:RegisterDefaults(defaults)
+-- defaults (table) - A table of defaults for this database
+--
+-- Sets the defaults table for the given database object by clearing any
+-- that are currently set, and then setting the new defaults.
+function DBObjectLib:RegisterDefaults(defaults)
+	if defaults and type(defaults) ~= "table" then
+		error("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected.", 2)
+	end
+	
+	validateDefaults(defaults, self.keys)
+	
+	-- Remove any currently set defaults
+	if self.defaults then
+		for section,key in pairs(self.keys) do
+			if self.defaults[section] and rawget(self, section) then
+				removeDefaults(self[section], self.defaults[section])
+			end
+		end
+	end
+	
+	-- Set the DBObject.defaults table
+	self.defaults = defaults
+	
+	-- Copy in any defaults, only touching those sections already created
+	if defaults then
+		for section,key in pairs(self.keys) do
+			if defaults[section] and rawget(self, section) then
+				copyDefaults(self[section], defaults[section])
+			end
+		end
+	end
+end
+
+-- DBObject:SetProfile(name)
+-- name (string) - The name of the profile to set as the current profile
+--
+-- Changes the profile of the database and all of it's namespaces to the
+-- supplied named profile
+function DBObjectLib:SetProfile(name)
+	if type(name) ~= "string" then
+		error("Usage: AceDBObject:SetProfile(name): 'name' - string expected.", 2)
+	end
+	
+	-- changing to the same profile, dont do anything
+	if name == self.keys.profile then return end
+	
+	local oldProfile = self.profile
+	local defaults = self.defaults and self.defaults.profile
+	
+	if oldProfile and defaults then
+		-- Remove the defaults from the old profile
+		removeDefaults(oldProfile, defaults)
+	end
+	
+	self.profile = nil
+	self.keys["profile"] = name
+	self.sv.profileKeys[charKey] = name
+
+	-- Callback: OnProfileChanged, database, newProfileKey
+	self.callbacks:Fire("OnProfileChanged", self, name)
+	
+	-- populate to child namespaces
+	if self.children then
+		for _, db in pairs(self.children) do
+			DBObjectLib.SetProfile(db, name)
+		end
+	end
+end
+
+-- DBObject:GetProfiles(tbl)
+-- tbl (table) - A table to store the profile names in (optional)
+--
+-- Returns a table with the names of the existing profiles in the database.
+-- You can optionally supply a table to re-use for this purpose.
+function DBObjectLib:GetProfiles(tbl)
+	if tbl and type(tbl) ~= "table" then
+		error("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected.", 2)
+	end
+
+	-- Clear the container table
+	if tbl then
+		for k,v in pairs(tbl) do tbl[k] = nil end
+	else
+		tbl = {}
+	end
+
+	local curProfile = self.keys.profile
+	
+	local i = 0
+	for profileKey in pairs(self.profiles) do
+		i = i + 1
+		tbl[i] = profileKey
+		if curProfile and profileKey == curProfile then curProfile = nil end
+	end
+
+	-- Add the current profile, if it hasn't been created yet
+	if curProfile then
+		i = i + 1
+		tbl[i] = curProfile
+	end
+	
+	return tbl, i
+end
+
+-- DBObject:GetCurrentProfile()
+--
+-- Returns the current profile name used by the database
+function DBObjectLib:GetCurrentProfile()
+	return self.keys.profile
+end
+
+-- DBObject:DeleteProfile(name)
+-- name (string) - The name of the profile to be deleted
+--
+-- Deletes a named profile.  This profile must not be the active profile.
+function DBObjectLib:DeleteProfile(name, silent)
+	if type(name) ~= "string" then
+		error("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected.", 2)
+	end
+	
+	if self.keys.profile == name then
+		error("Cannot delete the active profile in an AceDBObject.", 2)
+	end
+	
+	if not rawget(self.sv.profiles, name) and not silent then
+		error("Cannot delete profile '" .. name .. "'. It does not exist.", 2)
+	end
+	
+	self.sv.profiles[name] = nil
+	-- Callback: OnProfileDeleted, database, profileKey
+	self.callbacks:Fire("OnProfileDeleted", self, name)
+	
+	-- populate to child namespaces
+	if self.children then
+		for _, db in pairs(self.children) do
+			DBObjectLib.DeleteProfile(db, name, true)
+		end
+	end
+end
+
+-- DBObject:CopyProfile(name)
+-- name (string) - The name of the profile to be copied into the current profile
+--
+-- Copies a named profile into the current profile, overwriting any conflicting
+-- settings.
+function DBObjectLib:CopyProfile(name, silent)
+	if type(name) ~= "string" then
+		error("Usage: AceDBObject:CopyProfile(name): 'name' - string expected.", 2)
+	end
+	
+	if name == self.keys.profile then
+		error("Cannot have the same source and destination profiles.", 2)
+	end
+	
+	if not rawget(self.sv.profiles, name) and not silent then
+		error("Cannot copy profile '" .. name .. "'. It does not exist.", 2)
+	end
+	
+	-- Reset the profile before copying
+	DBObjectLib.ResetProfile(self)
+	
+	local profile = self.profile
+	local source = self.sv.profiles[name]
+	
+	copyTable(source, profile)
+	
+	-- Callback: OnProfileCopied, database, sourceProfileKey
+	self.callbacks:Fire("OnProfileCopied", self, name)
+	
+	-- populate to child namespaces
+	if self.children then
+		for _, db in pairs(self.children) do
+			DBObjectLib.CopyProfile(db, name, true)
+		end
+	end
+end
+
+-- DBObject:ResetProfile()
+-- 
+-- Resets the current profile
+function DBObjectLib:ResetProfile()
+	local profile = self.profile
+	
+	for k,v in pairs(profile) do
+		profile[k] = nil
+	end
+	
+	local defaults = self.defaults and self.defaults.profile
+	if defaults then
+		copyDefaults(profile, defaults)
+	end
+
+	-- Callback: OnProfileReset, database
+	self.callbacks:Fire("OnProfileReset", self)
+	
+	-- populate to child namespaces
+	if self.children then
+		for _, db in pairs(self.children) do
+			DBObjectLib.ResetProfile(db)
+		end
+	end
+end
+
+-- DBObject:ResetDB(defaultProfile)
+-- defaultProfile (string) - The profile name to use as the default
+--
+-- Resets the entire database, using the string defaultProfile as the default
+-- profile.
+function DBObjectLib:ResetDB(defaultProfile)
+	if defaultProfile and type(defaultProfile) ~= "string" then
+		error("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected.", 2)
+	end
+	
+	local sv = self.sv
+	for k,v in pairs(sv) do
+		sv[k] = nil
+	end
+	
+	local parent = self.parent
+	
+	initdb(sv, self.defaults, defaultProfile, self)
+	
+	-- Callback: OnDatabaseReset, database
+	self.callbacks:Fire("OnDatabaseReset", self)
+	-- Callback: OnProfileChanged, database, profileKey
+	self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
+	
+	-- fix the child namespaces
+	if self.children then
+		if not sv.namespaces then sv.namespaces = {} end
+		for name, db in pairs(self.children) do
+			if not sv.namespaces[name] then sv.namespaces[name] = {} end
+			initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
+		end
+	end
+	
+	return self
+end
+
+-- DBObject:RegisterNamespace(name [, defaults])
+-- name (string) - The name of the new namespace
+-- defaults (table) - A table of values to use as defaults
+--
+-- Creates a new database namespace, directly tied to the database.  This
+-- is a full scale database in it's own rights other than the fact that
+-- it cannot control its profile individually
+function DBObjectLib:RegisterNamespace(name, defaults)
+	if type(name) ~= "string" then
+		error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected.", 2)
+	end
+	if defaults and type(defaults) ~= "table" then
+		error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected.", 2)
+	end
+	if self.children and self.children[name] then
+		error ("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace with that name already exists.", 2)
+	end
+	
+	local sv = self.sv
+	if not sv.namespaces then sv.namespaces = {} end
+	if not sv.namespaces[name] then
+		sv.namespaces[name] = {}
+	end
+	
+	local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
+	
+	if not self.children then self.children = {} end
+	self.children[name] = newDB
+	return newDB
+end
+
+--[[-------------------------------------------------------------------------
+	AceDB Exposed Methods
+---------------------------------------------------------------------------]]
+
+-- AceDB:New(name, defaults, defaultProfile)
+-- name (table or string) - The name of variable, or table to use for the database
+-- defaults (table) - A table of database defaults
+-- defaultProfile (string) - The name of the default profile
+--
+-- Creates a new database object that can be used to handle database settings
+-- and profiles.
+function AceDB:New(tbl, defaults, defaultProfile)
+	if type(tbl) == "string" then
+		local name = tbl
+		tbl = getglobal(name)
+		if not tbl then
+			tbl = {}
+			setglobal(name, tbl)
+		end
+	end
+	
+	if type(tbl) ~= "table" then
+		error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected.", 2)
+	end
+	
+	if defaults and type(defaults) ~= "table" then
+		error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected.", 2)
+	end
+	
+	if defaultProfile and type(defaultProfile) ~= "string" then
+		error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string expected.", 2)
+	end
+	
+	return initdb(tbl, defaults, defaultProfile)
+end
+
+-- upgrade existing databases
+for db in pairs(AceDB.db_registry) do
+	if not db.parent then
+		for name,func in pairs(DBObjectLib) do
+			db[name] = func
+		end
+	else
+		db.RegisterDefaults = DBObjectLib.RegisterDefaults
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceDB-3.0/AceDB-3.0.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="AceDB-3.0.lua"/>
+</Ui>
\ No newline at end of file
--- a/lib/AceEvent-2.0/AceEvent-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1082 +0,0 @@
---[[
-Name: AceEvent-2.0
-Revision: $Rev: 49307 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceEvent-2.0
-SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
-Description: Mixin to allow for event handling, scheduling, and inter-addon
-             communication.
-Dependencies: AceLibrary, AceOO-2.0
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "AceEvent-2.0"
-local MINOR_VERSION = "$Revision: 49307 $"
-
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
-
-local AceOO = AceLibrary:GetInstance("AceOO-2.0")
-local Mixin = AceOO.Mixin
-local AceEvent = Mixin {
-	"RegisterEvent",
-	"RegisterAllEvents",
-	"UnregisterEvent",
-	"UnregisterAllEvents",
-	"TriggerEvent",
-	"ScheduleEvent",
-	"ScheduleRepeatingEvent",
-	"CancelScheduledEvent",
-	"CancelAllScheduledEvents",
-	"IsEventRegistered",
-	"IsEventScheduled",
-	"RegisterBucketEvent",
-	"UnregisterBucketEvent",
-	"UnregisterAllBucketEvents",
-	"IsBucketEventRegistered",
-	"ScheduleLeaveCombatAction",
-	"CancelAllCombatSchedules",
-}
-
-local weakKey = {__mode="k"}
-
-local FAKE_NIL
-local RATE
-
-local eventsWhichHappenOnce = {
-	PLAYER_LOGIN = true,
-	AceEvent_FullyInitialized = true,
-	VARIABLES_LOADED = true,
-	PLAYER_LOGOUT = true,
-}
-local next = next
-local pairs = pairs
-local pcall = pcall
-local type = type
-local GetTime = GetTime
-local gcinfo = gcinfo
-local unpack = unpack
-local geterrorhandler = geterrorhandler
-
-local build = GetBuildInfo()
-local useTablesAsIDs = build:find("^2%.0%.") or build:find("^2%.1%.") or build:find("^0%.1%.")
-
-local new, del
-do
-	local cache = setmetatable({}, {__mode='k'})
-	function new(...)
-		local t = next(cache)
-		if t then
-			cache[t] = nil
-			for i = 1, select('#', ...) do
-				t[i] = select(i, ...)
-			end
-			return t
-		else
-			return { ... }
-		end
-	end
-	function del(t)
-		for k in pairs(t) do
-			t[k] = nil
-		end
-		cache[t] = true
-		return nil
-	end
-end
-
-local registeringFromAceEvent
---[[----------------------------------------------------------------------------------
-Notes:
-	* Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered.
-Arguments:
-	string - name of the event to register
-	[optional] string or function - name of the method or function to call. Default: same name as "event".
-	[optional] boolean - whether to have method called only once. Default: false
-------------------------------------------------------------------------------------]]
-function AceEvent:RegisterEvent(event, method, once)
-	AceEvent:argCheck(event, 2, "string")
-	if self == AceEvent and not registeringFromAceEvent then
-		AceEvent:argCheck(method, 3, "function")
-		self = method
-	else
-		AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
-		if type(method) == "boolean" or type(method) == "number" then
-			AceEvent:argCheck(once, 4, "nil")
-			once, method = method, event
-		end
-	end
-	AceEvent:argCheck(once, 4, "number", "boolean", "nil")
-	if eventsWhichHappenOnce[event] then
-		once = true
-	end
-	local throttleRate
-	if type(once) == "number" then
-		throttleRate, once = once
-	end
-	if not method then
-		method = event
-	end
-	if type(method) == "string" and type(self[method]) ~= "function" then
-		AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
-	else
-		assert(type(method) == "function" or type(method) == "string")
-	end
-
-	local AceEvent_registry = AceEvent.registry
-	if not AceEvent_registry[event] then
-		AceEvent_registry[event] = new()
-		AceEvent.frame:RegisterEvent(event)
-	end
-
-	local remember = true
-	if AceEvent_registry[event][self] then
-		remember = false
-	end
-	AceEvent_registry[event][self] = method
-
-	local AceEvent_onceRegistry = AceEvent.onceRegistry
-	if once then
-		if not AceEvent_onceRegistry then
-			AceEvent.onceRegistry = {}
-			AceEvent_onceRegistry = AceEvent.onceRegistry
-		end
-		if not AceEvent_onceRegistry[event] then
-			AceEvent_onceRegistry[event] = new()
-		end
-		AceEvent_onceRegistry[event][self] = true
-	else
-		if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
-			AceEvent_onceRegistry[event][self] = nil
-			if not next(AceEvent_onceRegistry[event]) then
-				AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
-			end
-		end
-	end
-
-	local AceEvent_throttleRegistry = AceEvent.throttleRegistry
-	if throttleRate then
-		if not AceEvent_throttleRegistry then
-			AceEvent.throttleRegistry = {}
-			AceEvent_throttleRegistry = AceEvent.throttleRegistry
-		end
-		if not AceEvent_throttleRegistry[event] then
-			AceEvent_throttleRegistry[event] = new()
-		end
-		if AceEvent_throttleRegistry[event][self] then
-			AceEvent_throttleRegistry[event][self] = nil
-		end
-		AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
-		local t = AceEvent_throttleRegistry[event][self]
-		t[RATE] = throttleRate
-	else
-		if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
-			if AceEvent_throttleRegistry[event][self] then
-				AceEvent_throttleRegistry[event][self] = nil
-			end
-			if not next(AceEvent_throttleRegistry[event]) then
-				AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
-			end
-		end
-	end
-
-	if remember then
-		AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
-	end
-end
-
-local ALL_EVENTS
-
---[[----------------------------------------------------------------------------------
-Notes:
-	* Registers all events to the given method
-	* To access the current event, check AceEvent.currentEvent
-	* To access the current event's unique identifier, check AceEvent.currentEventUID
-	* This is only for debugging purposes.
-Arguments:
-	[optional] string or function - name of the method or function to call. Default: same name as "event".
-------------------------------------------------------------------------------------]]
-function AceEvent:RegisterAllEvents(method)
-	if self == AceEvent then
-		AceEvent:argCheck(method, 1, "function")
-		self = method
-	else
-		AceEvent:argCheck(method, 1, "string", "function")
-		if type(method) == "string" and type(self[method]) ~= "function" then
-			AceEvent:error("Cannot register all events to method %q, it does not exist", method)
-		end
-	end
-	
-	local AceEvent_registry = AceEvent.registry
-	if not AceEvent_registry[ALL_EVENTS] then
-		AceEvent_registry[ALL_EVENTS] = new()
-		AceEvent.frame:RegisterAllEvents()
-	end
-	
-	local remember = not AceEvent_registry[ALL_EVENTS][self]
-	AceEvent_registry[ALL_EVENTS][self] = method
-	if remember then
-		AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all")
-	end
-end
-
---[[----------------------------------------------------------------------------------
-Notes:
-	* Trigger a custom AceEvent.
-	* This should never be called to simulate fake Blizzard events.
-	* Custom events should be in the form of AddonName_SpecificEvent
-Arguments:
-	string - name of the event
-	tuple - list of arguments to pass along
-------------------------------------------------------------------------------------]]
-function AceEvent:TriggerEvent(event, ...)
-	if type(event) ~= "string" then
-		DEFAULT_CHAT_FRAME:AddMessage(debugstack())
-	end
-	AceEvent:argCheck(event, 2, "string")
-	local AceEvent_registry = AceEvent.registry
-	if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
-		return
-	end
-	local lastEvent = AceEvent.currentEvent
-	AceEvent.currentEvent = event
-	local lastEventUID = AceEvent.currentEventUID
-	local uid = AceEvent.UID_NUM + 1
-	AceEvent.UID_NUM = uid
-	AceEvent.currentEventUID = uid
-
-	local tmp = new()
-
-	local AceEvent_onceRegistry = AceEvent.onceRegistry
-	if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
-		for obj, method in pairs(AceEvent_onceRegistry[event]) do
-			tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
-		end
-		local obj = next(tmp)
-		while obj do
-			local method = tmp[obj]
-			AceEvent.UnregisterEvent(obj, event)
-			if type(method) == "string" then
-				local obj_method = obj[method]
-				if obj_method then
-					local success, err = pcall(obj_method, obj, ...)
-					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-				end
-			elseif method then -- function
-				local success, err = pcall(method, ...)
-				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-			end
-			tmp[obj] = nil
-			obj = next(tmp)
-		end
-	end
-
-	local AceEvent_throttleRegistry = AceEvent.throttleRegistry
-	local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
-	if AceEvent_registry[event] then
-		for obj, method in pairs(AceEvent_registry[event]) do
-			tmp[obj] = method
-		end
-		local obj = next(tmp)
-		while obj do
-			local method = tmp[obj]
-			local continue = false
-			if throttleTable and throttleTable[obj] then
-				local a1 = ...
-				if a1 == nil then
-					a1 = FAKE_NIL
-				end
-				if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
-					throttleTable[obj][a1] = GetTime()
-				else
-					continue = true
-				end
-			end
-			if not continue then
-				if type(method) == "string" then
-					local obj_method = obj[method]
-					if obj_method then
-						local success, err = pcall(obj_method, obj, ...)
-						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-					end
-				elseif method then -- function
-					local success, err = pcall(method, ...)
-					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-				end
-			end
-			tmp[obj] = nil
-			obj = next(tmp)
-		end
-	end
-	if AceEvent_registry[ALL_EVENTS] then
-		for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
-			tmp[obj] = method
-		end
-		local obj = next(tmp)
-		while obj do
-			local method = tmp[obj]
-			if type(method) == "string" then
-				local obj_method = obj[method]
-				if obj_method then
-					local success, err = pcall(obj_method, obj, ...)
-					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-				end
-			elseif method then -- function
-				local success, err = pcall(method, ...)
-				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-			end
-			tmp[obj] = nil
-			obj = next(tmp)
-		end
-	end
-	tmp = del(tmp)
-	AceEvent.currentEvent = lastEvent
-	AceEvent.currentEventUID = lastEventUID
-end
-
-local delayRegistry
-local OnUpdate
-do
-	local tmp = {}
-	OnUpdate = function()
-		local t = GetTime()
-		for k,v in pairs(delayRegistry) do
-			tmp[k] = true
-		end
-		for k in pairs(tmp) do
-			local v = delayRegistry[k]
-			if v then
-				local v_time = v.time
-				if not v_time then
-					delayRegistry[k] = nil
-				elseif v_time <= t then
-					local v_repeatDelay = v.repeatDelay
-					if v_repeatDelay then
-						-- use the event time, not the current time, else timing inaccuracies add up over time
-						v.time = v_time + v_repeatDelay
-					end
-					local event = v.event
-					if type(event) == "function" then
-						local uid = AceEvent.UID_NUM + 1
-						AceEvent.UID_NUM = uid
-						AceEvent.currentEventUID = uid
-						local success, err = pcall(event, unpack(v, 1, v.n))
-						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-						AceEvent.currentEventUID = nil
-					else
-						AceEvent:TriggerEvent(event, unpack(v, 1, v.n))
-					end
-					if not v_repeatDelay then
-						local x = delayRegistry[k]
-						if x and x.time == v_time then -- check if it was manually reset
-							if not useTablesAsIDs or type(k) == "string" then
-								del(delayRegistry[k])
-							end
-							delayRegistry[k] = nil
-						end
-					end
-				end
-			end
-		end
-		for k in pairs(tmp) do
-			tmp[k] = nil
-		end
-		if not next(delayRegistry) then
-			AceEvent.frame:Hide()
-		end
-	end
-end
-
-local function ScheduleEvent(self, repeating, event, delay, ...)
-	local id
-	if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
-		if useTablesAsIDs and type(event) == "table" then
-			if not delayRegistry or not delayRegistry[event] then
-				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
-			end
-		end
-		if type(delay) ~= "number" then
-			id, event, delay = event, delay, ...
-			AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
-			AceEvent:argCheck(delay, 4, "number")
-			self:CancelScheduledEvent(id)
-		end
-	else
-		AceEvent:argCheck(event, 2, "string", "function")
-		AceEvent:argCheck(delay, 3, "number")
-	end
-
-	if not delayRegistry then
-		AceEvent.delayRegistry = {}
-		delayRegistry = AceEvent.delayRegistry
-		AceEvent.frame:SetScript("OnUpdate", OnUpdate)
-	end
-	local t
-	if useTablesAsIDs and type(id) == "table" then
-		for k in pairs(id) do
-			id[k] = nil
-		end
-		t = id
-		for i = 2, select('#', ...) do
-			t[i-1] = select(i, ...)
-		end
-		t.n = select('#', ...) - 1
-	elseif id then
-		t = new(select(2, ...))
-		t.n = select('#', ...) - 1
-	else
-		t = new(...)
-		t.n = select('#', ...)
-	end
-	t.event = event
-	t.time = GetTime() + delay
-	t.self = self
-	t.id = id or t
-	t.repeatDelay = repeating and delay
-	delayRegistry[t.id] = t
-	AceEvent.frame:Show()
-	if useTablesAsIDs then
-		return t.id
-	else
-		return
-	end
-end
-
---[[----------------------------------------------------------------------------------
-Notes:
-	* Schedule an event to fire.
-	* To fire on the next frame, specify a delay of 0.
-Arguments:
-	string or function - name of the event to fire, or a function to call.
-	number - the amount of time to wait until calling.
-	tuple - a list of arguments to pass along.
-------------------------------------------------------------------------------------]]
-function AceEvent:ScheduleEvent(event, delay, ...)
-	if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
-		if useTablesAsIDs and type(event) == "table" then
-			if not delayRegistry or not delayRegistry[event] then
-				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
-			end
-		end
-		if type(delay) ~= "number" then
-			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
-			AceEvent:argCheck(..., 4, "number")
-		end
-	else
-		AceEvent:argCheck(event, 2, "string", "function")
-		AceEvent:argCheck(delay, 3, "number")
-	end
-
-	return ScheduleEvent(self, false, event, delay, ...)
-end
-
-function AceEvent:ScheduleRepeatingEvent(event, delay, ...)
-	if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
-		if useTablesAsIDs and type(event) == "table" then
-			if not delayRegistry or not delayRegistry[event] then
-				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
-			end
-		end
-		if type(delay) ~= "number" then
-			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
-			AceEvent:argCheck(..., 4, "number")
-		end
-	else
-		AceEvent:argCheck(event, 2, "string", "function")
-		AceEvent:argCheck(delay, 3, "number")
-	end
-
-	return ScheduleEvent(self, true, event, delay, ...)
-end
-
-function AceEvent:CancelScheduledEvent(t)
-	if useTablesAsIDs then
-		AceEvent:argCheck(t, 2, "string", "table")
-	else
-		AceEvent:argCheck(t, 2, "string")
-	end
-	if delayRegistry then
-		local v = delayRegistry[t]
-		if v then
-			if not useTablesAsIDs or type(t) == "string" then
-				del(delayRegistry[t])
-			end
-			delayRegistry[t] = nil
-			if not next(delayRegistry) then
-				AceEvent.frame:Hide()
-			end
-			return true
-		end
-	end
-	return false
-end
-
-function AceEvent:IsEventScheduled(t)
-	if useTablesAsIDs then
-		AceEvent:argCheck(t, 2, "string", "table")
-	else
-		AceEvent:argCheck(t, 2, "string")
-	end
-	if delayRegistry then
-		local v = delayRegistry[t]
-		if v then
-			return true, v.time - GetTime()
-		end
-	end
-	return false, nil
-end
-
-function AceEvent:UnregisterEvent(event)
-	AceEvent:argCheck(event, 2, "string")
-	local AceEvent_registry = AceEvent.registry
-	if AceEvent_registry[event] and AceEvent_registry[event][self] then
-		AceEvent_registry[event][self] = nil
-		local AceEvent_onceRegistry = AceEvent.onceRegistry
-		if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
-			AceEvent_onceRegistry[event][self] = nil
-			if not next(AceEvent_onceRegistry[event]) then
-				AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
-			end
-		end
-		local AceEvent_throttleRegistry = AceEvent.throttleRegistry
-		if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
-			AceEvent_throttleRegistry[event][self] = nil
-			if not next(AceEvent_throttleRegistry[event]) then
-				AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
-			end
-		end
-		if not next(AceEvent_registry[event]) then
-			AceEvent_registry[event] = del(AceEvent_registry[event])
-			if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
-				AceEvent.frame:UnregisterEvent(event)
-			end
-		end
-	else
-		if self == AceEvent then
-			error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2)
-		else
-			AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
-		end
-	end
-	AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
-end
-
-function AceEvent:UnregisterAllEvents()
-	local AceEvent_registry = AceEvent.registry
-	if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
-		AceEvent_registry[ALL_EVENTS][self] = nil
-		if not next(AceEvent_registry[ALL_EVENTS]) then
-			AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS])
-			AceEvent.frame:UnregisterAllEvents()
-			for k,v in pairs(AceEvent_registry) do
-				AceEvent.frame:RegisterEvent(k)
-			end
-		end
-	end
-	if AceEvent_registry.AceEvent_EventUnregistered then
-		local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered
-		local x = data[self]
-		data[self] = nil
-		if x then
-			if not next(data) then
-				if not AceEvent_registry[ALL_EVENTS] then
-					AceEvent.frame:UnregisterEvent(event)
-				end
-				AceEvent_registry[event] = del(AceEvent_registry[event])
-			end
-			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
-		end
-	end
-	for event, data in pairs(AceEvent_registry) do
-		local x = data[self]
-		data[self] = nil
-		if x and event ~= ALL_EVENTS then
-			if not next(data) then
-				if not AceEvent_registry[ALL_EVENTS] then
-					AceEvent.frame:UnregisterEvent(event)
-				end
-				AceEvent_registry[event] = del(AceEvent_registry[event])
-			end
-			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
-		end
-	end
-	if AceEvent.onceRegistry then
-		for event, data in pairs(AceEvent.onceRegistry) do
-			data[self] = nil
-		end
-	end
-end
-
-function AceEvent:CancelAllScheduledEvents()
-	if delayRegistry then
-		for k,v in pairs(delayRegistry) do
-			if v.self == self then
-				if not useTablesAsIDs or type(k) == "string" then
-					del(delayRegistry[k])
-				end
-				delayRegistry[k] = nil
-			end
-		end
-		if not next(delayRegistry) then
-			AceEvent.frame:Hide()
-		end
-	end
-end
-
-function AceEvent:IsEventRegistered(event)
-	AceEvent:argCheck(event, 2, "string")
-	local AceEvent_registry = AceEvent.registry
-	if self == AceEvent then
-		return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false
-	end
-	if AceEvent_registry[event] and AceEvent_registry[event][self] then
-		return true, AceEvent_registry[event][self]
-	end
-	if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
-		return true, AceEvent_registry[ALL_EVENTS][self]
-	end
-	return false, nil
-end
-
-local UnitExists = UnitExists
-local bucketfunc
-function AceEvent:RegisterBucketEvent(event, delay, method, ...)
-	AceEvent:argCheck(event, 2, "string", "table")
-	if type(event) == "table" then
-		for k,v in pairs(event) do
-			if type(k) ~= "number" then
-				AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
-			elseif type(v) ~= "string" then
-				AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
-			end
-		end
-	end
-	AceEvent:argCheck(delay, 3, "number")
-	if AceEvent == self then
-		AceEvent:argCheck(method, 4, "function")
-		self = method
-	else
-		if type(event) == "string" then
-			AceEvent:argCheck(method, 4, "string", "function", "nil")
-			if not method then
-				method = event
-			end
-		else
-			AceEvent:argCheck(method, 4, "string", "function")
-		end
-
-		if type(method) == "string" and type(self[method]) ~= "function" then
-			AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
-		end
-	end
-	local buckets = AceEvent.buckets
-	if not buckets[event] then
-		buckets[event] = new()
-	end
-	if not buckets[event][self] then
-		local t = new()
-		t.current = new()
-		t.self = self
-		buckets[event][self] = t
-	else
-		AceEvent.CancelScheduledEvent(self, buckets[event][self].id)
-	end
-	local bucket = buckets[event][self]
-	bucket.method = method
-	
-	local n = select('#', ...)
-	if n > 0 then
-		for i = 1, n do
-			bucket[i] = select(i, ...)
-		end
-	end
-	bucket.n = n
-
-	local func = function(arg1)
-		bucket.run = true
-		if arg1 then
-			bucket.current[arg1] = true
-		end
-	end
-	buckets[event][self].func = func
-	local isUnitBucket = true
-	if type(event) == "string" then
-		AceEvent.RegisterEvent(self, event, func)
-		if not event:find("^UNIT_") then
-			isUnitBucket = false
-		end
-	else
-		for _,v in ipairs(event) do
-			AceEvent.RegisterEvent(self, v, func)
-			if isUnitBucket and not v:find("^UNIT_") then
-				isUnitBucket = false
-			end
-		end
-	end
-	bucket.unit = isUnitBucket
-	if not bucketfunc then
-		bucketfunc = function(bucket)
-			local current = bucket.current
-			local method = bucket.method
-			local self = bucket.self
-			if bucket.run then
-				if bucket.unit then
-					for unit in pairs(current) do
-						if not UnitExists(unit) then
-							current[unit] = nil
-						end
-					end
-				end
-				if type(method) == "string" then
-					self[method](self, current, unpack(bucket, 1, bucket.n))
-				elseif method then -- function
-					method(current, unpack(bucket, 1, bucket.n))
-				end
-				for k in pairs(current) do
-					current[k] = nil
-					k = nil
-				end
-				bucket.run = false
-			end
-		end
-	end
-	bucket.id = "AceEvent-Bucket-" .. tostring(bucket)
-	AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket)
-end
-
-function AceEvent:IsBucketEventRegistered(event)
-	AceEvent:argCheck(event, 2, "string", "table")
-	return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
-end
-
-function AceEvent:UnregisterBucketEvent(event)
-	AceEvent:argCheck(event, 2, "string", "table")
-	if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
-		AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
-	end
-
-	local bucket = AceEvent.buckets[event][self]
-
-	if type(event) == "string" then
-		AceEvent.UnregisterEvent(self, event)
-	else
-		for _,v in ipairs(event) do
-			AceEvent.UnregisterEvent(self, v)
-		end
-	end
-	AceEvent:CancelScheduledEvent(bucket.id)
-
-	bucket.current = del(bucket.current)
-	AceEvent.buckets[event][self] = del(bucket)
-	if not next(AceEvent.buckets[event]) then
-		AceEvent.buckets[event] = del(AceEvent.buckets[event])
-	end
-end
-
-function AceEvent:UnregisterAllBucketEvents()
-	if not AceEvent.buckets or not next(AceEvent.buckets) then
-		return
-	end
-	for k,v in pairs(AceEvent.buckets) do
-		if v == self then
-			AceEvent.UnregisterBucketEvent(self, k)
-			k = nil
-		end
-	end
-end
-
-local combatSchedules
-function AceEvent:CancelAllCombatSchedules()
-	local i = 0
-	while true do
-		i = i + 1
-		if not combatSchedules[i] then
-			break
-		end
-		local v = combatSchedules[i]
-		if v.self == self then
-			v = del(v)
-			table.remove(combatSchedules, i)
-			i = i - 1
-		end
-	end
-end
-
-local inCombat = false
-
-function AceEvent:PLAYER_REGEN_DISABLED()
-	inCombat = true
-end
-
-do
-	local tmp = {}
-	function AceEvent:PLAYER_REGEN_ENABLED()
-		inCombat = false
-		for i, v in ipairs(combatSchedules) do
-			tmp[i] = v
-			combatSchedules[i] = nil
-		end
-		for i, v in ipairs(tmp) do
-			local func = v.func
-			if func then
-				local success, err = pcall(func, unpack(v, 1, v.n))
-				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-			else
-				local obj = v.obj or v.self
-				local method = v.method
-				local obj_method = obj[method]
-				if obj_method then
-					local success, err = pcall(obj_method, obj, unpack(v, 1, v.n))
-					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-				end
-			end
-			tmp[i] = del(v)
-		end
-	end
-end
-
-function AceEvent:ScheduleLeaveCombatAction(method, ...)
-	local style = type(method)
-	if self == AceEvent then
-		if style == "table" then
-			local func = (...)
-			AceEvent:argCheck(func, 3, "string")
-			if type(method[func]) ~= "function" then
-				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
-			end
-		else
-			AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table")
-		end
-		self = method
-	else
-		AceEvent:argCheck(method, 2, "function", "string", "table")
-		if style == "string" and type(self[method]) ~= "function" then
-			AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method)
-		elseif style == "table" then
-			local func = (...)
-			AceEvent:argCheck(func, 3, "string")
-			if type(method[func]) ~= "function" then
-				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
-			end
-		end
-	end
-	
-	if not inCombat then
-		local success, err
-		if type(method) == "function" then
-			success, err = pcall(method, ...)
-		elseif type(method) == "table" then
-			local func = (...)
-			success, err = pcall(method[func], method, select(2, ...))
-		else
-			success, err = pcall(self[method], self, ...)
-		end
-		if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
-		return
-	end
-	local t
-	local n = select('#', ...)
-	if style == "table" then
-		t = new(select(2, ...))
-		t.obj = method
-		t.method = (...)
-		t.n = n-1
-	else
-		t = new(...)
-		t.n = n
-		if style == "function" then
-			t.func = method
-		else
-			t.method = method
-		end
-	end
-	t.self = self
-	table.insert(combatSchedules, t)
-end
-
-function AceEvent:OnEmbedDisable(target)
-	self.UnregisterAllEvents(target)
-
-	self.CancelAllScheduledEvents(target)
-
-	self.UnregisterAllBucketEvents(target)
-	
-	self.CancelAllCombatSchedules(target)
-end
-
-function AceEvent:IsFullyInitialized()
-	return self.postInit or false
-end
-
-function AceEvent:IsPostPlayerLogin()
-	return IsLoggedIn() and true or false
-end
-
-local function activate(self, oldLib, oldDeactivate)
-	AceEvent = self
-	
-	self.onceRegistry = oldLib and oldLib.onceRegistry or {}
-	self.throttleRegistry = oldLib and oldLib.throttleRegistry or {}
-	self.delayRegistry = oldLib and oldLib.delayRegistry or {}
-	self.buckets = oldLib and oldLib.buckets or {}
-	self.registry = oldLib and oldLib.registry or {}
-	self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame")
-	self.playerLogin = IsLoggedIn() and true
-	self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
-	self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy()
-	self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy()
-	self.RATE = oldLib and oldLib.RATE or _G.newproxy()
-	self.combatSchedules = oldLib and oldLib.combatSchedules or {}
-	self.UID_NUM = oldLib and oldLib.UID_NUM or 0
-	
-	-- Delete this down the road.  Makes sure that the addonframes from revisions 33121 - 36174 get their events unregistered.
-	local addonframes = oldLib and oldLib.addonframes
-	if addonframes then
-		for _, v in pairs(addonframes) do
-			v:UnregisterAllEvents()
-		end
-	end
-	
-	combatSchedules = self.combatSchedules
-	ALL_EVENTS = self.ALL_EVENTS
-	FAKE_NIL = self.FAKE_NIL
-	RATE = self.RATE
-	local inPlw = false
-	local blacklist = {
-		UNIT_INVENTORY_CHANGED = true,
-		BAG_UPDATE = true,
-		ITEM_LOCK_CHANGED = true,
-		ACTIONBAR_SLOT_CHANGED = true,
-	}
-	self.frame:SetScript("OnEvent", function(_, event, ...)
-		if event == "PLAYER_ENTERING_WORLD" then
-			inPlw = false
-		elseif event == "PLAYER_LEAVING_WORLD" then
-			inPlw = true
-		end
-		if event and (not inPlw or not blacklist[event]) then
-			self:TriggerEvent(event, ...)
-		end
-	end)
-	if self.delayRegistry then
-		delayRegistry = self.delayRegistry
-		self.frame:SetScript("OnUpdate", OnUpdate)
-	end
-
-	self:UnregisterAllEvents()
-	self:CancelAllScheduledEvents()
-
-	registeringFromAceEvent = true
-	self:RegisterEvent("LOOT_OPENED", function()
-		SendAddonMessage("LOOT_OPENED", "", "RAID")
-	end)
-	registeringFromAceEvent = nil
-
-	local function handleFullInit()
-		if not self.postInit then
-			local function func()
-				self.postInit = true
-				self:TriggerEvent("AceEvent_FullyInitialized")
-				if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
-					self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
-				end
-				if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
-					self:UnregisterEvent("MEETINGSTONE_CHANGED")
-				end
-				if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
-					self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
-				end
-				if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
-					self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
-				end
-				collectgarbage('collect')
-			end
-			registeringFromAceEvent = true
-			local f = function()
-				self.playerLogin = true
-				self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
-			end
-			self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
-			self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
-				self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15)
-			end)
-			self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
-				if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
-					registeringFromAceEvent = true
-					self:UnregisterEvent("MEETINGSTONE_CHANGED")
-					self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true)
-					registeringFromAceEvent = nil
-				end
-			end)
-			self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
-			registeringFromAceEvent = nil
-		end
-	end
-	
-	if not self.playerLogin then
-		registeringFromAceEvent = true
-		self:RegisterEvent("PLAYER_LOGIN", function()
-			self.playerLogin = true
-			handleFullInit()
-			handleFullInit = nil
-			collectgarbage('collect')
-		end, true)
-		registeringFromAceEvent = nil
-	else
-		handleFullInit()
-		handleFullInit = nil
-	end
-	
-	if not AceEvent20EditBox then
-	    CreateFrame("Editbox", "AceEvent20EditBox")
-	end
-	local editbox = AceEvent20EditBox
-	function editbox:Execute(line)
-		local defaulteditbox = DEFAULT_CHAT_FRAME.editBox
-		self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType"))
-		self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget"))
-		self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget"))
-		self:SetText(line)
-		ChatEdit_SendText(self)
-	end
-	editbox:Hide()
-	_G["SLASH_IN1"] = "/in"
-	SlashCmdList["IN"] = function(msg)
-		local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$")
-		seconds = tonumber(seconds)
-		if not seconds then
-			DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'")
-			return
-		end
-		if IsSecureCmd(command) then
-			DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command))
-			return
-		end
-		self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest)
-	end
-	registeringFromAceEvent = true
-	self:RegisterEvent("PLAYER_REGEN_ENABLED")
-	self:RegisterEvent("PLAYER_REGEN_DISABLED")
-	inCombat = InCombatLockdown()
-	registeringFromAceEvent = nil
-	
-	-- another hack to make sure that we clean up properly from rev 33121 - 36174
-	if self.registry[ALL_EVENTS] then
-		self.frame:RegisterAllEvents()
-	else
-		for event in pairs(self.registry) do
-			self.frame:RegisterEvent(event)
-		end
-	end
-	
-	self:activate(oldLib, oldDeactivate)
-	if oldLib then
-		oldDeactivate(oldLib)
-	end
-end
-
-AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
--- a/lib/AceEvent-2.0/AceEvent-2.0.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceEvent-2.0
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary, AceOO-2.0
- 
-AceEvent-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceEvent-3.0/AceEvent-3.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,76 @@
+--[[ $Id: AceEvent-3.0.lua 60131 2008-02-03 13:03:56Z nevcairiel $ ]]
+local MAJOR, MINOR = "AceEvent-3.0", 3
+local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceEvent then return end
+
+local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
+
+
+AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
+AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
+
+
+-- APIs and registry for blizzard events, using CallbackHandler lib
+if not AceEvent.events then
+	AceEvent.events = CallbackHandler:New(AceEvent, 
+		"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
+end
+
+function AceEvent.events:OnUsed(target, eventname) 
+	AceEvent.frame:RegisterEvent(eventname)
+end
+
+function AceEvent.events:OnUnused(target, eventname) 
+	AceEvent.frame:UnregisterEvent(eventname)
+end
+
+
+-- APIs and registry for IPC messages, using CallbackHandler lib
+if not AceEvent.messages then
+	AceEvent.messages = CallbackHandler:New(AceEvent, 
+		"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
+	)
+	AceEvent.SendMessage = AceEvent.messages.Fire
+end
+
+--- embedding and embed handling
+local mixins = {
+	"RegisterEvent", "UnregisterEvent",
+	"RegisterMessage", "UnregisterMessage",
+	"SendMessage",
+	"UnregisterAllEvents", "UnregisterAllMessages",
+} 
+
+-- AceEvent:Embed( target )
+-- target (object) - target object to embed AceEvent in
+--
+-- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
+function AceEvent:Embed(target)
+	for k, v in pairs(mixins) do
+		target[v] = self[v]
+	end
+	self.embeds[target] = true
+	return target
+end
+
+-- AceEvent:OnEmbedDisable( target )
+-- target (object) - target object that is being disabled
+--
+-- Unregister all events messages etc when the target disables.
+-- this method should be called by the target manually or by an addon framework
+function AceEvent:OnEmbedDisable(target)
+	target:UnregisterAllEvents()
+	target:UnregisterAllMessages()
+end
+
+-- Script to fire blizzard events into the event listeners
+local events = AceEvent.events
+AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
+	events:Fire(event, ...)
+end)
+
+--- Finally: upgrade our old embeds
+for target, v in pairs(AceEvent.embeds) do
+	AceEvent:Embed(target)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceEvent-3.0/AceEvent-3.0.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="AceEvent-3.0.lua"/>
+</Ui>
\ No newline at end of file
--- a/lib/AceLibrary/AceLibrary.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,856 +0,0 @@
---[[
-Name: AceLibrary
-Revision: $Rev: 49421 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Iriel (iriel@vigilance-committee.org)
-             Tekkub (tekkub@gmail.com)
-             Revision: $Rev: 49421 $
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceLibrary
-SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
-Description: Versioning library to handle other library instances, upgrading,
-             and proper access.
-             It also provides a base for libraries to work off of, providing
-             proper error tools. It is handy because all the errors occur in the
-             file that called it, not in the library file itself.
-Dependencies: None
-License: LGPL v2.1
-]]
-
-local ACELIBRARY_MAJOR = "AceLibrary"
-local ACELIBRARY_MINOR = "$Revision: 49421 $"
-
-local _G = getfenv(0)
-local previous = _G[ACELIBRARY_MAJOR]
-if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
-
-do
-	-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
-	-- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
-	local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
-	local LibStub = _G[LIBSTUB_MAJOR]
-
-	if not LibStub or LibStub.minor < LIBSTUB_MINOR then
-		LibStub = LibStub or {libs = {}, minors = {} }
-		_G[LIBSTUB_MAJOR] = LibStub
-		LibStub.minor = LIBSTUB_MINOR
-		
-		function LibStub:NewLibrary(major, minor)
-			assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
-			minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
-			local oldminor = self.minors[major]
-			if oldminor and oldminor >= minor then return nil end
-			self.minors[major], self.libs[major] = minor, self.libs[major] or {}
-			return self.libs[major], oldminor
-		end
-		
-		function LibStub:GetLibrary(major, silent)
-			if not self.libs[major] and not silent then
-				error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
-			end
-			return self.libs[major], self.minors[major]
-		end
-		
-		function LibStub:IterateLibraries() return pairs(self.libs) end
-		setmetatable(LibStub, { __call = LibStub.GetLibrary })
-	end
-end
-local LibStub = _G.LibStub
-
--- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
--- disabled in the addon screen, set this to true.
-local DONT_ENABLE_LIBRARIES = nil
-
-local function safecall(func,...)
-    local success, err = pcall(func,...)
-    if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
-end
-
-local WoW22 = false
-if type(GetBuildInfo) == "function" then
-	local success, buildinfo = pcall(GetBuildInfo)
-	if success and type(buildinfo) == "string" then
-		local num = tonumber(buildinfo:match("^(%d+%.%d+)"))
-		if num and num >= 2.2 then
-			WoW22 = true
-		end
-	end
-end
-
--- @table AceLibrary
--- @brief System to handle all versioning of libraries.
-local AceLibrary = {}
-local AceLibrary_mt = {}
-setmetatable(AceLibrary, AceLibrary_mt)
-
-local function error(self, message, ...)
-	if type(self) ~= "table" then
-		return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
-	end
-	
-	local stack = debugstack()
-	if not message then
-		local second = stack:match("\n(.-)\n")
-		message = "error raised! " .. second
-	else
-		local arg = { ... } -- not worried about table creation, as errors don't happen often
-		
-		for i = 1, #arg do
-			arg[i] = tostring(arg[i])
-		end
-		for i = 1, 10 do
-			table.insert(arg, "nil")
-		end
-		message = message:format(unpack(arg))
-	end
-	
-	if getmetatable(self) and getmetatable(self).__tostring then
-		message = ("%s: %s"):format(tostring(self), message)
-	elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
-		message = ("%s: %s"):format(self:GetLibraryVersion(), message)
-	elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
-		message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
-	end
-	
-	local first = stack:gsub("\n.*", "")
-	local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
-	file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
-	
-	
-	local i = 0
-	for s in stack:gmatch("\n([^\n]*)") do
-		i = i + 1
-		if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
-			file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
-			file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
-			break
-		end
-	end
-	local j = 0
-	for s in stack:gmatch("\n([^\n]*)") do
-		j = j + 1
-		if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
-			return _G.error(message, j+1)
-		end
-	end
-	return _G.error(message, 2)
-end
-
-local assert
-if not WoW22 then
-	function assert(self, condition, message, ...)
-		if not condition then
-			if not message then
-				local stack = debugstack()
-				local second = stack:match("\n(.-)\n")
-				message = "assertion failed! " .. second
-			end
-			return error(self, message, ...)
-		end
-		return condition
-	end
-end
-
-local type = type
-local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
-	if type(num) ~= "number" then
-		return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
-	elseif type(kind) ~= "string" then
-		return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
-	end
-	arg = type(arg)
-	if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
-		local stack = debugstack()
-		local func = stack:match("`argCheck'.-([`<].-['>])")
-		if not func then
-			func = stack:match("([`<].-['>])")
-		end
-		if kind5 then
-			return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
-		elseif kind4 then
-			return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
-		elseif kind3 then
-			return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
-		elseif kind2 then
-			return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
-		else
-			return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
-		end
-	end
-end
-
-local pcall
-do
-	local function check(self, ret, ...)
-		if not ret then
-			local s = ...
-			return error(self, (s:gsub(".-%.lua:%d-: ", "")))
-		else
-			return ...
-		end
-	end
-
-	function pcall(self, func, ...)
-		return check(self, _G.pcall(func, ...))
-	end
-end
-
-local recurse = {}
-local function addToPositions(t, major)
-	if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
-		rawset(t, recurse, true)
-		AceLibrary.positions[t] = major
-		for k,v in pairs(t) do
-			if type(v) == "table" and not rawget(v, recurse) then
-				addToPositions(v, major)
-			end
-			if type(k) == "table" and not rawget(k, recurse) then
-				addToPositions(k, major)
-			end
-		end
-		local mt = getmetatable(t)
-		if mt and not rawget(mt, recurse) then
-			addToPositions(mt, major)
-		end
-		rawset(t, recurse, nil)
-	end
-end
-
-local function svnRevisionToNumber(text)
-	local kind = type(text)
-	if kind == "number" or tonumber(text) then
-		return tonumber(text)
-	elseif kind == "string" then
-		if text:find("^%$Revision: (%d+) %$$") then
-			return tonumber((text:match("^%$Revision: (%d+) %$$")))
-		elseif text:find("^%$Rev: (%d+) %$$") then
-			return tonumber((text:match("^%$Rev: (%d+) %$$")))
-		elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
-			return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
-		end
-	end
-	return nil
-end
-
-local crawlReplace
-do
-	local recurse = {}
-	local function func(t, to, from)
-		if recurse[t] then
-			return
-		end
-		recurse[t] = true
-		local mt = getmetatable(t)
-		setmetatable(t, nil)
-		rawset(t, to, rawget(t, from))
-		rawset(t, from, nil)
-		for k,v in pairs(t) do
-			if v == from then
-				t[k] = to
-			elseif type(v) == "table" then
-				if not recurse[v] then
-					func(v, to, from)
-				end
-			end
-			
-			if type(k) == "table" then
-				if not recurse[k] then
-					func(k, to, from)
-				end
-			end
-		end
-		setmetatable(t, mt)
-		if mt then
-			if mt == from then
-				setmetatable(t, to)
-			elseif not recurse[mt] then
-				func(mt, to, from)
-			end
-		end
-	end
-	function crawlReplace(t, to, from)
-		func(t, to, from)
-		for k in pairs(recurse) do
-			recurse[k] = nil
-		end
-	end
-end
-
--- @function destroyTable
--- @brief    remove all the contents of a table
--- @param t  table to destroy
-local function destroyTable(t)
-	setmetatable(t, nil)
-	for k,v in pairs(t) do
-		t[k] = nil 
-	end
-end
-
-local function isFrame(frame)
-	return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
-end
-
--- @function   copyTable
--- @brief      Create a shallow copy of a table and return it.
--- @param from The table to copy from
--- @return     A shallow copy of the table
-local function copyTable(from, to)
-	if not to then
-		to = {}
-	end
-	for k,v in pairs(from) do
-		to[k] = v
-	end
-	setmetatable(to, getmetatable(from))
-	return to
-end
-
--- @function         deepTransfer
--- @brief            Fully transfer all data, keeping proper previous table
---                   backreferences stable.
--- @param to         The table with which data is to be injected into
--- @param from       The table whose data will be injected into the first
--- @param saveFields If available, a shallow copy of the basic data is saved
---                   in here.
--- @param list       The account of table references
--- @param list2      The current status on which tables have been traversed.
-local deepTransfer
-do
-	-- @function   examine
-	-- @brief      Take account of all the table references to be shared
-	--             between the to and from tables.
-	-- @param to   The table with which data is to be injected into
-	-- @param from The table whose data will be injected into the first
-	-- @param list An account of the table references
-	local function examine(to, from, list, major)
-		list[from] = to
-		for k,v in pairs(from) do
-			if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
-				if from[k] == to[k] then
-					list[from[k]] = to[k]
-				elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
-					list[from[k]] = from[k]
-				elseif not list[from[k]] then
-					examine(to[k], from[k], list, major)
-				end
-			end
-		end
-		return list
-	end
-	
-	function deepTransfer(to, from, saveFields, major, list, list2)
-		setmetatable(to, nil)
-		if not list then
-			list = {}
-			list2 = {}
-			examine(to, from, list, major)
-		end
-		list2[to] = to
-		for k,v in pairs(to) do
-			if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
-				if saveFields then
-					saveFields[k] = v
-				end
-				to[k] = nil
-			elseif v ~= _G then
-				if saveFields then
-					saveFields[k] = copyTable(v)
-				end
-			end
-		end
-		for k in pairs(from) do
-			if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
-				if not list2[to[k]] then
-					deepTransfer(to[k], from[k], nil, major, list, list2)
-				end
-				to[k] = list[to[k]] or list2[to[k]]
-			else
-				rawset(to, k, from[k])
-			end
-		end
-		setmetatable(to, getmetatable(from))
-		local mt = getmetatable(to)
-		if mt then
-			if list[mt] then
-				setmetatable(to, list[mt])
-			elseif mt.__index and list[mt.__index] then
-				mt.__index = list[mt.__index]
-			end
-		end
-		destroyTable(from)
-	end
-end
-
-local function TryToEnable(addon)
-	if DONT_ENABLE_LIBRARIES then return end
-	local isondemand = IsAddOnLoadOnDemand(addon)
-	if isondemand then
-		local _, _, _, enabled = GetAddOnInfo(addon)
-		EnableAddOn(addon)
-		local _, _, _, _, loadable = GetAddOnInfo(addon)
-		if not loadable and not enabled then
-			DisableAddOn(addon)
-		end
-
-		return loadable
-	end
-end
-
--- @method      TryToLoadStandalone
--- @brief       Attempt to find and load a standalone version of the requested library
--- @param major A string representing the major version
--- @return      If library is found and loaded, true is return. If not loadable, false is returned.
---              If the library has been requested previously, nil is returned.
-local function TryToLoadStandalone(major)
-	if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
-	if AceLibrary.scannedlibs[major] then return end
-
-	AceLibrary.scannedlibs[major] = true
-
-	local name, _, _, enabled, loadable = GetAddOnInfo(major)
-	
-	loadable = (enabled and loadable) or TryToEnable(name)
-	
-	local loaded = false
-	if loadable then
-		loaded = true
-		LoadAddOn(name)
-	end
-	
-	local field = "X-AceLibrary-" .. major 
-	for i = 1, GetNumAddOns() do
-		if GetAddOnMetadata(i, field) then
-			name, _, _, enabled, loadable = GetAddOnInfo(i)
-			
-			loadable = (enabled and loadable) or TryToEnable(name)
-			if loadable then
-				loaded = true
-				LoadAddOn(name)
-			end
-		end
-	end
-	return loaded
-end
-
--- @method      IsNewVersion
--- @brief       Obtain whether the supplied version would be an upgrade to the
---              current version. This allows for bypass code in library
---              declaration.
--- @param major A string representing the major version
--- @param minor An integer or an svn revision string representing the minor version
--- @return      whether the supplied version would be newer than what is
---              currently available.
-function AceLibrary:IsNewVersion(major, minor)
-	argCheck(self, major, 2, "string")
-	TryToLoadStandalone(major)
-
-	if type(minor) == "string" then
-		local m = svnRevisionToNumber(minor)
-		if m then
-			minor = m
-		else
-			_G.error(("Bad argument #3 to  `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
-		end
-	end
-	argCheck(self, minor, 3, "number")
-	local lib, oldMinor = LibStub:GetLibrary(major, true)
-	if lib then
-		return oldMinor < minor
-	end
-	local data = self.libs[major]
-	if not data then
-		return true
-	end
-	return data.minor < minor
-end
-
--- @method      HasInstance
--- @brief       Returns whether an instance exists. This allows for optional support of a library.
--- @param major A string representing the major version.
--- @param minor (optional) An integer or an svn revision string representing the minor version.
--- @return      Whether an instance exists.
-function AceLibrary:HasInstance(major, minor)
-	argCheck(self, major, 2, "string")
-	if minor ~= false then
-		TryToLoadStandalone(major)
-	end
-	
-	local lib, ver = LibStub:GetLibrary(major, true)
-	if not lib and self.libs[major] then
-		lib, ver = self.libs[major].instance, self.libs[major].minor
-	end
-	if minor then
-		if type(minor) == "string" then
-			local m = svnRevisionToNumber(minor)
-			if m then
-				minor = m
-			else
-				_G.error(("Bad argument #3 to  `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
-			end
-		end
-		argCheck(self, minor, 3, "number")
-		if not lib then
-			return false
-		end
-		return ver == minor
-	end
-	return not not lib
-end
-
--- @method      GetInstance
--- @brief       Returns the library with the given major/minor version.
--- @param major A string representing the major version.
--- @param minor (optional) An integer or an svn revision string representing the minor version.
--- @return      The library with the given major/minor version.
-function AceLibrary:GetInstance(major, minor)
-	argCheck(self, major, 2, "string")
-	if minor ~= false then
-		TryToLoadStandalone(major)
-	end
-
-	local data, ver = LibStub:GetLibrary(major, true)
-	if not data then
-		if self.libs[major] then
-			data, ver = self.libs[major].instance, self.libs[major].minor
-		else
-			_G.error(("Cannot find a library instance of %s."):format(major), 2)
-			return
-		end
-	end
-	if minor then
-		if type(minor) == "string" then
-			local m = svnRevisionToNumber(minor)
-			if m then
-				minor = m
-			else
-				_G.error(("Bad argument #3 to  `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
-			end
-		end
-		argCheck(self, minor, 2, "number")
-		if ver ~= minor then
-			_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
-		end
-	end
-	return data
-end
-
--- Syntax sugar.  AceLibrary("FooBar-1.0")
-AceLibrary_mt.__call = AceLibrary.GetInstance
-
-local donothing = function() end
-
-local AceEvent
-
-local tmp = {}
-
--- @method               Register
--- @brief                Registers a new version of a given library.
--- @param newInstance    the library to register
--- @param major          the major version of the library
--- @param minor          the minor version of the library
--- @param activateFunc   (optional) A function to be called when the library is
---                       fully activated. Takes the arguments
---                       (newInstance [, oldInstance, oldDeactivateFunc]). If
---                       oldInstance is given, you should probably call
---                       oldDeactivateFunc(oldInstance).
--- @param deactivateFunc (optional) A function to be called by a newer library's
---                       activateFunc.
--- @param externalFunc   (optional) A function to be called whenever a new
---                       library is registered.
-function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
-	argCheck(self, newInstance, 2, "table")
-	argCheck(self, major, 3, "string")
-	if major ~= ACELIBRARY_MAJOR then
-		for k,v in pairs(_G) do
-			if v == newInstance then
-				geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
-			end
-		end
-	end
-	if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
-		_G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
-	end
-	if type(minor) == "string" then
-		local m = svnRevisionToNumber(minor)
-		if m then
-			minor = m
-		else
-			_G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
-		end
-	end
-	argCheck(self, minor, 4, "number")
-	if math.floor(minor) ~= minor or minor < 0 then
-		error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
-	end
-	argCheck(self, activateFunc, 5, "function", "nil")
-	argCheck(self, deactivateFunc, 6, "function", "nil")
-	argCheck(self, externalFunc, 7, "function", "nil")
-	if not deactivateFunc then
-		deactivateFunc = donothing
-	end
-	local data = self.libs[major]
-	if not data then
-		-- This is new
-		if LibStub:GetLibrary(major, true) then
-			error(self, "Cannot register library %q. It is already registered with LibStub.", major)
-		end
-		local instance = LibStub:NewLibrary(major, minor)
-		copyTable(newInstance, instance)
-		crawlReplace(instance, instance, newInstance)
-		destroyTable(newInstance)
-		if AceLibrary == newInstance then
-			self = instance
-			AceLibrary = instance
-		end
-		self.libs[major] = {
-			instance = instance,
-			minor = minor,
-			deactivateFunc = deactivateFunc,
-			externalFunc = externalFunc,
-		}
-		rawset(instance, 'GetLibraryVersion', function(self)
-			return major, minor
-		end)
-		if not rawget(instance, 'error') then
-			rawset(instance, 'error', error)
-		end
-		if not WoW22 and not rawget(instance, 'assert') then
-			rawset(instance, 'assert', assert)
-		end
-		if not rawget(instance, 'argCheck') then
-			rawset(instance, 'argCheck', argCheck)
-		end
-		if not rawget(instance, 'pcall') then
-			rawset(instance, 'pcall', pcall)
-		end
-		addToPositions(instance, major)
-		if activateFunc then
-			safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
-			
---[[			if major ~= ACELIBRARY_MAJOR then
-				for k,v in pairs(_G) do
-					if v == instance then
-						geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
-					end
-				end
-			end]]
-		end
-		
-		if externalFunc then
-			for k, data_instance in LibStub:IterateLibraries() do -- all libraries
-				tmp[k] = data_instance
-			end
-			for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
-				tmp[k] = data.instance
-			end
-			for k, data_instance in pairs(tmp) do
-				if k ~= major then
-					safecall(externalFunc, instance, k, data_instance)
-				end
-				tmp[k] = nil
-			end
-		end
-		
-		for k,data in pairs(self.libs) do -- only Ace libraries
-			if k ~= major and data.externalFunc then
-				safecall(data.externalFunc, data.instance, major, instance)
-			end
-		end
-		if major == "AceEvent-2.0" then
-			AceEvent = instance
-		end
-		if AceEvent then
-			AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
-		end
-		
-		return instance
-	end
-	if minor <= data.minor then
-		-- This one is already obsolete, raise an error.
-		_G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
-		return
-	end
-	local instance = data.instance
-	-- This is an update
-	local oldInstance = {}
-	
-	local libStubInstance = LibStub:GetLibrary(major, true)
-	if not libStubInstance then -- non-LibStub AceLibrary registered the library
-		-- pass
-	elseif libStubInstance ~= instance then	
-		error(self, "Cannot register library %q. It is already registered with LibStub.", major)
-	else
-		LibStub:NewLibrary(major, minor) -- upgrade the minor version
-	end
-	
-	addToPositions(newInstance, major)
-	local isAceLibrary = (AceLibrary == newInstance)
-	local old_error, old_assert, old_argCheck, old_pcall
-	if isAceLibrary then
-		self = instance
-		AceLibrary = instance
-		
-		old_error = instance.error
-		if not WoW22 then
-			old_assert = instance.assert
-		end
-		old_argCheck = instance.argCheck
-		old_pcall = instance.pcall
-		
-		self.error = error
-		if not WoW22 then
-			self.assert = assert
-		end
-		self.argCheck = argCheck
-		self.pcall = pcall
-	end
-	deepTransfer(instance, newInstance, oldInstance, major)
-	crawlReplace(instance, instance, newInstance)
-	local oldDeactivateFunc = data.deactivateFunc
-	data.minor = minor
-	data.deactivateFunc = deactivateFunc
-	data.externalFunc = externalFunc
-	rawset(instance, 'GetLibraryVersion', function()
-		return major, minor
-	end)
-	if not rawget(instance, 'error') then
-		rawset(instance, 'error', error)
-	end
-	if not WoW22 and not rawget(instance, 'assert') then
-		rawset(instance, 'assert', assert)
-	end
-	if not rawget(instance, 'argCheck') then
-		rawset(instance, 'argCheck', argCheck)
-	end
-	if not rawget(instance, 'pcall') then
-		rawset(instance, 'pcall', pcall)
-	end
-	if isAceLibrary then
-		for _,v in pairs(self.libs) do
-			local i = type(v) == "table" and v.instance
-			if type(i) == "table" then
-				if not rawget(i, 'error') or i.error == old_error then
-					rawset(i, 'error', error)
-				end
-				if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then
-					rawset(i, 'assert', assert)
-				end
-				if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
-					rawset(i, 'argCheck', argCheck)
-				end
-				if not rawget(i, 'pcall') or i.pcall == old_pcall then
-					rawset(i, 'pcall', pcall)
-				end
-			end
-		end
-	end
-	if activateFunc then
-		safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)	
-				
---[[		if major ~= ACELIBRARY_MAJOR then
-			for k,v in pairs(_G) do
-				if v == instance then
-					geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
-				end
-			end
-		end]]
-	else
-		safecall(oldDeactivateFunc, oldInstance)
-	end
-	oldInstance = nil
-	
-	if externalFunc then
-		for k, data_instance in LibStub:IterateLibraries() do -- all libraries
-			tmp[k] = data_instance
-		end
-		for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
-			tmp[k] = data.instance
-		end
-		for k, data_instance in pairs(tmp) do
-			if k ~= major then
-				safecall(externalFunc, instance, k, data_instance)
-			end
-			tmp[k] = nil
-		end
-	end
-	
-	return instance
-end
-
-function AceLibrary:IterateLibraries()
-	local t = {}
-	for major, instance in LibStub:IterateLibraries() do
-		t[major] = instance
-	end
-	for major, data in pairs(self.libs) do
-		t[major] = data.instance
-	end
-	return pairs(t)
-end
-
-local function manuallyFinalize(major, instance)
-	if AceLibrary.libs[major] then
-		-- don't work on Ace libraries
-		return
-	end
-	local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
-	if finalizedExternalLibs[major] then
-		return
-	end
-	finalizedExternalLibs[major] = true
-	
-	for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
-		if k ~= major and data.externalFunc then
-			safecall(data.externalFunc, data.instance, major, instance)
-		end
-	end
-end
-
--- @function            Activate
--- @brief               The activateFunc for AceLibrary itself. Called when
---                      AceLibrary properly registers.
--- @param self          Reference to AceLibrary
--- @param oldLib        (optional) Reference to an old version of AceLibrary
--- @param oldDeactivate (optional) Function to deactivate the old lib
-local function activate(self, oldLib, oldDeactivate)
-	AceLibrary = self
-	if not self.libs then
-		self.libs = oldLib and oldLib.libs or {}
-		self.scannedlibs = oldLib and oldLib.scannedlibs or {}
-	end
-	if not self.positions then
-		self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
-	end
-	self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
-	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
-	self.frame:UnregisterAllEvents()
-	self.frame:RegisterEvent("ADDON_LOADED")
-	self.frame:SetScript("OnEvent", function()
-		for major, instance in LibStub:IterateLibraries() do
-			manuallyFinalize(major, instance)
-		end
-	end)
-	for major, instance in LibStub:IterateLibraries() do
-		manuallyFinalize(major, instance)
-	end
-	
-	-- Expose the library in the global environment
-	_G[ACELIBRARY_MAJOR] = self
-	
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-if not previous then
-	previous = AceLibrary
-end
-if not previous.libs then
-	previous.libs = {}
-end
-AceLibrary.libs = previous.libs
-if not previous.positions then
-	previous.positions = setmetatable({}, { __mode = "k" })
-end
-AceLibrary.positions = previous.positions
-AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- a/lib/AceLibrary/AceLibrary.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceLibrary
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
- 
-AceLibrary.lua
--- a/lib/AceLocale-2.2/AceLocale-2.2.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,669 +0,0 @@
---[[
-Name: AceLocale-2.2
-Revision: $Rev: 40629 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceLocale-2.2
-SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2
-Description: Localization library for addons to use to handle proper
-             localization and internationalization.
-Dependencies: AceLibrary
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "AceLocale-2.2"
-local MINOR_VERSION = "$Revision: 40629 $"
-
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-local AceLocale = {}
-AceLocale.prototype = { class = AceLocale }
-
-local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME
-
-local _G = _G
-local rawget = rawget
-local rawset = rawset
-local type = type
-local pairs = pairs
-local next = next
-local getmetatable = getmetatable
-local setmetatable = setmetatable
-local GetTime = GetTime
-local geterrorhandler = geterrorhandler
-local pcall = pcall
-local ipairs = ipairs
-local GetLocale = GetLocale
-
-local newRegistries = {}
-local scheduleClear
-
-local lastSelf
-local strict__index = function(self, key)
-	lastSelf = self
-	local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key]
-	rawset(self, key, value)
-	return value
-end
-local nonstrict__index = function(self, key)
-	lastSelf = self
-	local t = rawget(self, TRANSLATIONS)
-	if t then
-		local value = rawget(t, key)
-		if value then
-			rawset(self, key, value)
-			return value
-		end
-	end
-	local value = (rawget(self, BASE_TRANSLATIONS) or AceLocale.prototype)[key]
-	rawset(self, key, value)
-	return value
-end
-
-local __newindex = function(self, k, v)
-	if type(v) ~= "function" and type(k) ~= "table" then
-		AceLocale.error(self, "Cannot change the values of an AceLocale instance.")
-	end
-	rawset(self, k, v)
-end
-
-local __tostring = function(self)
-	if type(rawget(self, 'GetLibraryVersion')) == "function" then
-		return self:GetLibraryVersion()
-	else
-		return "AceLocale(" .. self[NAME] .. ")"
-	end
-end
-
-local function clearCache(self)
-	for k, v in pairs(AceLocale.prototype) do
-		if type(v) == "function" and type(rawget(self, k)) == "function" then
-			self[k] = nil
-		end
-	end
-	if not rawget(self, BASE_TRANSLATIONS) then
-		return
-	end
-	
-	local cache = self[BASE_TRANSLATIONS]
-	rawset(self, REVERSE_TRANSLATIONS, nil)
-	
-	for k in pairs(self) do
-		if rawget(cache, k) ~= nil then
-			self[k] = nil
-		end
-	end
-	rawset(self, 'tmp', true)
-	self.tmp = nil
-end
-
-local strict_instance_mt, nonstrict_instance_mt
-local baseTranslations_mt
-
-local function refixInstance(instance)
-	if getmetatable(instance) then
-		setmetatable(instance, nil)
-	end
-	local translations = instance[TRANSLATIONS]
-	if translations then
-		if getmetatable(translations) then
-			setmetatable(translations, nil)
-		end
-		local baseTranslations = instance[BASE_TRANSLATIONS]
-		if getmetatable(baseTranslations) then
-			setmetatable(baseTranslations, nil)
-		end
-		if translations == baseTranslations or instance[STRICTNESS] then
-			setmetatable(instance, strict_instance_mt)
-			
-			setmetatable(translations, baseTranslations_mt)
-		else
-			setmetatable(instance, nonstrict_instance_mt)
-			
-			setmetatable(baseTranslations, baseTranslations_mt)
-		end
-	else
-		setmetatable(instance, strict_instance_mt)
-	end
-	clearCache(instance)
-	newRegistries[instance] = true
-	scheduleClear()
-	return instance
-end
-
-function AceLocale:new(name)
-	self:argCheck(name, 2, "string")
-	
-	if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then
-		return self.registry[name]
-	end
-	
-	AceLocale.registry[name] = refixInstance({
-		[STRICTNESS] = false,
-		[NAME] = name,
-	})
-	newRegistries[AceLocale.registry[name]] = true
-	return AceLocale.registry[name]
-end
-
-function AceLocale.prototype:EnableDebugging()
-	if rawget(self, BASE_TRANSLATIONS) then
-		AceLocale.error(self, "Cannot enable debugging after a translation has been registered.")
-	end
-	rawset(self, DEBUGGING, true)
-end
-
-function AceLocale.prototype:EnableDynamicLocales(override)
-	AceLocale.argCheck(self, override, 2, "boolean", "nil")
-	if not override and rawget(self, BASE_TRANSLATIONS) then
-		AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.")
-	end
-	if not rawget(self, DYNAMIC_LOCALES) then
-		rawset(self, DYNAMIC_LOCALES, true)
-		if rawget(self, BASE_LOCALE) then
-			if not rawget(self, TRANSLATION_TABLES) then
-				rawset(self, TRANSLATION_TABLES, {})
-			end
-			self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS]
-			self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS]
-		end
-	end
-end
-
-function AceLocale.prototype:RegisterTranslations(locale, func)
-	AceLocale.argCheck(self, locale, 2, "string")
-	AceLocale.argCheck(self, func, 3, "function")
-	
-	if locale == rawget(self, BASE_LOCALE) then
-		AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
-	end
-	
-	if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then
-		if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
-			if not rawget(self, TRANSLATION_TABLES) then
-				rawset(self, TRANSLATION_TABLES, {})
-			end
-			if self[TRANSLATION_TABLES][locale] then
-				AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
-			end
-			local t = func()
-			func = nil
-			if type(t) ~= "table" then
-				AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
-			end
-			self[TRANSLATION_TABLES][locale] = t
-			t = nil
-		end
-		func = nil
-		return
-	end
-	local t = func()
-	func = nil
-	if type(t) ~= "table" then
-		AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
-	end
-	
-	rawset(self, TRANSLATIONS, t)
-	if not rawget(self, BASE_TRANSLATIONS) then
-		rawset(self, BASE_TRANSLATIONS, t)
-		rawset(self, BASE_LOCALE, locale)
-		for key,value in pairs(t) do
-			if value == true then
-				t[key] = key
-			end
-		end
-	else
-		for key, value in pairs(self[TRANSLATIONS]) do
-			if not rawget(self[BASE_TRANSLATIONS], key) then
-				AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale)
-			end
-			if value == true then
-				AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale)
-			end
-		end
-	end
-	rawset(self, CURRENT_LOCALE, locale)
-	if not rawget(self, 'reverse') then
-		rawset(self, 'reverse', setmetatable({}, { __index = function(self2, key)
-			local self = AceLocale.reverseToBase[self2]
-			if not rawget(self, REVERSE_TRANSLATIONS) then
-				self:GetReverseTranslation(key)
-			end
-			self.reverse = self[REVERSE_TRANSLATIONS]
-			return self.reverse[key]
-		end }))
-		AceLocale.reverseToBase[self.reverse] = self
-	end
-	refixInstance(self)
-	if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
-		if not rawget(self, TRANSLATION_TABLES) then
-			rawset(self, TRANSLATION_TABLES, {})
-		end
-		self[TRANSLATION_TABLES][locale] = t
-	end
-	t = nil
-end
-
-function AceLocale.prototype:SetLocale(locale)
-	AceLocale.argCheck(self, locale, 2, "string", "boolean")
-	if not rawget(self, DYNAMIC_LOCALES) then
-		AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.")
-	end
-	if not rawget(self, TRANSLATION_TABLES) then
-		AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.")
-	end
-	if locale == true then
-		locale = GetLocale()
-		if not self[TRANSLATION_TABLES][locale] then
-			locale = self[BASE_LOCALE]
-		end
-	end
-	
-	if self[CURRENT_LOCALE] == locale then
-		return
-	end
-	
-	if not self[TRANSLATION_TABLES][locale] then
-		AceLocale.error(self, "Locale %q not registered.", locale)
-	end
-	
-	self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale]
-	self[CURRENT_LOCALE] = locale
-	refixInstance(self)
-end
-
-function AceLocale.prototype:GetLocale()
-	if not rawget(self, TRANSLATION_TABLES) then
-		AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.")
-	end
-	return self[CURRENT_LOCALE]
-end
-
-local function iter(t, position)
-	return (next(t, position))
-end
-
-function AceLocale.prototype:IterateAvailableLocales()
-	if not rawget(self, DYNAMIC_LOCALES) then
-		AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.")
-	end
-	if not rawget(self, TRANSLATION_TABLES) then
-		AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.")
-	end
-	return iter, self[TRANSLATION_TABLES], nil
-end
-
-function AceLocale.prototype:HasLocale(locale)
-	if not rawget(self, DYNAMIC_LOCALES) then
-		AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.")
-	end
-	AceLocale.argCheck(self, locale, 2, "string")
-	return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil
-end
-
-function AceLocale.prototype:SetStrictness(strict)
-	AceLocale.argCheck(self, strict, 2, "boolean")
-	local mt = getmetatable(self)
-	if not mt then
-		AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.")
-	end
-	if not rawget(self, TRANSLATIONS) then
-		AceLocale.error(self, "No translations registered.")
-	end
-	rawset(self, STRICTNESS, strict)
-	refixInstance(self)
-end
-
-local function initReverse(self)
-	rawset(self, REVERSE_TRANSLATIONS, setmetatable({}, { __index = function(_, key)
-		AceLocale.error(self, "Reverse translation for %q does not exist", key)
-	end }))
-	local alpha = self[TRANSLATIONS]
-	local bravo = self[REVERSE_TRANSLATIONS]
-	for base, localized in pairs(alpha) do
-		bravo[localized] = base
-	end
-end
-
-function AceLocale.prototype:GetTranslation(text)
-	AceLocale.argCheck(self, text, 1, "string", "number")
-	if not rawget(self, TRANSLATIONS) then
-		AceLocale.error(self, "No translations registered")
-	end
-	return self[text]
-end
-
-function AceLocale.prototype:GetStrictTranslation(text)
-	AceLocale.argCheck(self, text, 1, "string", "number")
-	local x = rawget(self, TRANSLATIONS)
-	if not x then
-		AceLocale.error(self, "No translations registered")
-	end
-	local value = rawget(x, text)
-	if value == nil then
-		local _, ret = pcall(AceLocale.error, self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE])
-		geterrorhandler()(ret)
-		return text
-	end
-	return value
-end
-
-function AceLocale.prototype:GetReverseTranslation(text)
-	local x = rawget(self, REVERSE_TRANSLATIONS)
-	if not x then
-		if not rawget(self, TRANSLATIONS) then
-			AceLocale.error(self, "No translations registered")
-		end
-		initReverse(self)
-		x = self[REVERSE_TRANSLATIONS]
-	end
-	local translation = x[text]
-	if not translation then
-		local _, ret = pcall(AceLocale.error, self, "Reverse translation for %q does not exist", text)
-		geterrorhandler()(ret)
-		return text
-	end
-	return translation
-end
-
-function AceLocale.prototype:GetIterator()
-	local x = rawget(self, TRANSLATIONS)
-	if not x then
-		AceLocale.error(self, "No translations registered")
-	end
-	return next, x, nil
-end
-
-function AceLocale.prototype:GetReverseIterator()
-	local x = rawget(self, REVERSE_TRANSLATIONS)
-	if not x then
-		if not rawget(self, TRANSLATIONS) then
-			AceLocale.error(self, "No translations registered")
-		end
-		initReverse(self)
-		x = self[REVERSE_TRANSLATIONS]
-	end
-	return next, x, nil
-end
-
-function AceLocale.prototype:HasTranslation(text)
-	AceLocale.argCheck(self, text, 1, "string", "number")
-	local x = rawget(self, TRANSLATIONS)
-	if not x then
-		AceLocale.error(self, "No translations registered")
-	end
-	return rawget(x, text) and true
-end
-
-function AceLocale.prototype:HasBaseTranslation(text)
-	AceLocale.argCheck(self, text, 1, "string", "number")
-	local x = rawget(self, BASE_TRANSLATIONS)
-	if not x then
-		AceLocale.error(self, "No translations registered")
-	end
-	return rawget(x, text) and true
-end
-
-function AceLocale.prototype:HasReverseTranslation(text)
-	local x = rawget(self, REVERSE_TRANSLATIONS)
-	if not x then
-		if not rawget(self, TRANSLATIONS) then
-			AceLocale.error(self, "No translations registered")
-		end
-		initReverse(self)
-		x = self[REVERSE_TRANSLATIONS]
-	end
-	return rawget(x, text) and true
-end
-
-function AceLocale.prototype:Debug()
-	if not rawget(self, DEBUGGING) then
-		return
-	end
-	local words = {}
-	local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"}
-	local localizations = {}
-	DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---")
-	for _,locale in ipairs(locales) do
-		if not self[TRANSLATION_TABLES][locale] then
-			DEFAULT_CHAT_FRAME:AddMessage(("Locale %q not found"):format(locale))
-		else
-			localizations[locale] = self[TRANSLATION_TABLES][locale]
-		end
-	end
-	local localeDebug = {}
-	for locale, localization in pairs(localizations) do
-		localeDebug[locale] = {}
-		for word in pairs(localization) do
-			if type(localization[word]) == "table" then
-				if type(words[word]) ~= "table" then
-					words[word] = {}
-				end
-				for bit in pairs(localization[word]) do
-					if type(localization[word][bit]) == "string" then
-						words[word][bit] = true
-					end
-				end
-			elseif type(localization[word]) == "string" then
-				words[word] = true
-			end
-		end
-	end
-	for word in pairs(words) do
-		if type(words[word]) == "table" then
-			for bit in pairs(words[word]) do
-				for locale, localization in pairs(localizations) do
-					if not rawget(localization, word) or not localization[word][bit] then
-						localeDebug[locale][word .. "::" .. bit] = true
-					end
-				end
-			end
-		else
-			for locale, localization in pairs(localizations) do
-				if not rawget(localization, word) then
-					localeDebug[locale][word] = true
-				end
-			end
-		end
-	end
-	for locale, t in pairs(localeDebug) do
-		if not next(t) then
-			DEFAULT_CHAT_FRAME:AddMessage(("Locale %q complete"):format(locale))
-		else
-			DEFAULT_CHAT_FRAME:AddMessage(("Locale %q missing:"):format(locale))
-			for word in pairs(t) do
-				DEFAULT_CHAT_FRAME:AddMessage(("    %q"):format(word))
-			end
-		end
-	end
-	DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---")
-end
-
-setmetatable(AceLocale.prototype, {
-	__index = function(self, k)
-		if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion"  and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later.
-			local _, ret = pcall(AceLocale.error, lastSelf or self, "Translation %q does not exist.", k)
-			geterrorhandler()(ret)
-			return k
-		end
-		return nil
-	end
-})
-
-local function activate(self, oldLib, oldDeactivate)
-	AceLocale = self
-	
-	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
-	self.registry = oldLib and oldLib.registry or {}
-	self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {}
-	self.DEBUGGING = oldLib and oldLib.DEBUGGING or {}
-	self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {}
-	self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {}
-	self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {}
-	self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {}
-	self.STRICTNESS = oldLib and oldLib.STRICTNESS or {}
-	self.NAME = oldLib and oldLib.NAME or {}
-	self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {}
-	self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {}
-	self.reverseToBase = oldLib and oldLib.reverseToBase or {}
-	
-	BASE_TRANSLATIONS = self.BASE_TRANSLATIONS
-	DEBUGGING = self.DEBUGGING
-	TRANSLATIONS = self.TRANSLATIONS
-	BASE_LOCALE = self.BASE_LOCALE
-	TRANSLATION_TABLES = self.TRANSLATION_TABLES
-	REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS
-	STRICTNESS = self.STRICTNESS
-	NAME = self.NAME
-	DYNAMIC_LOCALES = self.DYNAMIC_LOCALES
-	CURRENT_LOCALE = self.CURRENT_LOCALE
-	
-	strict_instance_mt = {
-		__index = strict__index,
-		__newindex = __newindex,
-		__tostring = __tostring
-	}
-
-	nonstrict_instance_mt = {
-		__index = nonstrict__index,
-		__newindex = __newindex,
-		__tostring = __tostring
-	}
-
-	baseTranslations_mt = {
-		__index = AceLocale.prototype
-	}
-	
-	local GetTime = GetTime
-	local timeUntilClear = GetTime() + 5
-	scheduleClear = function()
-		if next(newRegistries) then
-			self.frame:Show()
-			timeUntilClear = GetTime() + 5
-		end
-	end
-	
-	for name, instance in pairs(self.registry) do
-		local name = name
-		setmetatable(instance, nil)
-		instance[NAME] = name
-		local strict
-		if instance[STRICTNESS] ~= nil then
-			strict = instance[STRICTNESS]
-		elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then
-			if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then
-				strict = true
-			end
-		end
-		instance[STRICTNESS] = strict and true or false
-		refixInstance(instance)
-	end
-	
-	self.frame:SetScript("OnEvent", scheduleClear)
-	self.frame:SetScript("OnUpdate", function() -- (this, elapsed)
-		if timeUntilClear - GetTime() <= 0 then
-			self.frame:Hide()
-			for k in pairs(newRegistries) do
-				clearCache(k)
-				newRegistries[k] = nil
-				k = nil
-			end
-		end
-	end)
-	self.frame:UnregisterAllEvents()
-	self.frame:RegisterEvent("ADDON_LOADED")
-	self.frame:RegisterEvent("PLAYER_ENTERING_WORLD")
-	self.frame:Show()
-	
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate)
---[[
-if true then -- debug
-	local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG" or "AceLocale_DEBUG3")
-	L:RegisterTranslations("enUS", function() return {
-		Monkey = true,
-		House = true,
-	} end)
-	
-	L:RegisterTranslations("deDE", function() return {
-		Monkey = "Affe"
-	} end)
-	
-	L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG" or "AceLocale_DEBUG3")
-	assert(L.Monkey == "Monkey")
-	assert(L.House == "House")
-	if not L.Debug then
-		local pants = L.Pants
-		assert(not pants)
-	end
-	assert(L.Debug)
-	assert(L.Debug == AceLocale.prototype.Debug)
-	
-	if MINOR_VERSION == 100000 then
-		L = AceLocale:new("AceLocale_DEBUG")
-		assert(L.Monkey == "Monkey")
-		assert(L.House == "House")
-		assert(L.Debug)
-		assert(type(L.Debug) == "function")
-		assert(AceLocale.prototype.Debug)
-		assert(type(AceLocale.prototype.Debug) == "function")
-		assert(L.Debug == AceLocale.prototype.Debug)
-	end
-	
-	local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG2" or "AceLocale_DEBUG4")
-	L:RegisterTranslations("deDE", function() return {
-		Affe = true,
-		Haus = true,
-	} end)
-	
-	L:RegisterTranslations("enUS", function() return {
-		Affe = "Monkey"
-	} end)
-	
-	L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG2" or "AceLocale_DEBUG4")
-	assert(L.Affe == "Monkey")
-	assert(L.Haus == "Haus")
-	assert(L.Debug)
-	assert(L.Debug == AceLocale.prototype.Debug)
-	
-	if MINOR_VERSION == 100000 then
-		L = AceLocale:new("AceLocale_DEBUG2")
-		assert(L.Affe == "Monkey")
-		assert(L.Haus == "Haus")
-		assert(L.Debug)
-		assert(L.Debug == AceLocale.prototype.Debug)
-	end
-	
-	local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG5" or "AceLocale_DEBUG6")
-	L:RegisterTranslations("deDE", function() return {
-		Affe = true,
-		Haus = true,
-	} end)
-	
-	L:RegisterTranslations("enUS", function() return {
-		Affe = "Monkey"
-	} end)
-	
-	L:SetStrictness(true)
-	
-	L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG5" or "AceLocale_DEBUG6")
-	assert(L.Affe == "Monkey")
-	assert(L.Haus == "Haus")
-	assert(L.Debug)
-	assert(L.Debug == AceLocale.prototype.Debug)
-	
-	if MINOR_VERSION == 100000 then
-		L = AceLocale:new("AceLocale_DEBUG5")
-		assert(L.Affe == "Monkey")
-		assert(L.Haus == "Haus")
-		assert(L.Debug)
-		assert(L.Debug == AceLocale.prototype.Debug)
-	end
-end
-]]
\ No newline at end of file
--- a/lib/AceLocale-2.2/AceLocale-2.2.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceLocale-2.2
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary
- 
-AceLocale-2.2.lua
-AceLocale-2.2-2.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceLocale-3.0/AceLocale-3.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,103 @@
+--[[ $Id: AceLocale-3.0.lua 60131 2008-02-03 13:03:56Z nevcairiel $ ]]
+local MAJOR,MINOR = "AceLocale-3.0", 1
+
+local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceLocale then return end -- no upgrade needed
+
+local gameLocale = GetLocale()
+if gameLocale == "enGB" then
+	gameLocale = "enUS"
+end
+
+AceLocale.apps = AceLocale.apps or {}          -- array of ["AppName"]=localetableref
+AceLocale.appnames = AceLocale.appnames or {}  -- array of [localetableref]="AppName"
+
+-- This metatable is used on all tables returned from GetLocale
+local readmeta = {
+	__index = function(self, key)	-- requesting totally unknown entries: fire off a nonbreaking error and return key
+		geterrorhandler()(MAJOR..": "..tostring(AceLocale.appnames[self])..": Missing entry for '"..tostring(key).."'")
+		rawset(self, key, key)	-- only need to see the warning once, really
+		return key
+	end
+}
+
+-- Remember the locale table being registered right now (it gets set by :NewLocale())
+local registering
+
+-- local assert false function
+local assertfalse = function() assert(false) end
+
+-- This metatable proxy is used when registering nondefault locales
+local writeproxy = setmetatable({}, {
+	__newindex = function(self, key, value)
+		rawset(registering, key, value == true and key or value) -- assigning values: replace 'true' with key string
+	end,
+	__index = assertfalse
+})
+
+-- This metatable proxy is used when registering the default locale. 
+-- It refuses to overwrite existing values
+-- Reason 1: Allows loading locales in any order
+-- Reason 2: If 2 modules have the same string, but only the first one to be 
+--           loaded has a translation for the current locale, the translation
+--           doesn't get overwritten.
+--
+local writedefaultproxy = setmetatable({}, {
+	__newindex = function(self, key, value)
+		if not rawget(registering, key) then
+			rawset(registering, key, value == true and key or value)
+		end
+	end,
+	__index = assertfalse
+})
+
+-- AceLocale:NewLocale(application, locale, isDefault)
+--
+--  application (string)  - unique name of addon / module
+--  locale (string)       - name of locale to register, e.g. "enUS", "deDE", etc...
+--  isDefault (string)    - if this is the default locale being registered
+--
+-- Returns a table where localizations can be filled out, or nil if the locale is not needed
+function AceLocale:NewLocale(application, locale, isDefault)
+
+	-- GAME_LOCALE allows translators to test translations of addons without having that wow client installed
+	-- Ammo: I still think this is a bad idea, for instance an addon that checks for some ingame string will fail, just because some other addon
+	-- gives the user the illusion that they can run in a different locale? Ditch this whole thing or allow a setting per 'application'. I'm of the
+	-- opinion to remove this.
+	local gameLocale = GAME_LOCALE or gameLocale
+
+	if locale ~= gameLocale and not isDefault then
+		return -- nop, we don't need these translations
+	end
+	
+	local app = AceLocale.apps[application]
+	
+	if not app then
+		app = setmetatable({}, readmeta)
+		AceLocale.apps[application] = app
+		AceLocale.appnames[app] = application
+	end
+
+	registering = app	-- remember globally for writeproxy and writedefaultproxy
+	
+	if isDefault then
+		return writedefaultproxy
+	end
+
+	return writeproxy
+end
+
+-- AceLocale:GetLocale(application [, silent])
+--
+--  application (string) - unique name of addon
+--  silent (boolean)     - if true, the locale is optional, silently return nil if it's not found 
+--
+-- Returns localizations for the current locale (or default locale if translations are missing)
+-- Errors if nothing is registered (spank developer, not just a missing translation)
+function AceLocale:GetLocale(application, silent)
+	if not silent and not AceLocale.apps[application] then
+		error("Usage: GetLocale(application[, silent]): 'application' - No locales registered for '"..tostring(application).."'", 2)
+	end
+	return AceLocale.apps[application]
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceLocale-3.0/AceLocale-3.0.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="AceLocale-3.0.lua"/>
+</Ui>
\ No newline at end of file
--- a/lib/AceModuleCore-2.0/AceModuleCore-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,688 +0,0 @@
---[[
-Name: AceModuleCore-2.0
-Revision: $Rev: 43318 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceModuleCore-2.0
-SVN: http://svn.wowace.com/root/trunk/Ace2/AceModuleCore-2.0
-Description: Mixin to provide a module system so that modules or plugins can
-             use an addon as its core.
-Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0 (optional)
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "AceModuleCore-2.0"
-local MINOR_VERSION = "$Revision: 43318 $"
-
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
-
-local function safecall(func, ...)
-	local success, err = pcall(func, ...)
-	if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
-end
-
-local AceEvent
-local AceOO = AceLibrary:GetInstance("AceOO-2.0")
-local AceModuleCore = AceOO.Mixin {
-									"NewModule",
-									"HasModule",
-									"GetModule",
-									"IsModule",
-									"IterateModules",
-									"IterateModulesWithMethod",
-									"CallMethodOnAllModules",
-									"SetModuleMixins",
-									"SetModuleClass",
-									"IsModuleActive",
-									"ToggleModuleActive",
-									"SetModuleDefaultState",
-								  }
-local AceAddon
-
-local function getlibrary(lib)
-	if type(lib) == "string" then
-		return AceLibrary(lib)
-	else
-		return lib
-	end
-end
-
-local new, del
-do
-	local list = setmetatable({}, {__mode='k'})
-	function new()
-		local t = next(list)
-		if t then
-			list[t] = nil
-			return t
-		else
-			return {}
-		end
-	end
-	function del(t)
-		for k in pairs(t) do
-			t[k] = nil
-		end
-		list[t] = true
-		return nil
-	end
-end
-
-local iterList = setmetatable({}, {__mode='v'})
-local modulesWithMethod = setmetatable({}, {__mode='kv'})
-do
-	local function func(t)
-		local i = t.i + 1
-		local l = t.l
-		local k = l[i]
-		if k then
-			t.i = i
-			return k, l.m[k]
-		else
-			t = del(t)
-		end
-	end
-	function AceModuleCore:IterateModules()
-		local list = iterList[self]
-		if not list then
-			list = new()
-			for k in pairs(self.modules) do
-				list[#list+1] = k
-			end
-			table.sort(list)
-			list.m = self.modules
-			iterList[self] = list
-		end
-		local t = new()
-		t.i = 0
-		t.l = list
-		return func, t, nil
-	end
-	
-	function AceModuleCore:IterateModulesWithMethod(method)
-		local masterList = modulesWithMethod[self]
-		if not masterList then
-			masterList = new()
-			modulesWithMethod[self] = masterList
-		end
-		local list = masterList[method]
-		if not list then
-			list = new()
-			for k, v in pairs(self.modules) do
-				if self:IsModuleActive(k) and type(v[method]) == "function" then
-					list[#list+1] = k
-				end
-			end
-			table.sort(list)
-			list.m = self.modules
-			masterList[method] = list
-		end
-		local t = new()
-		t.i = 0
-		t.l = list
-		return func, t, nil
-	end
-	
---[[----------------------------------------------------------------------------------
-Notes:
-	Safely calls the given method on all active modules if it exists on said modules. This will automatically subvert any errors that occur in the modules.
-Arguments:
-	string - the name of the method.
-	tuple - the list of arguments to call the method with.
-Example:
-	core:CallMethodOnAllModules("OnSomething")
-	core:CallMethodOnAllModules("OnSomethingElse", 1, 2, 3, 4)
-------------------------------------------------------------------------------------]]
-	function AceModuleCore:CallMethodOnAllModules(method, ...)
-		for name, module in self:IterateModulesWithMethod(method) do
-			local success, ret = pcall(module[method], module, ...)
-			if not success then
-				geterrorhandler()(ret)
-			end
-		end
-	end
-end
-
---[[----------------------------------------------------------------------------
-Notes: 
-	Create a new module, parented to self.
-	The module created does, in fact, inherit from AceAddon-2.0.
-Arguments: 
-	string - name/title of the Module.
-	list of mixins the module is to inherit from.
-Example:
-	MyModule = core:NewModule('MyModule', "AceEvent-2.0", "AceHook-2.1")
-------------------------------------------------------------------------------]]
-local tmp = {}
-function AceModuleCore:NewModule(name, ...)
-	if not self.modules then
-		AceModuleCore:error("CreatePrototype() must be called before attempting to create a new module.", 2)
-	end
-	AceModuleCore:argCheck(name, 2, "string")
-	if name:len() == 0 then
-		AceModuleCore:error("Bad argument #2 to `NewModule`, string must not be empty")
-	end
-	if self.modules[name] then
-		AceModuleCore:error("The module %q has already been registered", name)
-	end
-	
-	if iterList[self] then
-		iterList[self] = del(iterList[self])
-	end
-
-	for i = 1, select('#', ...) do
-		tmp[i] = getlibrary((select(i, ...)))
-	end
-	
-	if self.moduleMixins then
-		for _,mixin in ipairs(self.moduleMixins) do
-			local exists = false
-			for _,v in ipairs(tmp) do
-				if mixin == v then
-					exists = true
-					break
-				end
-			end
-			if not exists then
-				tmp[#tmp+1] = mixin
-			end
-		end
-	end
-
-	local module = AceOO.Classpool(self.moduleClass, unpack(tmp)):new(name)
-	self.modules[name] = module
-	module.name = name
-	module.title = name
-
-	AceModuleCore.totalModules[module] = self
-	
-	if modulesWithMethod[self] then
-		for k,v in pairs(modulesWithMethod[self]) do
-			modulesWithMethod[self] = del(v)
-		end
-	end
-	
-	if type(self.OnModuleCreated) == "function" then
-		safecall(self.OnModuleCreated, self, name, module)
-	end
-	if AceEvent then
-		AceEvent:TriggerEvent("Ace2_ModuleCreated", module)
-	end
-
-	local num = #tmp
-	for i = 1, num do
-		tmp[i] = nil
-	end
-	return module
-end
---[[----------------------------------------------------------------------------------
-Notes:
-	Return whether the module names given are all available in the core.
-Arguments:
-	list of strings that are the names of the modules. (typically you'd only check for one)
-Returns:
-	* boolean - Whether all the modules are available in the core.
-Example:
-	if core:HasModule('Bank') then
-		-- do banking
-	end
-------------------------------------------------------------------------------------]]
-function AceModuleCore:HasModule(...)
-	for i = 1, select('#', ...) do
-		if not self.modules[select(i, ...)] then
-			return false
-		end
-	end
-	
-	return true
-end
-
---[[------------------------------------------------------------------------------------
-Notes:
-	Return the module "name" if it exists.
-	If the module doesnot exist, an error is thrown.
-Arguments:
-	string - the name of the module.
-Returns:
-	The module requested, if it exists.
-Example:
-	local bank = core:GetModule('Bank')
-------------------------------------------------------------------------------------]]
-function AceModuleCore:GetModule(name)
-	if not self.modules then
-		AceModuleCore:error("Error initializing class.  Please report error.")
-	end
-	if not self.modules[name] then
-		AceModuleCore:error("Cannot find module %q.", name)
-	end
-	return self.modules[name]
-end
-
---[[----------------------------------------------------------------------------------
-Notes:
-	Return whether the given module is actually a module.
-Arguments:
-	reference to the module
-Returns:
-	* boolean - whether the given module is actually a module.
-Example:
-	if core:IsModule(module) then
-		-- do something
-	end
-	-- alternatively
-	if AceModuleCore:IsModule(module) then
-		-- checks all modules, no matter the parent
-	end
-------------------------------------------------------------------------------------]]
-function AceModuleCore:IsModule(module)
-	if self == AceModuleCore then
-		return AceModuleCore.totalModules[module]
-	elseif type(module) == "table" then
-		if module.name and self.modules[module.name] and self.modules[module.name].name == module.name then
-			return true
-		end
-		for k,v in pairs(self.modules) do
-			if v == module then
-				return true
-			end
-		end
-		return false
-	end
-end
-
---[[----------------------------------------------------------------------------------
-Notes:
- * Sets the default mixins for a given module.
- * This cannot be called after :NewModule() has been called.
- * This should really only be called if you use the mixins in your prototype.
-Arguments:
-	list of mixins (up to 20)
-Example:
-	core:SetModuleMixins("AceEvent-2.0", "AceHook-2.0")
-------------------------------------------------------------------------------------]]
-function AceModuleCore:SetModuleMixins(...)
-	if self.moduleMixins then
-		AceModuleCore:error('Cannot call "SetModuleMixins" twice')
-	elseif not self.modules then
-		AceModuleCore:error("Error initializing class.  Please report error.")
-	elseif next(self.modules) then
-		AceModuleCore:error('Cannot call "SetModuleMixins" after "NewModule" has been called.')
-	end
-
-	self.moduleMixins =  { ... }
-	for i,v in ipairs(self.moduleMixins) do
-		self.moduleMixins[i] = getlibrary(v)
-	end
-end
-
--- #NODOC
-function AceModuleCore:SetModuleClass(class)
-	class = getlibrary(class)
-	if not AceOO.inherits(class, AceOO.Class) then
-		AceModuleCore:error("Bad argument #2 to `SetModuleClass' (Class expected)")
-	end
-	if not self.modules then
-		AceModuleCore:error("Error initializing class.  Please report error.")
-	end
-	if self.customModuleClass then
-		AceModuleCore:error("Cannot call `SetModuleClass' twice.")
-	end
-	self.customModuleClass = true
-	self.moduleClass = class
-	self.modulePrototype = class.prototype
-end
-
-local mt = {__index=function(self, key)
-	self[key] = false
-	return false
-end}
-local defaultState = setmetatable({}, {__index=function(self, key)
-	local t = setmetatable({}, mt)
-	self[key] = t
-	return t
-end})
-
-local function isDisabled(core, module)
-	local moduleName
-	if type(module) == "table" then
-		moduleName = module.name
-	else
-		moduleName = module
-	end
-	local disabled
-	if type(module) == "table" and type(module.IsActive) == "function" then
-		return not module:IsActive()
-	elseif AceOO.inherits(core, "AceDB-2.0") then
-		local _,profile = core:GetProfile()
-		disabled = core.db and core.db.raw and core.db.raw.disabledModules and core.db.raw.disabledModules[profile] and core.db.raw.disabledModules[profile][moduleName]
-	else
-		disabled = core.disabledModules and core.disabledModules[moduleName]
-	end
-	if disabled == nil then
-		return defaultState[core][moduleName]
-	else
-		return disabled
-	end
-end
-
---[[----------------------------------------------------------------------------------
-Notes:
-	Sets the default active state of a module. This should be called before the ADDON_LOADED of the module.
-Arguments:
-	string - name of the module.
-	table - reference to the module.
-	boolean - new state. false means disabled by default, true means enabled by default (true is the default).
-Example:
-	self:SetModuleDefaultState('bank', false)
-------------------------------------------------------------------------------------]]
-function AceModuleCore:SetModuleDefaultState(module, state)
-	AceModuleCore:argCheck(module, 2, "table", "string")
-	AceModuleCore:argCheck(state, 3, "boolean")
-	
-	if type(module) == "table" then
-		if not self:IsModule(module) then
-			AceModuleCore:error("%q is not a module", module)
-		end
-		module = module.name
-	end
-	
-	defaultState[self][module] = not state
-end
-
---[[----------------------------------------------------------------------------------
-Notes: 
-Toggles the active state of a module.
-
-This calls module:ToggleActive([state]) if available.
-
-If suspending, This will call :OnDisable() on the module if it is available. Also, it will iterate through the addon's mixins and call :OnEmbedDisable(module) if available. - this in turn will, through AceEvent and others, unregister events/hooks/etc. depending on the mixin. Also, it will call :OnModuleDisable(module) on the core if it is available.
-
-If resuming, This will call :OnEnable(first) on the module if it is available. Also, it will iterate through the addon's mixins and call :OnEmbedEnable(module) if available. - this in turn will, through AceEvent and others, unregister events/hooks/etc. depending on the mixin. Also, it will call :OnModuleEnable(module) on the core if it is available.
-
-If you call :ToggleModuleActive("name or module, true) and it is already active, it silently returns, same if you pass false and it is inactive.
-
-Arguments:
-	string/table - name of the module or a reference to the module
-	[optional] boolean - new state. (default not :IsModuleActive("name" or module))
-Returns:
-	* boolean - Whether the module is now in an active (enabled) state.
-Example:
-	self:ToggleModuleActive('bank')
-------------------------------------------------------------------------------------]]
-function AceModuleCore:ToggleModuleActive(module, state)
-	AceModuleCore:argCheck(module, 2, "table", "string")
-	AceModuleCore:argCheck(state, 3, "nil", "boolean")
-	
-	if type(module) == "string" then
-		if not self:HasModule(module) then
-			AceModuleCore:error("Cannot find module %q", module)
-		end
-		module = self:GetModule(module)
-	elseif not self:IsModule(module) then
-		AceModuleCore:error("%q is not a module", module)
-	end
-
-	local disable
-	if state == nil then
-		disable = self:IsModuleActive(module)
-	else
-		disable = not state
-		if disable ~= self:IsModuleActive(module) then
-			return
-		end
-	end
-
-	if type(module.ToggleActive) == "function" then
-		return module:ToggleActive(not disable)
-	elseif AceOO.inherits(self, "AceDB-2.0") then
-		if not self.db or not self.db.raw then
-			AceModuleCore:error("Cannot toggle a module until `RegisterDB' has been called and `ADDON_LOADED' has been fired.")
-		end
-		if type(self.db.raw.disabledModules) ~= "table" then
-			self.db.raw.disabledModules = {}
-		end
-		local _,profile = self:GetProfile()
-		if type(self.db.raw.disabledModules[profile]) ~= "table" then
-			self.db.raw.disabledModules[profile] = {}
-		end
-		if type(self.db.raw.disabledModules[profile][module.name]) ~= "table" then
-			local value = nil
-			if disable ~= defaultState[self][module.name] then
-				value = disable
-			end
-			self.db.raw.disabledModules[profile][module.name] = value
-		end
-		if not disable then
-			if not next(self.db.raw.disabledModules[profile]) then
-				self.db.raw.disabledModules[profile] = nil
-			end
-			if not next(self.db.raw.disabledModules) then
-				self.db.raw.disabledModules = nil
-			end
-		end
-	else
-		if type(self.disabledModules) ~= "table" then
-			self.disabledModules = {}
-		end
-		local value = nil
-		if disable ~= defaultState[self][module.name] then
-			value = disable
-		end
-		self.disabledModules[module.name] = value
-	end
-	if AceOO.inherits(module, "AceAddon-2.0") then
-		if not AceAddon.addonsStarted[module] then
-			return
-		end
-	end
-	if not disable then
-		local first = nil
-		if AceOO.inherits(module, "AceAddon-2.0") then
-			if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[module] then
-				AceAddon.addonsEnabled[module] = true
-				first = true
-			end
-		end
-		local current = module.class
-		while true do
-			if current == AceOO.Class then
-				break
-			end
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnEmbedEnable) == "function" then
-						safecall(mixin.OnEmbedEnable, mixin, module, first)
-					end
-				end
-			end
-			current = current.super
-		end
-		if type(module.OnEnable) == "function" then
-			safecall(module.OnEnable, module, first)
-		end
-		if AceEvent then
-			AceEvent:TriggerEvent("Ace2_AddonEnabled", module, first)
-		end
-	else
-		local current = module.class
-		while true do
-			if current == AceOO.Class then
-				break
-			end
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnEmbedDisable) == "function" then
-						safecall(mixin.OnEmbedDisable, mixin, module)
-					end
-				end
-			end
-			current = current.super
-		end
-		if type(module.OnDisable) == "function" then
-			safecall(module.OnDisable, module)
-		end
-		if AceEvent then
-			AceEvent:TriggerEvent("Ace2_AddonDisabled", module)
-		end
-	end
-	return not disable
-end
-
---[[-----------------------------------------------------------------------
-Notes:
-	Returns whether the module is in an active (enabled) state. This calls module:IsActive() if available. if notLoaded is set, then "name" must be a string.
-Arguments:
-	string/table - name of the module or a reference to the module
-	[optional] - boolean - if set, this will check modules that are not loaded as well. (default: false)
-Returns:
-	* boolean - Whether the module is in an active (enabled) state.
-Example:
-	assert(self:IsModuleActive('bank'))
-------------------------------------------------------------------------]]
-function AceModuleCore:IsModuleActive(module, notLoaded)
-	AceModuleCore:argCheck(module, 2, "table", "string")
-	AceModuleCore:argCheck(notLoaded, 3, "nil", "boolean")
-	if notLoaded then
-		AceModuleCore:argCheck(module, 2, "string")
-	end
-	
-	if AceModuleCore == self then
-		self:argCheck(module, 2, "table")
-		
-		local core = AceModuleCore.totalModules[module]
-		if not core then
-			self:error("Bad argument #2 to `IsModuleActive'. Not a module")
-		end
-		return core:IsModuleActive(module)
-	end
-
-	if type(module) == "string" then
-		if not notLoaded and not self:HasModule(module) then
-			AceModuleCore:error("Cannot find module %q", module)
-		end
-		if not notLoaded then
-			module = self:GetModule(module)
-		else
-			module = self:HasModule(module) and self:GetModule(module) or module
-		end
-	else
-		if not self:IsModule(module) then
-			AceModuleCore:error("%q is not a module", module)
-		end
-	end
-	
-	return not isDisabled(self, module)
-end
-
--- #NODOC
-function AceModuleCore:OnInstanceInit(target)
-	if target.modules then
-		do return end
-		AceModuleCore:error("OnInstanceInit cannot be called twice")
-	end
-	
-	if not AceAddon then
-		if AceLibrary:HasInstance("AceAddon-2.0") then
-			AceAddon = AceLibrary("AceAddon-2.0")
-		else
-			self:error(MAJOR_VERSION .. " requires AceAddon-2.0")
-		end
-	end
-	target.modules = {}
-
-	target.moduleClass = AceOO.Class("AceAddon-2.0")
-	target.modulePrototype = target.moduleClass.prototype
-end
-
-AceModuleCore.OnManualEmbed = AceModuleCore.OnInstanceInit
-
-function AceModuleCore.OnEmbedProfileDisable(AceModuleCore, self, newProfile)
-	if not AceOO.inherits(self, "AceDB-2.0") then
-		return
-	end
-	local _,currentProfile = self:GetProfile()
-	for k, module in pairs(self.modules) do
-		if type(module.IsActive) == "function" or type(module.ToggleActive) == "function" then
-			-- continue
-		else
-			local currentActive =  not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[currentProfile] or not self.db.raw.disabledModules[currentProfile][module.name]
-			local newActive =  not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[newProfile] or not self.db.raw.disabledModules[newProfile][module.name]
-			if currentActive ~= newActive then
-				self:ToggleModuleActive(module)
-				if not self.db.raw.disabledModules then
-					self.db.raw.disabledModules = {}
-				end
-				if not self.db.raw.disabledModules[currentProfile] then
-					self.db.raw.disabledModules[currentProfile] = {}
-				end
-				self.db.raw.disabledModules[currentProfile][module.name] = not currentActive or nil
-			end
-		end
-	end
-end
-
--- #NODOC
-function AceModuleCore:Ace2_AddonEnabled(module, first)
-	local addon = self.totalModules[module]
-	if not addon then
-		return
-	end
-	
-	if modulesWithMethod[addon] then
-		for k,v in pairs(modulesWithMethod[addon]) do
-			modulesWithMethod[addon] = del(v)
-		end
-	end
-	if type(addon.OnModuleEnable) == "function" then
-		safecall(addon.OnModuleEnable, addon, module, first)
-	end
-end
-
--- #NODOC
-function AceModuleCore:Ace2_AddonDisabled(module)
-	local addon = self.totalModules[module]
-	if not addon then
-		return
-	end
-	
-	if modulesWithMethod[addon] then
-		for k,v in pairs(modulesWithMethod[addon]) do
-			modulesWithMethod[addon] = del(v)
-		end
-	end
-	if type(addon.OnModuleDisable) == "function" then
-		safecall(addon.OnModuleDisable, addon, module)
-	end
-end
-
-local function activate(self, oldLib, oldDeactivate)
-	AceModuleCore = self
-
-	self.totalModules = oldLib and oldLib.totalModules or {}
-	
-	self:activate(oldLib, oldDeactivate)
-	
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-local function external(self, major, instance)
-	if major == "AceEvent-2.0" then
-		AceEvent = instance
-		AceEvent:embed(self)
-		
-		self:UnregisterAllEvents()
-		self:RegisterEvent("Ace2_AddonEnabled")
-		self:RegisterEvent("Ace2_AddonDisabled")
-	elseif major == "AceAddon-2.0" then
-		AceAddon = instance
-	end
-end
-
-AceLibrary:Register(AceModuleCore, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
-AceModuleCore = AceLibrary(MAJOR_VERSION)
--- a/lib/AceModuleCore-2.0/AceModuleCore-2.0.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceModuleCore-2.0
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0
- 
-AceModuleCore-2.0.lua
--- a/lib/AceOO-2.0/AceOO-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,980 +0,0 @@
---[[
-Name: AceOO-2.0
-Revision: $Rev: 38641 $
-Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
-Inspired By: Ace 1.x by Turan (turan@gryphon.com)
-Website: http://www.wowace.com/
-Documentation: http://www.wowace.com/index.php/AceOO-2.0
-SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0
-Description: Library to provide an object-orientation framework.
-Dependencies: AceLibrary
-License: MIT
-]]
-
-local MAJOR_VERSION = "AceOO-2.0"
-local MINOR_VERSION = "$Revision: 38641 $"
-
--- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-local AceOO = {
-	error = AceLibrary.error,
-	argCheck = AceLibrary.argCheck
-}
-
--- @function	getuid
--- @brief		Obtain a unique string identifier for the object in question.
--- @param t		The object to obtain the uid for.
--- @return		The uid string.
-local function getuid(t)
-	local mt = getmetatable(t)
-	setmetatable(t, nil)
-	local str = tostring(t)
-	setmetatable(t, mt)
-	local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$")
-	if cap then
-		return ("0"):rep(8 - #cap) .. cap
-	end
-end
-
-local function getlibrary(o)
-	if type(o) == "table" then
-		return o
-	elseif type(o) == "string" then
-		if not AceLibrary:HasInstance(o) then
-			AceOO:error("Library %q does not exist.", o)
-		end
-		return AceLibrary(o)
-	end
-end
-
-local function deeprawget(self, k)
-	while true do
-		local v = rawget(self, k)
-		if v ~= nil then
-			return v
-		end
-		local mt = getmetatable(self)
-		if not mt or type(mt.__index) ~= "table" then
-			return nil
-		end
-		self = mt.__index
-	end
-end
-
--- @function		Factory
--- @brief			Construct a factory for the creation of objects.
--- @param obj		The object whose init method will be called on the new factory
---					object.
--- @param newobj	The object whose init method will be called on the new
---					objects that the Factory creates, to initialize them.
--- @param (...) Arguments which will be passed to obj.init() in addition
---					to the Factory object.
--- @return			The new factory which creates a newobj when its new method is called,
---					or when it is called directly (__call metamethod).
-local Factory
-do
-	local function getlibraries(...)
-		if select('#', ...) == 0 then
-			return
-		end
-		return getlibrary((select(1, ...))), getlibraries(select(2, ...))
-	end
-	local arg = {}
-	local function new(obj, ...)
-		local t = {}
-		local uid = getuid(t)
-		obj:init(t, getlibraries(...))
-		t.uid = uid
-		return t
-	end
-	
-	local function createnew(self, ...)
-		local o = self.prototype
-		local x = new(o, getlibraries(...))
-		return x
-	end
-
-	function Factory(obj, newobj, ...)
-		local t = new(obj, ...)
-		t.prototype = newobj
-		t.new = createnew
-		getmetatable(t).__call = t.new
-		return t
-	end
-end
-
-
-local function objtostring(self)
-	if self.ToString then
-		return self:ToString()
-	elseif self.GetLibraryVersion then
-		return (self:GetLibraryVersion())
-	elseif self.super then
-		local s = "Sub-" .. tostring(self.super)
-		local first = true
-		if self.interfaces then
-			for interface in pairs(self.interfaces) do
-				if first then
-					s = s .. "(" .. tostring(interface)
-					first = false
-				else
-					s = s .. ", " .. tostring(interface)
-				end
-			end
-		end
-		if self.mixins then
-			for mixin in pairs(self.mixins) do
-				if first then
-					s = s .. tostring(mixin)
-					first = false
-				else
-					s = s .. ", " .. tostring(mixin)
-				end
-			end
-		end
-		if first then
-			if self.uid then
-				return s .. ":" .. self.uid
-			else
-				return s
-			end
-		else
-			return s .. ")"
-		end
-	else
-		return self.uid and 'Subclass:' .. self.uid or 'Subclass'
-	end
-end
-
--- @table			Object
--- @brief			Base of all objects, including Class.
---
--- @method			init
--- @brief			Initialize a new object.
--- @param newobject The object to initialize
--- @param class		The class to make newobject inherit from
-local Object
-do
-	Object = {}
-	function Object:init(newobject, class)
-		local parent = class or self
-		if not rawget(newobject, 'uid') then
-			newobject.uid = getuid(newobject)
-		end
-		local mt = {
-			__index = parent,
-			__tostring = objtostring,
-		}
-		setmetatable(newobject, mt)
-	end
-	Object.uid = getuid(Object)
-	setmetatable(Object, { __tostring = function() return 'Object' end })
-end
-
-local Interface
-
-local function validateInterface(object, interface)
-	if not object.class and object.prototype then
-		object = object.prototype
-	end
-	for k,v in pairs(interface.interface) do
-		if tostring(type(object[k])) ~= v then
-			return false
-		end
-	end
-	if interface.superinterfaces then
-		for superinterface in pairs(interface.superinterfaces) do
-			if not validateInterface(object, superinterface) then
-				return false
-			end
-		end
-	end
-	if type(object.class) == "table" and rawequal(object.class.prototype, object) then
-		if not object.class.interfaces then
-			rawset(object.class, 'interfaces', {})
-		end
-		object.class.interfaces[interface] = true
-	elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
-		validateInterface(object.class.prototype, interface)
-		-- check if class is proper, thus preventing future checks.
-	end
-	return true
-end
-
--- @function		inherits
--- @brief			Return whether an Object or Class inherits from a given
---					parent.
--- @param object	Object or Class to check
--- @param parent	Parent to test inheritance from
--- @return			whether an Object or Class inherits from a given
---					parent.
-local function inherits(object, parent)
-	object = getlibrary(object)
-	if type(parent) == "string" then
-		if not AceLibrary:HasInstance(parent) then
-			return false
-		else
-			parent = AceLibrary(parent)
-		end
-	end
-	AceOO:argCheck(parent, 2, "table")
-	if type(object) ~= "table" then
-		return false
-	end
-	local current
-	local class = deeprawget(object, 'class')
-	if class then
-		current = class
-	else
-		current = object
-	end
-	if type(current) ~= "table" then
-		return false
-	end
-	if rawequal(current, parent) then
-		return true
-	end
-	if parent.class then
-		while true do
-			if rawequal(current, Object) then
-				break
-			end
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if rawequal(mixin, parent) then
-						return true
-					end
-				end
-			end
-			if current.interfaces then
-				for interface in pairs(current.interfaces) do
-					if rawequal(interface, parent) then
-						return true
-					end
-				end
-			end
-			current = deeprawget(current, 'super')
-			if type(current) ~= "table" then
-				break
-			end
-		end
-		
-		local isInterface = false
-		local curr = parent.class
-		while true do
-			if rawequal(curr, Object) then
-				break
-			elseif rawequal(curr, Interface) then
-				isInterface = true
-				break
-			end
-			curr = deeprawget(curr, 'super')
-			if type(curr) ~= "table" then
-				break
-			end
-		end
-		return isInterface and validateInterface(object, parent)
-	else
-		while true do
-			if rawequal(current, parent) then
-				return true
-			elseif rawequal(current, Object) then
-				return false
-			end
-			current = deeprawget(current, 'super')
-			if type(current) ~= "table" then
-				return false
-			end
-		end
-	end
-end
-
--- @table			Class
--- @brief			An object factory which sets up inheritence and supports
---					'mixins'.
---
--- @metamethod		Class call
--- @brief			Call ClassFactory:new() to create a new class.
---
--- @method			Class new
--- @brief			Construct a new object.
--- @param (...) Arguments to pass to the object init function.
--- @return			The new object.
---
--- @method			Class init
--- @brief			Initialize a new class.
--- @param parent	Superclass.
--- @param (...) Mixins.
---
--- @method			Class ToString
--- @return			A string representing the object, in this case 'Class'.
-local initStatus
-local Class
-local Mixin
-local autoEmbed = false
-local function traverseInterfaces(bit, total)
-	if bit.superinterfaces then
-		for interface in pairs(bit.superinterfaces) do
-			if not total[interface] then
-				total[interface] = true
-				traverseInterfaces(interface, total)
-			end
-		end
-	end
-end
-local class_new
-do
-	Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
-	Class.super = Object
-	
-	local function protostring(t)
-		return '<' .. tostring(t.class) .. ' prototype>'
-	end
-	local function classobjectstring(t)
-		if t.ToString then
-			return t:ToString()
-		elseif t.GetLibraryVersion then
-			return (t:GetLibraryVersion())
-		else
-			return '<' .. tostring(t.class) .. ' instance>'
-		end
-	end
-	local function classobjectequal(self, other)
-		if type(self) == "table" and self.Equals then
-			return self:Equals(other)
-		elseif type(other) == "table" and other.Equals then
-			return other:Equals(self)
-		elseif type(self) == "table" and self.CompareTo then
-			return self:CompareTo(other) == 0
-		elseif type(other) == "table" and other.CompareTo then
-			return other:CompareTo(self) == 0
-		else
-			return rawequal(self, other)
-		end
-	end
-	local function classobjectlessthan(self, other)
-		if type(self) == "table" and self.IsLessThan then
-			return self:IsLessThan(other)
-		elseif type(other) == "table" and other.IsLessThanOrEqualTo then
-			return not other:IsLessThanOrEqualTo(self)
-		elseif type(self) == "table" and self.CompareTo then
-			return self:CompareTo(other) < 0
-		elseif type(other) == "table" and other.CompareTo then
-			return other:CompareTo(self) > 0
-		elseif type(other) == "table" and other.IsLessThan and other.Equals then
-			return other:Equals(self) or other:IsLessThan(self)
-		else
-			AceOO:error("cannot compare two objects")
-		end
-	end
-	local function classobjectlessthanequal(self, other)
-		if type(self) == "table" and self.IsLessThanOrEqualTo then
-			return self:IsLessThanOrEqualTo(other)
-		elseif type(other) == "table" and other.IsLessThan then
-			return not other:IsLessThan(self)
-		elseif type(self) == "table" and self.CompareTo then
-			return self:CompareTo(other) <= 0
-		elseif type(other) == "table" and other.CompareTo then
-			return other:CompareTo(self) >= 0
-		elseif type(self) == "table" and self.IsLessThan and self.Equals then
-			return self:Equals(other) or self:IsLessThan(other)
-		else
-			AceOO:error("cannot compare two incompatible objects")
-		end
-	end
-	local function classobjectadd(self, other)
-		if type(self) == "table" and self.Add then
-			return self:Add(other)
-		else
-			AceOO:error("cannot add two incompatible objects")
-		end
-	end
-	local function classobjectsub(self, other)
-		if type(self) == "table" and self.Subtract then
-			return self:Subtract(other)
-		else
-			AceOO:error("cannot subtract two incompatible objects")
-		end
-	end
-	local function classobjectunm(self, other)
-		if type(self) == "table" and self.UnaryNegation then
-			return self:UnaryNegation(other)
-		else
-			AceOO:error("attempt to negate an incompatible object")
-		end
-	end
-	local function classobjectmul(self, other)
-		if type(self) == "table" and self.Multiply then
-			return self:Multiply(other)
-		else
-			AceOO:error("cannot multiply two incompatible objects")
-		end
-	end
-	local function classobjectdiv(self, other)
-		if type(self) == "table" and self.Divide then
-			return self:Divide(other)
-		else
-			AceOO:error("cannot divide two incompatible objects")
-		end
-	end
-	local function classobjectpow(self, other)
-		if type(self) == "table" and self.Exponent then
-			return self:Exponent(other)
-		else
-			AceOO:error("cannot exponentiate two incompatible objects")
-		end
-	end
-	local function classobjectconcat(self, other)
-		if type(self) == "table" and self.Concatenate then
-			return self:Concatenate(other)
-		else
-			AceOO:error("cannot concatenate two incompatible objects")
-		end
-	end
-	function class_new(self, ...)
-		if self.virtual then
-			AceOO:error("Cannot instantiate a virtual class.")
-		end
-		
-		local o = self.prototype
-		local newobj = {}
-		if o.class and o.class.instancemeta then
-			setmetatable(newobj, o.class.instancemeta)
-		else
-			Object:init(newobj, o)
-		end
-		
-		if self.interfaces and not self.interfacesVerified then
-			-- Verify the interfaces
-			
-			for interface in pairs(self.interfaces) do
-				for field,kind in pairs(interface.interface) do
-					if tostring(type(newobj[field])) ~= kind then
-						AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field])))
-					end
-				end
-			end
-			self.interfacesVerified = true
-		end
-		local tmp = initStatus
-		initStatus = newobj
-		newobj:init(...)
-		if initStatus then
-			initStatus = tmp
-			AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
-			return
-		end
-		initStatus = tmp
-		return newobj
-	end
-	local classmeta = {
-		__tostring = objtostring,
-		__call = function(self, ...)
-			return self:new(...)
-		end,
-	}
-	function Class:init(newclass, parent, ...)
-		parent = parent or self
-		
-		local total
-		
-		if parent.class then
-			total = { parent, ... }
-			parent = self
-		else
-			total = { ... }
-		end
-		if not inherits(parent, Class) then
-			AceOO:error("Classes must inherit from a proper class")
-		end
-		if parent.sealed then
-			AceOO:error("Cannot inherit from a sealed class")
-		end
-		for i,v in ipairs(total) do
-			if inherits(v, Mixin) and v.class then
-				if v.__deprecated then
-					AceOO:error(v.__deprecated)
-				end
-				if not newclass.mixins then
-					newclass.mixins = {}
-				end
-				if newclass.mixins[v] then
-					AceOO:error("Cannot explicitly inherit from the same mixin twice")
-				end
-				newclass.mixins[v] = true
-			elseif inherits(v, Interface) and v.class then
-				if not newclass.interfaces then
-					newclass.interfaces = {}
-				end
-				if newclass.interfaces[v] then
-					AceOO:error("Cannot explicitly inherit from the same interface twice")
-				end
-				newclass.interfaces[v] = true
-			else
-				AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
-			end
-		end
-		if parent.interfaces then
-			if not newclass.interfaces then
-				newclass.interfaces = {}
-			end
-			for interface in pairs(parent.interfaces) do
-				newclass.interfaces[interface] = true
-			end
-		end
-		for k in pairs(total) do
-			total[k] = nil
-		end
-		
-		newclass.super = parent
-		
-		newclass.prototype = setmetatable(total, {
-			__index = parent.prototype,
-			__tostring = protostring,
-		})
-		total = nil
-		
-		newclass.instancemeta = {
-			__index = newclass.prototype,
-			__tostring = classobjectstring,
-			__eq = classobjectequal,
-			__lt = classobjectlessthan,
-			__le = classobjectlessthanequal,
-			__add = classobjectadd,
-			__sub = classobjectsub,
-			__unm = classobjectunm,
-			__mul = classobjectmul,
-			__div = classobjectdiv,
-			__pow = classobjectpow,
-			__concat = classobjectconcat,
-		}
-		
-		setmetatable(newclass, classmeta)
-		
-		newclass.new = class_new
-		
-		if newclass.mixins then
-			-- Fold in the mixins
-			local err, msg
-			for mixin in pairs(newclass.mixins) do
-				local ret
-				autoEmbed = true
-				ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
-				autoEmbed = false
-				if not ret then
-					err = true
-					break
-				end
-			end
-	
-			if err then
-				local pt = newclass.prototype
-				for k,v in pairs(pt) do
-					pt[k] = nil
-				end
-	
-				-- method conflict
-				AceOO:error(msg)
-			end
-		end
-		
-		newclass.prototype.class = newclass
-		
-		if newclass.interfaces then
-			for interface in pairs(newclass.interfaces) do
-				traverseInterfaces(interface, newclass.interfaces)
-			end
-		end
-		if newclass.mixins then
-			for mixin in pairs(newclass.mixins) do
-				if mixin.interfaces then
-					if not newclass.interfaces then
-						newclass.interfaces = {}
-					end
-					for interface in pairs(mixin.interfaces) do
-						newclass.interfaces[interface] = true
-					end
-				end
-			end
-		end
-	end
-	function Class:ToString()
-		if type(self.GetLibraryVersion) == "function" then
-			return (self:GetLibraryVersion())
-		else
-			return "Class"
-		end
-	end
-	
-	local tmp
-	function Class.prototype:init()
-		if rawequal(self, initStatus) then
-			initStatus = nil
-		else
-			AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
-		end
-		self.uid = getuid(self)
-		local current = self.class
-		while true do
-			if current == Class then
-				break
-			end
-			if current.mixins then
-				for mixin in pairs(current.mixins) do
-					if type(mixin.OnInstanceInit) == "function" then
-						mixin:OnInstanceInit(self)
-					end
-				end
-			end
-			current = current.super
-		end
-	end
-end
-
-
--- @object	ClassFactory
--- @brief	A factory for creating classes.	Rarely used directly.
-local ClassFactory = Factory(Object, Class, Object)
-
-function Class:new(...)
-	local x = ClassFactory:new(...)
-	if AceOO.classes then
-		AceOO.classes[x] = true
-	end
-	return x
-end
-getmetatable(Class).__call = Class.new
-
--- @class	Mixin
--- @brief	A class to create mixin objects, which contain methods that get
--- "mixed in" to class prototypes.
---
--- @object	Mixin prototype
--- @brief	The prototype that mixin objects inherit their methods from.
---
--- @method	Mixin prototype embed
--- @brief	Mix in the methods of our object which are listed in our interface
---		 to the supplied target table.
---
--- @method	Mixin prototype init
--- @brief	Initialize the mixin object.
--- @param	newobj	 The new object we're initializing.
--- @param	interface	The interface we implement (the list of methods our
---					prototype provides which should be mixed into the target
---					table by embed).
-do
-	Mixin = Class()
-	function Mixin:ToString()
-		if self.GetLibraryVersion then
-			return (self:GetLibraryVersion())
-		else
-			return 'Mixin'
-		end
-	end
-	local function _Embed(state, field, target)
-		field = next(state.export, field)
-		if field == nil then
-			return
-		end
-
-		if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
-			AceOO:error("Method conflict in attempt to mixin. Field %q", field)
-		end
-
-		target[field] = state[field]
-
-		local ret,msg = pcall(_Embed, state, field, target)
-		if not ret then
-			-- Mix in the next method according to the defined interface.	If that
-			-- fails due to a conflict, re-raise to back out the previous mixed
-			-- methods.
-
-			target[field] = nil
-			AceOO:error(msg)
-		end
-	end
-	function Mixin.prototype:embed(target)
-		if self.__deprecated then
-			AceOO:error(self.__deprecated)
-		end
-		local mt = getmetatable(target)
-		setmetatable(target, nil)
-		local err, msg = pcall(_Embed, self, nil, target)
-		if not err then
-			setmetatable(target, mt)
-			AceOO:error(msg)
-			return
-		end
-		if type(self.embedList) == "table" then
-			self.embedList[target] = true
-		end
-		if type(target.class) ~= "table" then
-			target[self] = true
-		end
-		if not autoEmbed and type(self.OnManualEmbed) == "function" then
-			self:OnManualEmbed(target)
-		end
-		setmetatable(target, mt)
-	end
-	
-	function Mixin.prototype:activate(oldLib, oldDeactivate)
-		if oldLib and oldLib.embedList then
-			for target in pairs(oldLib.embedList) do
-				local mt = getmetatable(target)
-				setmetatable(target, nil)
-				for field in pairs(oldLib.export) do
-					target[field] = nil
-				end
-				setmetatable(target, mt)
-			end
-			self.embedList = oldLib.embedList
-			for target in pairs(self.embedList) do
-				self:embed(target)
-			end
-		else
-			self.embedList = setmetatable({}, {__mode="k"})
-		end
-	end
-	
-	function Mixin.prototype:init(export, ...)
-		AceOO:argCheck(export, 2, "table")
-		for k,v in pairs(export) do
-			if type(k) ~= "number" then
-				AceOO:error("All keys to argument #2 must be numbers.")
-			elseif type(v) ~= "string" then
-				AceOO:error("All values to argument #2 must be strings.")
-			end
-		end
-		local num = #export
-		for i = 1, num do
-			local v = export[i]
-			export[i] = nil
-			export[v] = true
-		end
-		
-		local interfaces
-		if select('#', ...) >= 1 then
-			interfaces = { ... }
-			for i,v in ipairs(interfaces) do
-				v = getlibrary(v)
-				interfaces[i] = v
-				if not v.class or not inherits(v, Interface) then
-					AceOO:error("Mixins can inherit only from interfaces")
-				end
-			end
-			local num = #interfaces
-			for i = 1, num do
-				local v = interfaces[i]
-				interfaces[i] = nil
-				interfaces[v] = true
-			end
-			for interface in pairs(interfaces) do
-				traverseInterfaces(interface, interfaces)
-			end
-			for interface in pairs(interfaces) do
-				for field,kind in pairs(interface.interface) do
-					if kind ~= "nil" then
-						local good = false
-						for bit in pairs(export) do
-							if bit == field then
-								good = true
-								break
-							end
-						end
-						if not good then
-							AceOO:error("Mixin does not fully accommodate field %q", field)
-						end
-					end
-				end
-			end
-		end
-		self.super = Mixin.prototype
-		Mixin.super.prototype.init(self)
-		self.export = export
-		self.interfaces = interfaces
-	end
-end
-
--- @class Interface
--- @brief A class to create interfaces, which contain contracts that classes
---			which inherit from this must comply with.
---
--- @object Interface prototype
--- @brief	The prototype that interface objects must adhere to.
---
--- @method Interface prototype init
--- @brief	Initialize the mixin object.
--- @param	interface	The interface we contract (the hash of fields forced).
--- @param	(...)	Superinterfaces
-do
-	Interface = Class()
-	function Interface:ToString()
-		if self.GetLibraryVersion then
-			return (self:GetLibraryVersion())
-		else
-			return 'Instance'
-		end
-	end
-	function Interface.prototype:init(interface, ...)
-		Interface.super.prototype.init(self)
-		AceOO:argCheck(interface, 2, "table")
-		for k,v in pairs(interface) do
-			if type(k) ~= "string" then
-				AceOO:error("All keys to argument #2 must be numbers.")
-			elseif type(v) ~= "string" then
-				AceOO:error("All values to argument #2 must be strings.")
-			elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
-				AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
-			end
-		end
-		if select('#', ...) >= 1 then
-			self.superinterfaces = { ... }
-			for i,v in ipairs(self.superinterfaces) do
-				v = getlibrary(v)
-				self.superinterfaces[i] = v
-				if not inherits(v, Interface) or not v.class then
-					AceOO:error('Cannot provide a non-Interface to inherit from')
-				end
-			end
-			local num = #self.superinterfaces
-			for i = 1, num do
-				local v = self.superinterfaces[i]
-				self.superinterfaces[i] = nil
-				self.superinterfaces[v] = true
-			end
-		end
-		self.interface = interface
-	end
-end
-
--- @function Classpool
--- @brief	Obtain a read only class from our pool of classes, indexed by the
---		 superclass and mixins.
--- @param	sc		 The superclass of the class we want.
--- @param	(m1..m20)	Mixins of the class we want's objects.
--- @return A read only class from the class pool.
-local Classpool
-do
-	local pool = setmetatable({}, {__mode = 'v'})
-	local function newindex(k, v)
-		AceOO:error('Attempt to modify a read-only class.')
-	end
-	local function protonewindex(k, v)
-		AceOO:error('Attempt to modify a read-only class prototype.')
-	end
-	local function ts(bit)
-		if type(bit) ~= "table" then
-			return tostring(bit)
-		elseif getmetatable(bit) and bit.__tostring then
-			return tostring(bit)
-		elseif type(bit.GetLibraryVersion) == "function" then
-			return bit:GetLibraryVersion()
-		else
-			return tostring(bit)
-		end
-	end
-	local t = {}
-	local function getcomplexuid(sc, ...)
-		if sc then
-			if sc.uid then
-				table.insert(t, sc.uid)
-			else
-				AceOO:error("%s is not an appropriate class/mixin", ts(sc))
-			end
-		end
-		for i = 1, select('#', ...) do
-			local m = select(i, ...)
-			if m.uid then
-				table.insert(t, m.uid)
-			else
-				AceOO:error("%s is not an appropriate mixin", ts(m))
-			end
-		end
-		table.sort(t)
-		local uid = table.concat(t, '')
-		local num = #t
-		for i = 1, num do
-			t[i] = nil
-		end
-		return uid
-	end
-	local classmeta
-	local arg = {}
-	function Classpool(superclass, ...)
-		local l = getlibrary
-		superclass = getlibrary(superclass)
-		arg = { ... }
-		for i, v in ipairs(arg) do
-			arg[i] = getlibrary(v)
-		end
-		if superclass then
-			if superclass.class then -- mixin
-				table.insert(arg, 1, superclass)
-				superclass = Class
-			end
-		else
-			superclass = Class
-		end
-		local key = getcomplexuid(superclass, unpack(arg))
-		if not pool[key] then
-			local class = Class(superclass, unpack(arg))
-			if not classmeta then
-				classmeta = {}
-				local mt = getmetatable(class)
-				for k,v in pairs(mt) do
-					classmeta[k] = v
-				end
-				classmeta.__newindex = newindex
-			end
-			-- Prevent the user from adding methods to this class.
-			-- NOTE: I'm not preventing modifications of existing class members,
-			-- but it's likely that only a truly malicious user will be doing so.
-			class.sealed = true
-			setmetatable(class, classmeta)
-			getmetatable(class.prototype).__newindex = protonewindex
-			pool[key] = class
-		end
-		return pool[key]
-	end
-end
-
-AceOO.Factory = Factory
-AceOO.Object = Object
-AceOO.Class = Class
-AceOO.Mixin = Mixin
-AceOO.Interface = Interface
-AceOO.Classpool = Classpool
-AceOO.inherits = inherits
-
--- Library handling bits
-
-local function activate(self, oldLib, oldDeactivate)
-	AceOO = self
-	Factory = self.Factory
-	Object = self.Object
-	Class = self.Class
-	ClassFactory.prototype = Class
-	Mixin = self.Mixin
-	Interface = self.Interface
-	Classpool = self.Classpool
-	
-	if oldLib then
-		self.classes = oldLib.classes
-	end
-	if not self.classes then
-		self.classes = setmetatable({}, {__mode="k"})
-	else
-		for class in pairs(self.classes) do
-			class.new = class_new
-		end
-	end
-	
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
-AceOO = AceLibrary(MAJOR_VERSION)
--- a/lib/AceOO-2.0/AceOO-2.0.toc	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-## Interface: 20200
-
-## Title: Lib: AceOO-2.0
-## Notes: AddOn development framework
-## Author: Ace Development Team
-## LoadOnDemand: 1
-## X-Website: http://www.wowace.com
-## X-Category: Library
-## X-License: LGPL v2.1 + MIT for AceOO-2.0
-## Dependencies: AceLibrary
- 
-AceOO-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/CallbackHandler-1.0/CallbackHandler-1.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,239 @@
+--[[ $Id: CallbackHandler-1.0.lua 60697 2008-02-09 16:51:20Z nevcairiel $ ]]
+local MAJOR, MINOR = "CallbackHandler-1.0", 3
+local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not CallbackHandler then return end -- No upgrade needed
+
+local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
+
+local type = type
+local pcall = pcall
+local pairs = pairs
+local assert = assert
+local concat = table.concat
+local loadstring = loadstring
+local next = next
+local select = select
+local type = type
+local xpcall = xpcall
+
+local function errorhandler(err)
+	return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+	local code = [[
+	local next, xpcall, eh = ...
+
+	local method, ARGS
+	local function call() method(ARGS) end
+
+	local function dispatch(handlers, ...)
+		local index
+		index, method = next(handlers)
+		if not method then return end
+		local OLD_ARGS = ARGS
+		ARGS = ...
+		repeat
+			xpcall(call, eh)
+			index, method = next(handlers, index)
+		until not method
+		ARGS = OLD_ARGS
+	end
+
+	return dispatch
+	]]
+
+	local ARGS, OLD_ARGS = {}, {}
+	for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
+	code = code:gsub("OLD_ARGS", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(ARGS, ", "))
+	return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+	local dispatcher = CreateDispatcher(argCount)
+	rawset(self, argCount, dispatcher)
+	return dispatcher
+end})
+
+--------------------------------------------------------------------------
+-- CallbackHandler:New
+--
+--   target            - target object to embed public APIs in
+--   RegisterName      - name of the callback registration API, default "RegisterCallback"
+--   UnregisterName    - name of the callback unregistration API, default "UnregisterCallback"
+--   UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
+
+function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
+	-- TODO: Remove this after beta has gone out
+	assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
+
+	RegisterName = RegisterName or "RegisterCallback"
+	UnregisterName = UnregisterName or "UnregisterCallback"
+	if UnregisterAllName==nil then	-- false is used to indicate "don't want this method"
+		UnregisterAllName = "UnregisterAllCallbacks"
+	end
+
+	-- we declare all objects and exported APIs inside this closure to quickly gain access
+	-- to e.g. function names, the "target" parameter, etc
+
+
+	-- Create the registry object
+	local events = setmetatable({}, meta)
+	local registry = { recurse=0, events=events }
+
+	-- registry:Fire() - fires the given event/message into the registry
+	function registry:Fire(eventname, ...)
+		if not rawget(events, eventname) or not next(events[eventname]) then return end
+		local oldrecurse = registry.recurse
+		registry.recurse = oldrecurse + 1
+
+		Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
+
+		registry.recurse = oldrecurse
+
+		if registry.insertQueue and oldrecurse==0 then
+			-- Something in one of our callbacks wanted to register more callbacks; they got queued
+			for eventname,callbacks in pairs(registry.insertQueue) do
+				local first = not rawget(events, eventname) or not next(events[eventname])	-- test for empty before. not test for one member after. that one member may have been overwritten.
+				for self,func in pairs(callbacks) do
+					events[eventname][self] = func
+					-- fire OnUsed callback?
+					if first and registry.OnUsed then
+						registry.OnUsed(registry, target, eventname)
+						first = nil
+					end
+				end
+			end
+			registry.insertQueue = nil
+		end
+	end
+
+	-- Registration of a callback, handles:
+	--   self["method"], leads to self["method"](self, ...)
+	--   self with function ref, leads to functionref(...)
+	--   "addonId" (instead of self) with function ref, leads to functionref(...)
+	-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
+	target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
+		if type(eventname) ~= "string" then
+			error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
+		end
+
+		method = method or eventname
+
+		local first = not rawget(events, eventname) or not next(events[eventname])	-- test for empty before. not test for one member after. that one member may have been overwritten.
+
+		if type(method) ~= "string" and type(method) ~= "function" then
+			error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
+		end
+
+		local regfunc
+
+		if type(method) == "string" then
+			-- self["method"] calling style
+			if type(self) ~= "table" then
+				error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
+			elseif self==target then
+				error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
+			elseif type(self[method]) ~= "function" then
+				error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
+			end
+
+			if select("#",...)>=1 then	-- this is not the same as testing for arg==nil!
+				local arg=select(1,...)
+				regfunc = function(...) self[method](self,arg,...) end
+			else
+				regfunc = function(...) self[method](self,...) end
+			end
+		else
+			-- function ref with self=object or self="addonId"
+			if type(self)~="table" and type(self)~="string" then
+				error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2)
+			end
+
+			if select("#",...)>=1 then	-- this is not the same as testing for arg==nil!
+				local arg=select(1,...)
+				regfunc = function(...) method(arg,...) end
+			else
+				regfunc = method
+			end
+		end
+
+
+		if events[eventname][self] or registry.recurse<1 then
+		-- if registry.recurse<1 then
+			-- we're overwriting an existing entry, or not currently recursing. just set it.
+			events[eventname][self] = regfunc
+			-- fire OnUsed callback?
+			if registry.OnUsed and first then
+				registry.OnUsed(registry, target, eventname)
+			end
+		else
+			-- we're currently processing a callback in this registry, so delay the registration of this new entry!
+			-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
+			registry.insertQueue = registry.insertQueue or setmetatable({},meta)
+			registry.insertQueue[eventname][self] = regfunc
+		end
+	end
+
+	-- Unregister a callback
+	target[UnregisterName] = function(self, eventname)
+		if not self or self==target then
+			error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
+		end
+		if type(eventname) ~= "string" then
+			error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
+		end
+		if rawget(events, eventname) and events[eventname][self] then
+			events[eventname][self] = nil
+			-- Fire OnUnused callback?
+			if registry.OnUnused and not next(events[eventname]) then
+				registry.OnUnused(registry, target, eventname)
+			end
+		end
+		if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
+			registry.insertQueue[eventname][self] = nil
+		end
+	end
+
+	-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
+	if UnregisterAllName then
+		target[UnregisterAllName] = function(...)
+			if select("#",...)<1 then
+				error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
+			end
+			if select("#",...)==1 and ...==target then
+				error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
+			end
+
+
+			for i=1,select("#",...) do
+				local self = select(i,...)
+				if registry.insertQueue then
+					for eventname, callbacks in pairs(registry.insertQueue) do
+						if callbacks[self] then
+							callbacks[self] = nil
+						end
+					end
+				end
+				for eventname, callbacks in pairs(events) do
+					if callbacks[self] then
+						callbacks[self] = nil
+						-- Fire OnUnused callback?
+						if registry.OnUnused and not next(callbacks) then
+							registry.OnUnused(registry, target, eventname)
+						end
+					end
+				end
+			end
+		end
+	end
+
+	return registry
+end
+
+
+-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
+-- try to upgrade old implicit embeds since the system is selfcontained and
+-- relies on closures to work.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/CallbackHandler-1.0/CallbackHandler-1.0.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="CallbackHandler-1.0.lua"/>
+</Ui>
\ No newline at end of file
--- a/lib/Dewdrop-2.0/Dewdrop-2.0.lua	Tue Mar 11 21:39:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3487 +0,0 @@
---[[
-Name: Dewdrop-2.0
-Revision: $Rev: 48630 $
-Author(s): ckknight (ckknight@gmail.com)
-Website: http://ckknight.wowinterface.com/
-Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0
-SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0
-Description: A library to provide a clean dropdown menu interface.
-Dependencies: AceLibrary
-License: LGPL v2.1
-]]
-
-local MAJOR_VERSION = "Dewdrop-2.0"
-local MINOR_VERSION = "$Revision: 48630 $"
-
-if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
-if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
-
-local Dewdrop = {}
-
-local SharedMedia
-
-local CLOSE = "Close"
-local CLOSE_DESC = "Close the menu."
-local VALIDATION_ERROR = "Validation error."
-local USAGE_TOOLTIP = "Usage: %s."
-local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one."
-local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding."
-local KEY_BUTTON1 = "Left Mouse"
-local KEY_BUTTON2 = "Right Mouse"
-local DISABLED = "Disabled"
-local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?"
-
-if GetLocale() == "deDE" then
-	CLOSE = "Schlie\195\159en"
-	CLOSE_DESC = "Men\195\188 schlie\195\159en."
-	VALIDATION_ERROR = "Validierungsfehler."
-	USAGE_TOOLTIP = "Benutzung: %s."
-	RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen."
-	RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen."
-	KEY_BUTTON1 = "Linke Maustaste"
-	KEY_BUTTON2 = "Rechte Maustaste"
-	DISABLED = "Deaktiviert"
-	DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?"
-elseif GetLocale() == "koKR" then
-	CLOSE = "닫기"
-	CLOSE_DESC = "메뉴를 닫습니다."
-	VALIDATION_ERROR = "오류 확인."
-	USAGE_TOOLTIP = "사용법: %s."
-	RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다."
-	RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요."
-	KEY_BUTTON1 = "왼쪽 마우스"
-	KEY_BUTTON2 = "오른쪽 마우스"
-	DISABLED = "비활성화됨"
-	DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?"
-elseif GetLocale() == "frFR" then
-	CLOSE = "Fermer"
-	CLOSE_DESC = "Ferme le menu."
-	VALIDATION_ERROR = "Erreur de validation."
-	USAGE_TOOLTIP = "Utilisation : %s."
-	RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement."
-	RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci."
-	KEY_BUTTON1 = "Clic gauche"
-	KEY_BUTTON2 = "Clic droit"
-	DISABLED = "D\195\169sactiv\195\169"
-	DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?"
-elseif GetLocale() == "esES" then
-	CLOSE = "Cerrar"
-	CLOSE_DESC = "Cierra el menú."
-	VALIDATION_ERROR = "Error de validación."
-	USAGE_TOOLTIP = "Uso: %s."
-	RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador."
-	RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla."
-	KEY_BUTTON1 = "Clic Izquierdo"
-	KEY_BUTTON2 = "Clic Derecho"
-	DISABLED = "Desactivado"
-	DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?"
-elseif GetLocale() == "zhTW" then
-	CLOSE = "關閉"
-	CLOSE_DESC = "關閉選單。"
-	VALIDATION_ERROR = "驗證錯誤。"
-	USAGE_TOOLTIP = "用法: %s。"
-	RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。"
-	RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。"
-	KEY_BUTTON1 = "滑鼠左鍵"
-	KEY_BUTTON2 = "滑鼠右鍵"
-	DISABLED = "停用"
-	DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?"
-elseif GetLocale() == "zhCN" then
-	CLOSE = "关闭"
-	CLOSE_DESC = "关闭菜单"
-	VALIDATION_ERROR = "验证错误."
-	USAGE_TOOLTIP = "用法: %s."
-	RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页."
-	RESET_KEYBINDING_DESC = "按ESC键清除按键绑定"
-	KEY_BUTTON1 = "鼠标左键"
-	KEY_BUTTON2 = "鼠标右键"
-	DISABLED = "禁用"
-	DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?"
-end
-
-Dewdrop.KEY_BUTTON1 = KEY_BUTTON1
-Dewdrop.KEY_BUTTON2 = KEY_BUTTON2
-
-local function new(...)
-	local t = {}
-	for i = 1, select('#', ...), 2 do
-		local k = select(i, ...)
-		if k then
-			t[k] = select(i+1, ...)
-		else
-			break
-		end
-	end
-	return t
-end
-
-local tmp
-do
-	local t = {}
-	function tmp(...)
-		for k in pairs(t) do
-			t[k] = nil
-		end
-		for i = 1, select('#', ...), 2 do
-			local k = select(i, ...)
-			if k then
-				t[k] = select(i+1, ...)
-			else
-				break
-			end
-		end
-		return t
-	end
-end
-local tmp2
-do
-	local t = {}
-	function tmp2(...)
-		for k in pairs(t) do
-			t[k] = nil
-		end
-		for i = 1, select('#', ...), 2 do
-			local k = select(i, ...)
-			if k then
-				t[k] = select(i+1, ...)
-			else
-				break
-			end
-		end
-		return t
-	end
-end
-local levels
-local buttons
-
-
--- Secure frame handling:
--- Rather than using secure buttons in the menu (has problems), we have one
--- master secureframe that we pop onto menu items on mouseover. This requires
--- some dark magic with OnLeave etc, but it's not too bad.
-
-local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate")
-secureFrame:Hide()
-
-local function secureFrame_Show(self)
-  local owner = self.owner
-
-  if self.secure then	-- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..)
-	  for k,v in pairs(self.secure) do
-	    self:SetAttribute(k, nil)
-	  end
-  end
-  self.secure = owner.secure;	-- Grab hold of new secure data
-
-  local scale = owner:GetEffectiveScale()
-
-  self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale)
-  self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale)
-  self:EnableMouse(true)
-  for k,v in pairs(self.secure) do
-    self:SetAttribute(k, v)
-  end
-
-	secureFrame:SetFrameStrata(owner:GetFrameStrata())
-	secureFrame:SetFrameLevel(owner:GetFrameLevel()+1)
-
-  self:Show()
-end
-
-local function secureFrame_Hide(self)
-  self:Hide()
-  if self.secure then
-	  for k,v in pairs(self.secure) do
-	    self:SetAttribute(k, nil)
-	  end
-	end
-  self.secure = nil
-end
-
-secureFrame:SetScript("OnEvent",
-	function()
-		if event=="PLAYER_REGEN_ENABLED" then
-			this.combat = false
-			if not this:IsShown() and this.owner then
-				secureFrame_Show(this)
-			end
-		elseif event=="PLAYER_REGEN_DISABLED" then
-			this.combat = true
-			if this:IsShown() then
-				secureFrame_Hide(this)
-			end
-		end
-	end
-)
-secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
-secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
-
-secureFrame:SetScript("OnLeave",
-	function()
-		local owner=this.owner
-		this:Deactivate()
-		owner:GetScript("OnLeave")()
-	end
-)
-
-secureFrame:HookScript("OnClick",
-	function()
-		local realthis = this
-		this = this.owner
-		this:GetScript("OnClick")()
-	end
-)
-
-function secureFrame:IsOwnedBy(frame)
-	return self.owner == frame
-end
-
-function secureFrame:Activate(owner)
-	if self.owner then		-- "Shouldn't" happen but apparently it does and I cba to troubleshoot...
-		if not self.combat then
-			secureFrame_Hide(self)
-		end
-	end
-	self.owner = owner
-	if not self.combat then
-		secureFrame_Show(self)
-	end
-end
-
-function secureFrame:Deactivate()
-	if not self.combat then
-		secureFrame_Hide(self)
-	end
-	self.owner = nil
-end
-
--- END secure frame utilities
-
-
--- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies
-local underlineFrame = CreateFrame("Frame", nil)
-underlineFrame.tx = underlineFrame:CreateTexture()
-underlineFrame.tx:SetTexture(1,1,0.5,0.75)
-underlineFrame:SetScript("OnHide", function(this) this:Hide(); end)
-underlineFrame:SetScript("OnShow", function(this) 	-- change sizing on the fly to catch runtime uiscale changes
-    underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale())
-    underlineFrame.tx:SetPoint("RIGHT", 1,0)
-    underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale());
-end)
-underlineFrame:SetHeight(1)
-
--- END underline on mouseover
-
-
-local function GetScaledCursorPosition()
-	local x, y = GetCursorPosition()
-	local scale = UIParent:GetEffectiveScale()
-	return x / scale, y / scale
-end
-
-local function StartCounting(self, level)
-	for i = level, 1, -1 do
-		if levels[i] then
-			levels[i].count = 3
-		end
-	end
-end
-
-local function StopCounting(self, level)
-	for i = level, 1, -1 do
-		if levels[i] then
-			levels[i].count = nil
-		end
-	end
-end
-
-local function OnUpdate(self, elapsed)
-	for _,level in ipairs(levels) do
-		local count = level.count
-		if count then
-			count = count - elapsed
-			if count < 0 then
-				level.count = nil
-				self:Close(level.num)
-			else
-				level.count = count
-			end
-		end
-	end
-end
-
-local function CheckDualMonitor(self, frame)
-	local ratio = GetScreenWidth() / GetScreenHeight()
-	if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then
-		local offsetx
-		if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then
-			offsetx = GetScreenWidth() / 2 - frame:GetRight()
-		else
-			offsetx = GetScreenWidth() / 2 - frame:GetLeft()
-		end
-		local point, parent, relativePoint, x, y = frame:GetPoint(1)
-		frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0)
-	end
-end
-
-local function CheckSize(self, level)
-	if not level.buttons then
-		return
-	end
-	local height = 20
-	for _, button in ipairs(level.buttons) do
-		height = height + button:GetHeight()
-	end
-	level:SetHeight(height)
-	local width = 160
-	for _, button in ipairs(level.buttons) do
-		local extra = 1
-		if button.hasArrow or button.hasColorSwatch then
-			extra = extra + 16
-		end
-		if not button.notCheckable then
-			extra = extra + 24
-		end
-		button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight)
-		if button.text:GetWidth() + extra > width then
-			width = button.text:GetWidth() + extra
-		end
-	end
-	level:SetWidth(width + 20)
-	if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then
-		level:ClearAllPoints()
-		local parent = level.parent or level:GetParent()
-		if type(parent) ~= "table" then
-			parent = UIParent
-		end
-		if level.lastDirection == "RIGHT" then
-			if level.lastVDirection == "DOWN" then
-				level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
-			else
-				level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
-			end
-		else
-			if level.lastVDirection == "DOWN" then
-				level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
-			else
-				level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
-			end
-		end
-	end
-	local dirty = false
-	if not level:GetRight() then
-		self:Close()
-		return
-	end
-	if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then
-		level.lastDirection = "LEFT"
-		dirty = true
-	elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then
-		level.lastDirection = "RIGHT"
-		dirty = true
-	end
-	if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then
-		level.lastVDirection = "DOWN"
-		dirty = true
-	elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then
-		level.lastVDirection = "UP"
-		dirty = true
-	end
-	if dirty then
-		level:ClearAllPoints()
-		local parent = level.parent or level:GetParent()
-		if type(parent) ~= "table" then
-			parent = UIParent
-		end
-		if level.lastDirection == "RIGHT" then
-			if level.lastVDirection == "DOWN" then
-				level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
-			else
-				level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
-			end
-		else
-			if level.lastVDirection == "DOWN" then
-				level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
-			else
-				level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
-			end
-		end
-	end
-	if level:GetTop() > GetScreenHeight() then
-		local top = level:GetTop()
-		local point, parent, relativePoint, x, y = level:GetPoint(1)
-		level:ClearAllPoints()
-		level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top)
-	elseif level:GetBottom() < 0 then
-		local bottom = level:GetBottom()
-		local point, parent, relativePoint, x, y = level:GetPoint(1)
-		level:ClearAllPoints()
-		level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom)
-	end
-	CheckDualMonitor(self, level)
-	if mod(level.num, 5) == 0 then
-		local left, bottom = level:GetLeft(), level:GetBottom()
-		level:ClearAllPoints()
-		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
-	end
-end
-
-local Open
-local OpenSlider
-local OpenEditBox
-local Refresh
-local Clear
-local function ReleaseButton(self, level, index)
-	if not level.buttons then
-		return
-	end
-	if not level.buttons[index] then
-		return
-	end
-	local button = level.buttons[index]
-	button:Hide()
-	if button.highlight then
-		button.highlight:Hide()
-	end
---	button.arrow:SetVertexColor(1, 1, 1)
---	button.arrow:SetHeight(16)
---	button.arrow:SetWidth(16)
-	table.remove(level.buttons, index)
-	table.insert(buttons, button)
-	for k in pairs(button) do
-		if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then
-			button[k] = nil
-		end
-	end
-	return true
-end
-
-local function Scroll(self, level, down)
-	if down then
-		if level:GetBottom() < 0 then
-			local point, parent, relativePoint, x, y = level:GetPoint(1)
-			level:SetPoint(point, parent, relativePoint, x, y + 50)
-			if level:GetBottom() > 0 then
-				level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom())
-			end
-		end
-	else
-		if level:GetTop() > GetScreenHeight() then
-			local point, parent, relativePoint, x, y = level:GetPoint(1)
-			level:SetPoint(point, parent, relativePoint, x, y - 50)
-			if level:GetTop() < GetScreenHeight() then
-				level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop())
-			end
-		end
-	end
-end
-
-local function getArgs(t, str, num, ...)
-	local x = t[str .. num]
-	if x == nil then
-		return ...
-	else
-		return x, getArgs(t, str, num + 1, ...)
-	end
-end
-
-local sliderFrame
-local editBoxFrame
-
-local normalFont
-local lastSetFont
-local justSetFont = false
-local regionTmp = {}
-local function fillRegionTmp(...)
-	for i = 1, select('#', ...) do
-		regionTmp[i] = select(i, ...)
-	end
-end
-
-local function showGameTooltip(this)
-	if this.tooltipTitle or this.tooltipText then
-		GameTooltip_SetDefaultAnchor(GameTooltip, this)
-		local disabled = not this.isTitle and this.disabled
-		local font
-		if this.tooltipTitle then
-			if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then
-				font = SharedMedia:Fetch("font", this.tooltipTitle)
-			end
-			if disabled then
-				GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1)
-			else
-				GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1)
-			end
-			if this.tooltipText then
-				if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then
-					font = SharedMedia:Fetch("font", this.tooltipText)
-				end
-				if disabled then
-					GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1)
-				else
-					GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
-				end
-			end
-		else
-			if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then
-				font = SharedMedia:Fetch("font", this.tooltipText)
-			end
-			if disabled then
-				GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1)
-			else
-				GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1)
-			end
-		end
-		if font then
-			fillRegionTmp(GameTooltip:GetRegions())
-			lastSetFont = font
-			justSetFont = true
-			for i,v in ipairs(regionTmp) do
-				if v.SetFont then
-					local norm,size,outline = v:GetFont()
-					v:SetFont(font, size, outline)
-					if not normalFont then
-						normalFont = norm
-					end
-				end
-				regionTmp[i] = nil
-			end
-		elseif not normalFont then
-			fillRegionTmp(GameTooltip:GetRegions())
-			for i,v in ipairs(regionTmp) do
-				if v.GetFont and not normalFont then
-					normalFont = v:GetFont()
-				end
-				regionTmp[i] = nil
-			end
-		end
-		GameTooltip:Show()
-	end
-	if this.tooltipFunc then
-		GameTooltip:SetOwner(this, "ANCHOR_NONE")
-		GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0)
-		this.tooltipFunc(getArgs(this, 'tooltipArg', 1))
-		GameTooltip:Show()
-	end
-end
-
-local tmpt = setmetatable({}, {mode='v'})
-local numButtons = 0
-local function AcquireButton(self, level)
-	if not levels[level] then
-		return
-	end
-	level = levels[level]
-	if not level.buttons then
-		level.buttons = {}
-	end
-	local button
-	if #buttons == 0 then
-		numButtons = numButtons + 1
-		button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil)
-		button:SetFrameStrata("FULLSCREEN_DIALOG")
-		button:SetHeight(16)
-		local highlight = button:CreateTexture(nil, "BACKGROUND")
-		highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
-		button.highlight = highlight
-		highlight:SetBlendMode("ADD")
-		highlight:SetAllPoints(button)
-		highlight:Hide()
-		local check = button:CreateTexture(nil, "ARTWORK")
-		button.check = check
-		check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
-		check:SetPoint("CENTER", button, "LEFT", 12, 0)
-		check:SetWidth(24)
-		check:SetHeight(24)
-		local radioHighlight = button:CreateTexture(nil, "ARTWORK")
-		button.radioHighlight = radioHighlight
-		radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
-		radioHighlight:SetAllPoints(check)
-		radioHighlight:SetBlendMode("ADD")
-		radioHighlight:SetTexCoord(0.5, 0.75, 0, 1)
-		radioHighlight:Hide()
-		button:SetScript("OnEnter", function()
-			if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then
-				for i = 1, this.level.num do
-					Refresh(self, levels[i])
-				end
-				return
-			end
-			self:Close(this.level.num + 1)
-			if not this.disabled then
-				if this.secure then
-					secureFrame:Activate(this)
-				elseif this.hasSlider then
-					OpenSlider(self, this)
-				elseif this.hasEditBox then
-					OpenEditBox(self, this)
-				elseif this.hasArrow then
-					Open(self, this, nil, this.level.num + 1, this.value)
-				end
-			end
-			if not this.level then -- button reclaimed
-				return
-			end
-			StopCounting(self, this.level.num + 1)
-			if not this.disabled then
-				highlight:Show()
-				if this.isRadio then
-					button.radioHighlight:Show()
-				end
-				if this.mouseoverUnderline then
-					underlineFrame:SetParent(this)
-					underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0)
-					underlineFrame:SetWidth(this.text:GetWidth())
-					underlineFrame:Show()
-				end
-			end
-			showGameTooltip(this)
-		end)
-		button:SetScript("OnHide", function()
-			if this.secure and secureFrame:IsOwnedBy(this) then
-				secureFrame:Deactivate()
-			end
-		end)
-		button:SetScript("OnLeave", function()
-			if this.secure and secureFrame:IsShown() then
-				return;	-- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it
-			end
-			underlineFrame:Hide()
-			if not this.selected then
-				highlight:Hide()
-			end
-			button.radioHighlight:Hide()
-			if this.level then
-				StartCounting(self, this.level.num)
-			end
-			GameTooltip:Hide()
-		end)
-		local first = true
-		button:SetScript("OnClick", function()
-			if not this.disabled then
-				if this.hasColorSwatch then
-					local func = button.colorFunc
-					local hasOpacity = this.hasOpacity
-					local this = this
-					for k in pairs(tmpt) do
-						tmpt[k] = nil
-					end
-					for i = 1, 1000 do
-						local x = this['colorArg'..i]
-						if x == nil then
-							break
-						else
-							tmpt[i] = x
-						end
-					end
-					ColorPickerFrame.func = function()
-						if func then
-							local r,g,b = ColorPickerFrame:GetColorRGB()
-							local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil
-							local n = #tmpt
-							tmpt[n+1] = r
-							tmpt[n+2] = g
-							tmpt[n+3] = b
-							tmpt[n+4] = a
-							func(unpack(tmpt))
-							tmpt[n+1] = nil
-							tmpt[n+2] = nil
-							tmpt[n+3] = nil
-							tmpt[n+4] = nil
-						end
-					end
-					ColorPickerFrame.hasOpacity = this.hasOpacity
-					ColorPickerFrame.opacityFunc = ColorPickerFrame.func
-					ColorPickerFrame.opacity = 1 - this.opacity
-					ColorPickerFrame:SetColorRGB(this.r, this.g, this.b)
-					local r, g, b, a = this.r, this.g, this.b, this.opacity
-					ColorPickerFrame.cancelFunc = function()
-						if func then
-							local n = #tmpt
-							tmpt[n+1] = r
-							tmpt[n+2] = g
-							tmpt[n+3] = b
-							tmpt[n+4] = a
-							func(unpack(tmpt))
-							for i = 1, n+4 do
-								tmpt[i] = nil
-							end
-						end
-					end
-					self:Close(1)
-					ShowUIPanel(ColorPickerFrame)
-				elseif this.func then
-					local level = this.level
-					if type(this.func) == "string" then
-						if type(this.arg1[this.func]) ~= "function" then
-							self:error("Cannot call method %q", this.func)
-						end
-						this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2))
-					else
-						this.func(getArgs(this, 'arg', 1))
-					end
-					if this.closeWhenClicked then
-						self:Close()
-					elseif level:IsShown() then
-						for i = 1, level.num do
-							Refresh(self, levels[i])
-						end
-						local value = levels[level.num].value
-						for i = level.num-1, 1, -1 do
-							local level = levels[i]
-							local good = false
-							for _,button in ipairs(level.buttons) do
-								if button.value == value then
-									good = true
-									break
-								end
-							end
-							if not good then
-								Dewdrop:Close(i+1)
-							end
-							value = levels[i].value
-						end
-					end
-				elseif this.closeWhenClicked then
-					self:Close()
-				end
-			end
-		end)
-		local text = button:CreateFontString(nil, "ARTWORK")
-		button.text = text
-		text:SetFontObject(GameFontHighlightSmall)
-		button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT)
-		button:SetScript("OnMouseDown", function()
-			if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
-				text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1)
-			end
-		end)
-		button:SetScript("OnMouseUp", function()
-			if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
-				text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0)
-			end
-		end)
-		local arrow = button:CreateTexture(nil, "ARTWORK")
-		button.arrow = arrow
-		arrow:SetPoint("LEFT", button, "RIGHT", -16, 0)
-		arrow:SetWidth(16)
-		arrow:SetHeight(16)
-		arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
-		local colorSwatch = button:CreateTexture(nil, "ARTWORK")
-		button.colorSwatch = colorSwatch
-		colorSwatch:SetWidth(20)
-		colorSwatch:SetHeight(20)
-		colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
-		local texture = button:CreateTexture(nil, "OVERLAY")
-		colorSwatch.texture = texture
-		texture:SetTexture("Interface\\Buttons\\WHITE8X8")
-		texture:SetWidth(11.5)
-		texture:SetHeight(11.5)
-		texture:Show()
-		texture:SetPoint("CENTER", colorSwatch, "CENTER")
-		colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0)
-	else
-		button = table.remove(buttons)
-	end
-	button:ClearAllPoints()
-	button:SetParent(level)
-	button:SetFrameStrata(level:GetFrameStrata())
-	button:SetFrameLevel(level:GetFrameLevel() + 1)
-	button:SetPoint("LEFT", level, "LEFT", 10, 0)
-	button:SetPoint("RIGHT", level, "RIGHT", -10, 0)
-	if #level.buttons == 0 then
-		button:SetPoint("TOP", level, "TOP", 0, -10)
-	else
-		button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0)
-	end
-	button.text:SetPoint("LEFT", button, "LEFT", 24, 0)
-	button:Show()
-	button.level = level
-	table.insert(level.buttons, button)
-	if not level.parented then
-		level.parented = true
-		level:ClearAllPoints()
-		if level.num == 1 then
-			if level.parent ~= UIParent and type(level.parent) == "table" then
-				level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT")
-			else
-				level:SetPoint("CENTER", UIParent, "CENTER")
-			end
-		else
-			if level.lastDirection == "RIGHT" then
-				if level.lastVDirection == "DOWN" then
-					level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10)
-				else
-					level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10)
-				end
-			else
-				if level.lastVDirection == "DOWN" then
-					level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10)
-				else
-					level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10)
-				end
-			end
-		end
-		level:SetFrameStrata("FULLSCREEN_DIALOG")
-	end
-	button:SetAlpha(1)
-	return button
-end
-
-local numLevels = 0
-local function AcquireLevel(self, level)
-	if not levels[level] then
-		for i = #levels + 1, level, -1 do
-			local i = i
-			numLevels = numLevels + 1
-			local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil)
-			if i == 1 then
-				local old_CloseSpecialWindows = CloseSpecialWindows
-				function CloseSpecialWindows()
-					local found = old_CloseSpecialWindows()
-					if levels[1]:IsShown() then
-						self:Close()
-						return 1
-					end
-					return found
-				end
-			end
-			levels[i] = frame
-			frame.num = i
-			frame:SetParent(UIParent)
-			frame:SetFrameStrata("FULLSCREEN_DIALOG")
-			frame:Hide()
-			frame:SetWidth(180)
-			frame:SetHeight(10)
-			frame:SetFrameLevel(i * 3)
-			frame:SetScript("OnHide", function()
-				self:Close(level + 1)
-			end)
-			if frame.SetTopLevel then
-				frame:SetTopLevel(true)
-			end
-			frame:EnableMouse(true)
-			frame:EnableMouseWheel(true)
-			local backdrop = CreateFrame("Frame", nil, frame)
-			backdrop:SetAllPoints(frame)
-			backdrop:SetBackdrop(tmp(
-				'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
-				'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
-				'tile', true,
-				'insets', tmp2(
-					'left', 5,
-					'right', 5,
-					'top', 5,
-					'bottom', 5
-				),
-				'tileSize', 16,
-				'edgeSize', 16
-			))
-			backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
-			backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
-			frame:SetScript("OnClick", function()
-				self:Close(i)
-			end)
-			frame:SetScript("OnEnter", function()
-				StopCounting(self, i)
-			end)
-			frame:SetScript("OnLeave", function()
-				StartCounting(self, i)
-			end)
-			frame:SetScript("OnMouseWheel", function()
-				Scroll(self, frame, arg1 < 0)
-			end)
-			if i == 1 then
-				frame:SetScript("OnUpdate", function(this, arg1)
-					OnUpdate(self, arg1)
-				end)
-				levels[1].lastDirection = "RIGHT"
-				levels[1].lastVDirection = "DOWN"
-			else
-				levels[i].lastDirection = levels[i - 1].lastDirection
-				levels[i].lastVDirection = levels[i - 1].lastVDirection
-			end
-		end
-	end
-	local fullscreenFrame = GetUIPanel("fullscreen")
-	local l = levels[level]
-	local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel()
-	if fullscreenFrame then
-		l:SetParent(fullscreenFrame)
-	else
-		l:SetParent(UIParent)
-	end
-	l:SetFrameStrata(strata)
-	l:SetFrameLevel(framelevel)
-	l:SetAlpha(1)
-	return l
-end
-
-local function validateOptions(options, position, baseOptions, fromPass)
-	if not baseOptions then
-		baseOptions = options
-	end
-	if type(options) ~= "table" then
-		return "Options must be a table.", position
-	end
-	local kind = options.type
-	if type(kind) ~= "string" then
-		return '"type" must be a string.', position
-	elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then
-		return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position
-	end
-	if options.aliases then
-		if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then
-			return '"alias" must be a table or string', position
-		end
-	end
-	if not fromPass then
-		if kind == "execute" then
-			if type(options.func) ~= "string" and type(options.func) ~= "function" then
-				return '"func" must be a string or function', position
-			end
-		elseif kind == "range" or kind == "text" or kind == "toggle" then
-			if type(options.set) ~= "string" and type(options.set) ~= "function" then
-				return '"set" must be a string or function', position
-			end
-			if kind == "text" and options.get == false then
-			elseif type(options.get) ~= "string" and type(options.get) ~= "function" then
-				return '"get" must be a string or function', position
-			end
-		elseif kind == "group" and options.pass then
-			if options.pass ~= true then
-				return '"pass" must be either nil, true, or false', position
-			end
-			if not options.func then
-				if type(options.set) ~= "string" and type(options.set) ~= "function" then
-					return '"set" must be a string or function', position
-				end
-				if type(options.get) ~= "string" and type(options.get) ~= "function" then
-					return '"get" must be a string or function', position
-				end
-			elseif type(options.func) ~= "string" and type(options.func) ~= "function" then
-				return '"func" must be a string or function', position
-			end
-		end
-	end
-	if options ~= baseOptions then
-		if kind == "header" then
-		elseif type(options.desc) ~= "string" then
-			return '"desc" must be a string', position
-		elseif options.desc:len() == 0 then
-			return '"desc" cannot be a 0-length string', position
-		end
-	end
-	if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then
-		if options.type == "header" and not options.cmdName and not options.name then
-		elseif options.cmdName then
-			if type(options.cmdName) ~= "string" then
-				return '"cmdName" must be a string or nil', position
-			elseif options.cmdName:len() == 0 then
-				return '"cmdName" cannot be a 0-length string', position
-			end
-			if type(options.guiName) ~= "string" then
-				if not options.guiNameIsMap then
-					return '"guiName" must be a string or nil', position
-				end
-			elseif options.guiName:len() == 0 then
-				return '"guiName" cannot be a 0-length string', position
-			end
-		else
-			if type(options.name) ~= "string" then
-				return '"name" must be a string', position
-			elseif options.name:len() == 0 then
-				return '"name" cannot be a 0-length string', position
-			end
-		end
-	end
-	if options.guiNameIsMap then
-		if type(options.guiNameIsMap) ~= "boolean" then
-			return '"guiNameIsMap" must be a boolean or nil', position
-		elseif options.type ~= "toggle" then
-			return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position
-		elseif type(options.map) ~= "table" then
-			return '"map" must be a table', position
-		end
-	end
-	if options.message and type(options.message) ~= "string" then
-		return '"message" must be a string or nil', position
-	end
-	if options.error and type(options.error) ~= "string" then
-		return '"error" must be a string or nil', position
-	end
-	if options.current and type(options.current) ~= "string" then
-		return '"current" must be a string or nil', position
-	end
-	if options.order then
-		if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then
-			return '"order" must be a non-zero number or nil', position
-		end
-	end
-	if options.disabled then
-		if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then
-			return '"disabled" must be a function, string, or boolean', position
-		end
-	end
-	if options.cmdHidden then
-		if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then
-			return '"cmdHidden" must be a function, string, or boolean', position
-		end
-	end
-	if options.guiHidden then
-		if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then
-			return '"guiHidden" must be a function, string, or boolean', position
-		end
-	end
-	if options.hidden then
-		if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then
-			return '"hidden" must be a function, string, or boolean', position
-		end
-	end
-	if kind == "text" then
-		if type(options.validate) == "table" then
-			local t = options.validate
-			local iTable = nil
-			for k,v in pairs(t) do
-				if type(k) == "number" then
-					if iTable == nil then
-						iTable = true
-					elseif not iTable then
-						return '"validate" must either have all keys be indexed numbers or strings', position
-					elseif k < 1 or k > #t then
-						return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position
-					end
-				else
-					if iTable == nil then
-						iTable = false
-					elseif iTable then
-						return '"validate" must either have all keys be indexed numbers or strings', position
-					end
-				end
-				if type(v) ~= "string" then
-					return '"validate" values must all be strings', position
-				end
-			end
-			if options.multiToggle and options.multiToggle ~= true then
-				return '"multiToggle" must be a boolean or nil if "validate" is a table', position
-			end
-		elseif options.validate == "keybinding" then
-			-- no other checks
-		else
-			if type(options.usage) ~= "string" then
-				return '"usage" must be a string', position
-			elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then
-				return '"validate" must be a string, function, or table', position
-			end
-		end
-		if options.multiToggle and type(options.validate) ~= "table" then
-			return '"validate" must be a table if "multiToggle" is true', position
-		end
-	elseif kind == "range" then
-		if options.min or options.max then
-			if type(options.min) ~= "number" then
-				return '"min" must be a number', position
-			elseif type(options.max) ~= "number" then
-				return '"max" must be a number', position
-			elseif options.min >= options.max then
-				return '"min" must be less than "max"', position
-			end
-		end
-		if options.step then
-			if type(options.step) ~= "number" then
-				return '"step" must be a number', position
-			elseif options.step < 0 then
-				return '"step" must be nonnegative', position
-			end
-		end
-		if options.bigStep then
-			if type(options.bigStep) ~= "number" then
-				return '"bigStep" must be a number', position
-			elseif options.bigStep < 0 then
-				return '"bigStep" must be nonnegative', position
-			end
-		end
-		if options.isPercent and options.isPercent ~= true then
-			return '"isPercent" must either be nil, true, or false', position
-		end
-	elseif kind == "toggle" then
-		if options.map then
-			if type(options.map) ~= "table" then
-				return '"map" must be a table', position
-			elseif type(options.map[true]) ~= "string" then
-				return '"map[true]" must be a string', position
-			elseif type(options.map[false]) ~= "string" then
-				return '"map[false]" must be a string', position
-			end
-		end
-	elseif kind == "color" then
-		if options.hasAlpha and options.hasAlpha ~= true then
-			return '"hasAlpha" must be nil, true, or false', position
-		end
-	elseif kind == "group" then
-		if options.pass and options.pass ~= true then
-			return '"pass" must be nil, true, or false', position
-		end
-		if type(options.args) ~= "table" then
-			return '"args" must be a table', position
-		end
-		for k,v in pairs(options.args) do
-			if type(k) ~= "number" then
-				if type(k) ~= "string" then
-					return '"args" keys must be strings or numbers', position
-				elseif k:len() == 0 then
-					return '"args" keys must not be 0-length strings.', position
-				end
-			end
-			if type(v) ~= "table" then
-				return '"args" values must be tables', position and position .. "." .. k or k
-			end
-			local newposition
-			if position then
-				newposition = position .. ".args." .. k
-			else
-				newposition = "args." .. k
-			end
-			local err, pos = validateOptions(v, newposition, baseOptions, options.pass)
-			if err then
-				return err, pos
-			end
-		end
-	elseif kind == "execute" then
-		if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then
-			return '"confirm" must be a string, boolean, or nil', position
-		end
-	end
-	if options.icon and type(options.icon) ~= "string" then
-		return'"icon" must be a string', position
-	end
-	if options.iconWidth or options.iconHeight then
-		if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then
-			return '"iconHeight" and "iconWidth" must be numbers', position
-		end
-	end
-	if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then
-		if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then
-			return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position
-		end
-	end
-end
-
-local validatedOptions
-
-local values
-local mysort_args
-local mysort
-local othersort
-local othersort_validate
-
-local baseFunc, currentLevel
-
-local function confirmPopup(message, func, ...)
-	if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then
-		StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {}
-	end
-	local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"]
-	for k in pairs(t) do
-		t[k] = nil
-	end
-	t.text = message
-	t.button1 = ACCEPT or "Accept"
-	t.button2 = CANCEL or "Cancel"
-	t.OnAccept = function()
-		func(unpack(t))
-	end
-	for i = 1, select('#', ...) do
-		t[i] = select(i, ...)
-	end
-	t.timeout = 0
-	t.whileDead = 1
-	t.hideOnEscape = 1
-
-	Dewdrop:Close()
-	StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG")
-end
-
-
-local function getMethod(settingname, handler, v, methodName, ...)	-- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222"
-	assert(v and type(v)=="table")
-	assert(methodName and type(methodName)=="string")
-
-	local method = v[methodName]
-	if type(method)=="function" then
-		return method, ...
-	elseif type(method)=="string" then
-		if not handler then
-			Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method)
-		elseif not handler[method] then
-			Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method)
-		end
-		return handler[method], handler, ...
-	end
-
-	Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName)
-end
-
-local function callMethod(settingname, handler, v, methodName, ...)
-	assert(v and type(v)=="table")
-	assert(methodName and type(methodName)=="string")
-
-	local method = v[methodName]
-	if type(method)=="function" then
-		local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...)
-		if not success then
-			geterrorhandler()(ret)
-			return nil
-		end
-		return ret,ret2,ret3,ret4
-
-	elseif type(method)=="string" then
-
-		local neg = method:match("^~(.-)$")
-		if neg then
-			method = neg
-		end
-		if not handler then
-			Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method)
-		elseif not handler[method] then
-			Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method)
-		end
-		local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...)
-		if not success then
-			geterrorhandler()(ret)
-			return nil
-		end
-		if neg then
-			return not ret
-		end
-		return ret,ret2,ret3,ret4
-	elseif method == false then
-		return nil
-	end
-
-	Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)")
-end
-
-local function skip1Nil(...)
-	if select(1,...)==nil then
-		return select(2,...)
-	end
-	return ...
-end
-
-function Dewdrop:FeedAceOptionsTable(options, difference)
-	self:argCheck(options, 2, "table")
-	self:argCheck(difference, 3, "nil", "number")
-	if not currentLevel then
-		self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration")
-	end
-	if not difference then
-		difference = 0
-	end
-	if not validatedOptions then
-		validatedOptions = {}
-	end
-	if not validatedOptions[options] then
-		local err, position = validateOptions(options)
-
-		if err then
-			if position then
-				Dewdrop:error(position .. ": " .. err)
-			else
-				Dewdrop:error(err)
-			end
-		end
-
-		validatedOptions[options] = true
-	end
-	local level = levels[currentLevel]
-	if not level then
-		self:error("Improper level given")
-	end
-	if not values then
-		values = {}
-	else
-		for k,v in pairs(values) do
-			values[k] = nil
-		end
-	end
-
-	local current = level
-	while current do		-- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later
-		if current.num == difference + 1 then
-			break
-		end
-		table.insert(values, current.value)
-		current = levels[current.num - 1]
-	end
-
-	local realOptions = options
-	local handler = options.handler
-	local passTable
-	local passValue
-	while #values > 0 do	-- This loop traverses values from the END (trunk nodes first, then onto leaf nodes)
-		if options.pass then
-			if options.get and options.set then
-				passTable = options
-			elseif not passTable then
-				passTable = options
-			end
-		else
-			passTable = nil
-		end
-		local value = table.remove(values)
-		options = options.args and options.args[value]
-		if not options then
-			return
-		end
-		handler = options.handler or handler
-		passValue = passTable and value or nil
-	end
-
-	if options.type == "group" then
-		local hidden = options.hidden
-		if type(hidden) == "function" or type(hidden) == "string" then
-			hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false
-		end
-		if hidden then
-			return
-		end
-		local disabled = options.disabled
-		if type(disabled) == "function" or type(disabled) == "string" then
-			disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false
-		end
-		if disabled then
-			self:AddLine(
-				'text', DISABLED,
-				'disabled', true
-			)
-			return
-		end
-		for k in pairs(options.args) do
-			table.insert(values, k)
-		end
-		if options.pass then
-			if options.get and options.set then
-				passTable = options
-			elseif not passTable then
-				passTable = options
-			end
-		else
-			passTable = nil
-		end
-		if not mysort then
-			mysort = function(a, b)
-				local alpha, bravo = mysort_args[a], mysort_args[b]
-				local alpha_order = alpha.order or 100
-				local bravo_order = bravo.order or 100
-				local alpha_name = alpha.guiName or alpha.name
-				local bravo_name = bravo.guiName or bravo.name
-				if alpha_order == bravo_order then
-					if not alpha_name then
-						return bravo_name
-					elseif not bravo_name then
-						return false
-					else
-						return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper()
-					end
-				else
-					if alpha_order < 0 then
-						if bravo_order > 0 then
-							return false
-						end
-					else
-						if bravo_order < 0 then
-							return true
-						end
-					end
-					return alpha_order < bravo_order
-				end
-			end
-		end
-		mysort_args = options.args
-		table.sort(values, mysort)
-		mysort_args = nil
-		local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0
-		local last_order = 1
-		for _,k in ipairs(values) do
-			local v = options.args[k]
-			local handler = v.handler or handler
-			if hasBoth and last_order > 0 and (v.order or 100) < 0 then
-				hasBoth = false
-				self:AddLine()
-			end
-			local hidden, disabled = v.guiHidden or v.hidden, v.disabled
-
-			if type(hidden) == "function" or type(hidden) == "string" then
-				hidden = callMethod(k, handler, v, "hidden", v.passValue) or false
-			end
-			if not hidden then
-				if type(disabled) == "function" or type(disabled) == "string" then
-					disabled = callMethod(k, handler, v, "disabled", v.passValue) or false
-				end
-				local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name)
-				local desc = v.guiDesc or v.desc
-				local iconHeight = v.iconHeight or 16
-				local iconWidth = v.iconWidth or 16
-				local iconCoordLeft = v.iconCoordLeft
-				local iconCoordRight = v.iconCoordRight
-				local iconCoordBottom = v.iconCoordBottom
-				local iconCoordTop = v.iconCoordTop
-				local tooltipTitle, tooltipText
-				tooltipTitle = name
-				if name ~= desc then
-					tooltipText = desc
-				end
-				if type(v.usage) == "string" and v.usage:trim():len() > 0 then
-					if tooltipText then
-						tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage)
-					else
-						tooltipText = USAGE_TOOLTIP:format(v.usage)
-					end
-				end
-				local v_p = passTable
-				if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then
-					v_p = v
-				end
-				local passValue = v.passValue or (v_p~=v and k) or nil
-				if v.type == "toggle" then
-					local checked = callMethod(name, handler, v_p, "get", passValue) or false
-					local checked_arg = checked
-					if type(v_p.get)=="string" and v_p.get:match("^~") then
-						checked_arg = not checked
-					end
-					local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set",   skip1Nil(passValue, not checked_arg))
-					if v.guiNameIsMap then
-						checked = checked and true or false
-						name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
-						tooltipTitle = name
-						checked = true--nil
-					end
-					self:AddLine(
-						'text', name,
-						'checked', checked,
-						'isRadio', v.isRadio,
-						'func', func,
-						'arg1', arg1,
-						'arg2', arg2,
-						'arg3', arg3,
-						'disabled', disabled,
-						'tooltipTitle', tooltipTitle,
-						'tooltipText', tooltipText
-					)
-				elseif v.type == "execute" then
-					local func, arg1, arg2, arg3, arg4
-					local confirm = v.confirm
-					if confirm == true then
-						confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle)
-						func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue)
-					elseif type(confirm) == "string" then
-						func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue)
-					else
-						func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue)
-					end
-					self:AddLine(
-						'text', name,
-						'checked', checked,
-						'func', func,
-						'arg1', arg1,
-						'arg2', arg2,
-						'arg3', arg3,
-						'arg4', arg4,
-						'disabled', disabled,
-						'tooltipTitle', tooltipTitle,
-						'tooltipText', tooltipText,
-						'icon', v.icon,
-						'iconHeight', iconHeight,
-						'iconWidth', iconWidth,
-						'iconCoordLeft', iconCoordLeft,
-						'iconCoordRight', iconCoordRight,
-						'iconCoordTop', iconCoordTop,
-						'iconCoordBottom', iconCoordBottom
-					)
-				elseif v.type == "range" then
-					local sliderValue
-					sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0
-					local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set",    passValue)
-					if tooltipText then
-						tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP)
-					else
-						tooltipText = RANGE_TOOLTIP
-					end
-					self:AddLine(
-						'text', name,
-						'hasArrow', true,
-						'hasSlider', true,
-						'sliderMin', v.min or 0,
-						'sliderMax', v.max or 1,
-						'sliderStep', v.step or 0,
-						'sliderBigStep', v.bigStep or nil,
-						'sliderIsPercent', v.isPercent or false,
-						'sliderValue', sliderValue,
-						'sliderFunc', sliderFunc,
-						'sliderArg1', sliderArg1,
-						'sliderArg2', sliderArg2,
-						'fromAceOptions', true,
-						'disabled', disabled,
-						'tooltipTitle', tooltipTitle,
-						'tooltipText', tooltipText,
-						'icon', v.icon,
-						'iconHeight', iconHeight,
-						'iconWidth', iconWidth,
-						'iconCoordLeft', iconCoordLeft,
-						'iconCoordRight', iconCoordRight,
-						'iconCoordTop', iconCoordTop,
-						'iconCoordBottom', iconCoordBottom
-					)
-				elseif v.type == "color" then
-					local r,g,b,a = callMethod(name, handler, v_p, "get", passValue)
-					if not r then
-						r,g,b,a = 0,0,0,0
-					end
-					local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set",    passValue)
-					self:AddLine(
-						'text', name,
-						'hasArrow', true,
-						'hasColorSwatch', true,
-						'r', r,
-						'g', g,
-						'b', b,
-						'opacity', v.hasAlpha and a or nil,
-						'hasOpacity', v.hasAlpha,
-						'colorFunc', colorFunc,
-						'colorArg1', colorArg1,
-						'colorArg2', colorArg2,
-						'disabled', disabled,
-						'tooltipTitle', tooltipTitle,
-						'tooltipText', tooltipText
-					)
-				elseif v.type == "text" then
-						if type(v.validate) == "table" then
-						local func,arg1,arg2
-						if v.onClick then
-							func,arg1,arg2 = getMethod(name, handler, v, "onClick",    passValue)
-						end
-						local checked
-						if v.isChecked then
-							checked = callMethod(name, handler, v, "isChecked",    passValue) or false
-						end
-						self:AddLine(
-							'text', name,
-							'hasArrow', true,
-							'value', k,
-							'func', func,
-							'arg1', arg1,
-							'arg2', arg2,
-							'mouseoverUnderline', func and true or nil,
-							'disabled', disabled,
-							'checked', checked,
-							'tooltipTitle', tooltipTitle,
-							'tooltipText', tooltipText,
-							'icon', v.icon,
-							'iconHeight', iconHeight,
-							'iconWidth', iconWidth,
-							'iconCoordLeft', iconCoordLeft,
-							'iconCoordRight', iconCoordRight,
-							'iconCoordTop', iconCoordTop,
-							'iconCoordBottom', iconCoordBottom
-						)
-					else
-						local editBoxText
-						editBoxText = callMethod(name, handler, v_p, "get", passValue) or ""
-						local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set",    passValue)
-
-						local editBoxValidateFunc, editBoxValidateArg1
-
-						if v.validate and v.validate ~= "keybinding" then
-							if v.validate == "keybinding" then
-								if tooltipText then
-									tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC)
-								else
-									tooltipText = RESET_KEYBINDING_DESC
-								end
-							else
-								editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue!
-							end
-						end
-
-						self:AddLine(
-							'text', name,
-							'hasArrow', true,
-							'icon', v.icon,
-							'iconHeight', iconHeight,
-							'iconWidth', iconWidth,
-							'iconCoordLeft', iconCoordLeft,
-							'iconCoordRight', iconCoordRight,
-							'iconCoordTop', iconCoordTop,
-							'iconCoordBottom', iconCoordBottom,
-							'hasEditBox', true,
-							'editBoxText', editBoxText,
-							'editBoxFunc', editBoxFunc,
-							'editBoxArg1', editBoxArg1,
-							'editBoxArg2', editBoxArg2,
-							'editBoxValidateFunc', editBoxValidateFunc,
-							'editBoxValidateArg1', editBoxValidateArg1,
-							'editBoxIsKeybinding', v.validate == "keybinding",
-							'editBoxKeybindingOnly', v.keybindingOnly,
-							'editBoxKeybindingExcept', v.keybindingExcept,
-							'disabled', disabled,
-							'tooltipTitle', tooltipTitle,
-							'tooltipText', tooltipText
-						)
-					end
-				elseif v.type == "group" then
-					local func,arg1,arg2
-					if v.onClick then
-						func,arg1,arg2 = getMethod(name, handler, v, "onClick",    passValue)
-					end
-					local checked
-					if v.isChecked then
-						checked = callMethod(name, handler, v, "isChecked",    passValue) or false
-					end
-					self:AddLine(
-						'text', name,
-						'hasArrow', true,
-						'value', k,
-						'func', func,
-						'arg1', arg1,
-						'arg2', arg2,
-						'mouseoverUnderline', func and true or nil,
-						'disabled', disabled,
-						'checked', checked,
-						'tooltipTitle', tooltipTitle,
-						'tooltipText', tooltipText,
-						'icon', v.icon,
-						'iconHeight', iconHeight,
-						'iconWidth', iconWidth,
-						'iconCoordLeft', iconCoordLeft,
-						'iconCoordRight', iconCoordRight,
-						'iconCoordTop', iconCoordTop,
-						'iconCoordBottom', iconCoordBottom
-					)
-				elseif v.type == "header" then
-					if name == "" or not name then
-						self:AddLine(
-							'isTitle', true,
-							'icon', v.icon,
-							'iconHeight', iconHeight,
-							'iconWidth', iconWidth,
-							'iconCoordLeft', iconCoordLeft,
-							'iconCoordRight', iconCoordRight,
-							'iconCoordTop', iconCoordTop,
-							'iconCoordBottom', iconCoordBottom
-						)
-					else
-						self:AddLine(
-							'text', name,
-							'isTitle', true,
-							'icon', v.icon,
-							'iconHeight', iconHeight,
-							'iconWidth', iconWidth,
-							'iconCoordLeft', iconCoordLeft,
-							'iconCoordRight', iconCoordRight,
-							'iconCoordTop', iconCoordTop,
-							'iconCoordBottom', iconCoordBottom
-						)
-					end
-				end
-			end
-			last_order = v.order or 100
-		end
-	elseif options.type == "text" and type(options.validate) == "table" then
-		local current
-		local options_p = passTable
-		if not options_p or (options.get and options.set) then
-			options_p = options
-			passTable = nil
-			passValue = nil
-		end
-		local multiToggle = options.multiToggle
-		local passValue = options.passValue or passValue
-		if not multiToggle then
-			current = callMethod(k, handler, options_p, "get", passValue)
-		end
-		local indexed = true
-		for k,v in pairs(options.validate) do
-			if type(k) ~= "number" then
-				indexed = false
-			end
-			table.insert(values, k)
-		end
-		if not indexed then
-			if not othersort then
-				othersort = function(alpha, bravo)
-					return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper()
-				end
-			end
-			othersort_validate = options.validate
-			table.sort(values, othersort)
-			othersort_validate = nil
-		end
-		for _,k in ipairs(values) do
-			local v = options.validate[k]
-			if type(k) == "number" then
-				k = v
-			end
-			local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set",    skip1Nil(passValue, k))
-			local checked
-			if multiToggle then
-				checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false
-				if arg2 == nil then
-					arg2 = not checked
-				elseif arg3 == nil then
-					arg3 = not checked
-				else
-					arg4 = not checked
-				end
-			else
-				checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower()))
-				if checked then
-					func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil
-				end
-			end
-			local tooltipTitle
-			local tooltipText
-			if options.validateDesc then
-				tooltipTitle = v
-				tooltipText = options.validateDesc[k]
-			else
-				tooltipTitle = options.guiName or options.name
-				tooltipText = v
-			end
-			self:AddLine(
-				'text', v,
-				'func', func,
-				'arg1', arg1,
-				'arg2', arg2,
-				'arg3', arg3,
-				'arg4', arg4,
-				'isRadio', not multiToggle,
-				'checked',  checked,
-				'tooltipTitle', tooltipTitle,
-				'tooltipText', tooltipText
-			)
-		end
-		for k in pairs(values) do
-			values[k] = nil
-		end
-	else
-		return false
-	end
-	return true
-end
-
-function Dewdrop:FeedTable(s, difference)
-	self:argCheck(s, 2, "table")
-	self:argCheck(difference, 3, "nil", "number")
-	if not currentLevel then
-		self:error("Cannot call `FeedTable' outside of a Dewdrop declaration")
-	end
-	if not difference then
-		difference = 0
-	end
-	local level = levels[currentLevel]
-	if not level then
-		self:error("Improper level given")
-	end
-	if not values then
-		values = {}
-	else
-		for k,v in pairs(values) do
-			values[k] = nil
-		end
-	end
-	local t = s.subMenu and s or {subMenu = s}
-	local current = level
-	while current do
-		if current.num == difference + 1 then
-			break
-		end
-		table.insert(values, current.value)
-		current = levels[current.num - 1]
-	end
-
-	while #values > 0 do
-		local value = table.remove(values)
-		t = t.subMenu and t.subMenu[value]
-		if not t then
-			return
-		end
-	end
-
-	if t.subMenu or current.num == 1 then
-		for k in pairs(t.subMenu) do
-			table.insert(values, k)
-		end
-		table.sort(values)
-		for _,k in ipairs(values) do
-			local argTable = {"value", k}
-			for key, val in pairs(t.subMenu[k]) do
-				table.insert(argTable, key)
-				table.insert(argTable, val)
-			end
-			self:AddLine(unpack(argTable))
-		end
-		for k in pairs(values) do
-			values[k] = nil
-		end
-		return false
-	end
-	return true
-end
-
-function Refresh(self, level)
-	if type(level) == "number" then
-		level = levels[level]
-	end
-	if not level then
-		return
-	end
-	if baseFunc then
-		Clear(self, level)
-		currentLevel = level.num
-		if type(baseFunc) == "table" then
-			if currentLevel == 1 then
-				local handler = baseFunc.handler
-				if handler then
-					local name = tostring(handler)
-					if not name:find('^table:') and not handler.hideMenuTitle then
-						name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
-						self:AddLine(
-							'text', name,
-							'isTitle', true
-						)
-					end
-				end
---			elseif level.parentText then
---				self:AddLine(
---					'text', level.parentText,
---					'tooltipTitle', level.parentTooltipTitle,
---					'tooltipText', level.parentTooltipText,
---					'tooltipFunc', level.parentTooltipFunc,
---					'isTitle', true
---				)
-			end
-			self:FeedAceOptionsTable(baseFunc)
-			if currentLevel == 1 then
-				self:AddLine(
-					'text', CLOSE,
-					'tooltipTitle', CLOSE,
-					'tooltipText', CLOSE_DESC,
-					'closeWhenClicked', true
-				)
-			end
-		else
---			if level.parentText then
---				self:AddLine(
---					'text', level.parentText,
---					'tooltipTitle', level.parentTooltipTitle,
---					'tooltipText', level.parentTooltipText,
---					'tooltipFunc', level.parentTooltipFunc,
---					'isTitle', true
---				)
---			end
-			baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value)
-		end
-		currentLevel = nil
-		CheckSize(self, level)
-	end
-end
-
-function Dewdrop:Refresh(level)
-	self:argCheck(level, 2, "number", "nil")
-	if not level then
-		for k,v in pairs(levels) do
-			Refresh(self, v)
-		end
-	else
-		Refresh(self, levels[level])
-	end
-end
-
-function OpenSlider(self, parent)
-	if not sliderFrame then
-		sliderFrame = CreateFrame("Frame", nil, nil)
-		sliderFrame:SetWidth(100)
-		sliderFrame:SetHeight(170)
-		sliderFrame:SetScale(UIParent:GetScale())
-		sliderFrame:SetBackdrop(tmp(
-			'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
-			'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
-			'tile', true,
-			'insets', tmp2(
-				'left', 5,
-				'right', 5,
-				'top', 5,
-				'bottom', 5
-			),
-			'tileSize', 16,
-			'edgeSize', 16
-		))
-		sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG")
-		if sliderFrame.SetTopLevel then
-			sliderFrame:SetTopLevel(true)
-		end
-		sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
-		sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
-		sliderFrame:EnableMouse(true)
-		sliderFrame:EnableMouseWheel(true)
-		sliderFrame:Hide()
-		sliderFrame:SetPoint("CENTER", UIParent, "CENTER")
-		local slider = CreateFrame("Slider", nil, sliderFrame)
-		sliderFrame.slider = slider
-		slider:SetOrientation("VERTICAL")
-		slider:SetMinMaxValues(0, 1)
-		slider:SetValueStep(0.000000001)
-		slider:SetValue(0.5)
-		slider:SetWidth(16)
-		slider:SetHeight(128)
-		slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0)
-		slider:SetBackdrop(tmp(
-			'bgFile', "Interface\\Buttons\\UI-SliderBar-Background",
-			'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border",
-			'tile', true,
-			'edgeSize', 8,
-			'tileSize', 8,
-			'insets', tmp2(
-				'left', 3,
-				'right', 3,
-				'top', 3,
-				'bottom', 3
-			)
-		))
-		local texture = slider:CreateTexture()
-		slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
-		local text = slider:CreateFontString(nil, "ARTWORK")
-		sliderFrame.topText = text
-		text:SetFontObject(GameFontGreenSmall)
-		text:SetText("100%")
-		text:SetPoint("BOTTOM", slider, "TOP")
-		local text = slider:CreateFontString(nil, "ARTWORK")
-		sliderFrame.bottomText = text
-		text:SetFontObject(GameFontGreenSmall)
-		text:SetText("0%")
-		text:SetPoint("TOP", slider, "BOTTOM")
-		local editBox = CreateFrame("EditBox", nil, sliderFrame)
-		sliderFrame.currentText = editBox
-		editBox:SetFontObject(ChatFontNormal)
-		editBox:SetHeight(13)
-		editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0)
-		editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0)
-		editBox:SetText("50%")
-		editBox:SetJustifyH("CENTER")
-
-		local width = editBox:GetWidth()/2 + 10
-		local left = editBox:CreateTexture(nil, "BACKGROUND")
-		left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
-		left:SetTexCoord(0, width / 256, 0, 1)
-		left:SetWidth(width)
-		left:SetHeight(32)
-		left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
-		local right = editBox:CreateTexture(nil, "BACKGROUND")
-		right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
-		right:SetTexCoord(1 - width / 256, 1, 0, 1)
-		right:SetWidth(width)
-		right:SetHeight(32)
-		right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
-
-		local changed = false
-		local inside = false
-		slider:SetScript("OnValueChanged", function()
-			if sliderFrame.changing then
-				return
-			end
-			changed = true
-			local done = false
-			if sliderFrame.parent and sliderFrame.parent.sliderFunc then
-				local min = sliderFrame.parent.sliderMin or 0
-				local max = sliderFrame.parent.sliderMax or 1
-				local step
-				if sliderFrame.fineStep then
-					step = sliderFrame.parent.sliderStep or (max - min) / 100
-				else
-					step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100
-				end
-				local value = (1 - slider:GetValue()) * (max - min) + min
-				if step > 0 then
-					value = math.floor((value - min) / step + 0.5) * step + min
-					if value > max then
-						value = max
-					elseif value < min then
-						value = min
-					end
-				end
-				if value == sliderFrame.lastValue then
-					return
-				end
-				sliderFrame.lastValue = value
-				local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value))
-				if sliderFrame.parent.fromAceOptions then
-					text = nil
-				elseif type(text) == "string" or type(text) == "number" then
-					sliderFrame.currentText:SetText(text)
-					done = true
-				end
-			end
-			if not done then
-				local min = sliderFrame.parent.sliderMin or 0
-				local max = sliderFrame.parent.sliderMax or 1
-				local step
-				if sliderFrame.fineStep then
-					step = sliderFrame.parent.sliderStep or (max - min) / 100
-				else
-					step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100
-				end
-				local value = (1 - slider:GetValue()) * (max - min) + min
-				if step > 0 then
-					value = math.floor((value - min) / step + 0.5) * step + min
-					if value > max then
-						value = max
-					elseif value < min then
-						value = min
-					end
-				end
-				if sliderFrame.parent.sliderIsPercent then
-					sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100))
-				else
-					if step < 0.1 then
-						sliderFrame.currentText:SetText(string.format("%.2f", value))
-					elseif step < 1 then
-						sliderFrame.currentText:SetText(string.format("%.1f", value))
-					else
-						sliderFrame.currentText:SetText(string.format("%.0f", value))
-					end
-				end
-			end
-		end)
-		local function onEnter()
-			StopCounting(self, sliderFrame.level)
-			showGameTooltip(sliderFrame.parent)
-		end
-		local function onLeave()
-			GameTooltip:Hide()
-		end
-		sliderFrame:SetScript("OnEnter", onEnter)
-		sliderFrame:SetScript("OnLeave", function()
-			GameTooltip:Hide()
-			if changed then
-				local parent = sliderFrame.parent
-				local sliderFunc = parent.sliderFunc
-				for i = 1, sliderFrame.level - 1 do
-					Refresh(self, levels[i])
-				end
-				local newParent
-				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
-					if button.sliderFunc == sliderFunc then
-						newParent = button
-						break
-					end
-				end
-				if newParent then
-					OpenSlider(self, newParent)
-				else
-					sliderFrame:Hide()
-				end
-			end
-		end)
-		editBox:SetScript("OnEnter", onEnter)
-		editBox:SetScript("OnLeave", onLeave)
-		slider:SetScript("OnMouseDown", function()
-			sliderFrame.mouseDown = true
-			GameTooltip:Hide()
-		end)
-		slider:SetScript("OnMouseUp", function()
-			sliderFrame.mouseDown = false
-			if changed--[[ and not inside]] then
-				local parent = sliderFrame.parent
-				local sliderFunc = parent.sliderFunc
-				for i = 1, sliderFrame.level - 1 do
-					Refresh(self, levels[i])
-				end
-				local newParent
-				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
-					if button.sliderFunc == sliderFunc then
-						newParent = button
-						break
-					end
-				end
-				if newParent then
-					OpenSlider(self, newParent)
-				else
-					sliderFrame:Hide()
-				end
-			end
-			if inside then
-				showGameTooltip(sliderFrame.parent)
-			end
-		end)
-		slider:SetScript("OnEnter", function()
-			inside = true
-			StopCounting(self, sliderFrame.level)
-			showGameTooltip(sliderFrame.parent)
-		end)
-		slider:SetScript("OnLeave", function()
-			inside = false
-			GameTooltip:Hide()
-			if changed and not sliderFrame.mouseDown then
-				local parent = sliderFrame.parent
-				local sliderFunc = parent.sliderFunc
-				for i = 1, sliderFrame.level - 1 do
-					Refresh(self, levels[i])
-				end
-				local newParent
-				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
-					if button.sliderFunc == sliderFunc then
-						newParent = button
-						break
-					end
-				end
-				if newParent then
-					OpenSlider(self, newParent)
-				else
-					sliderFrame:Hide()
-				end
-
-				changed = false
-			end
-		end)
-		sliderFrame:SetScript("OnMouseWheel", function(t, a1)
-			local arg1 = a1 or arg1
-			local up = arg1 > 0
-
-			local min = sliderFrame.parent.sliderMin or 0
-			local max = sliderFrame.parent.sliderMax or 1
-			local step = sliderFrame.parent.sliderStep or (max - min) / 100
-			if step <= 0 then
-				step = (max - min) / 100
-			end
-
-			local value = (1 - slider:GetValue()) * (max - min) + min
-			if up then
-				value = value + step
-			else
-				value = value - step
-			end
-			if value > max then
-				value = max
-			elseif value < min then
-				value = min
-			end
-			sliderFrame.fineStep = true
-			if max<=min then
-				slider:SetValue(0)
-			else
-				slider:SetValue(1 - (value - min) / (max - min))
-			end
-			sliderFrame.fineStep = nil
-		end)
-		slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel"))
-		editBox:SetScript("OnEnterPressed", function(t, a1)
-			local value = editBox:GetNumber()
-
-			if sliderFrame.parent.sliderIsPercent then
-				value = value / 100
-			end
-
-			local min = sliderFrame.parent.sliderMin or 0
-			local max = sliderFrame.parent.sliderMax or 1
-
-			if value > max then
-				value = max
-			elseif value < min then
-				value = min
-			end
-			sliderFrame.fineStep = true
-			if max <= min then
-				slider:SetValue(0)
-			else
-				slider:SetValue(1 - (value - min) / (max - min))
-			end
-			sliderFrame.fineStep = nil
-
-			StartCounting(self, sliderFrame.level)
-		end)
-		editBox:SetScript("OnEscapePressed", function()
-			self:Close(sliderFrame.level)
-			StartCounting(self, sliderFrame.level)
-		end)
-		editBox:SetAutoFocus(false)
-	end
-	sliderFrame.parent = parent
-	sliderFrame.level = parent.level.num + 1
-	sliderFrame.parentValue = parent.level.value
-	sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
-	sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
-	sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
-	sliderFrame.currentText:ClearFocus()
-	sliderFrame.changing = true
-	if not parent.sliderMin or not parent.sliderMax then
-		return
-	end
-
-	if parent.arrow then
---		parent.arrow:SetVertexColor(0.2, 0.6, 0)
---		parent.arrow:SetHeight(24)
---		parent.arrow:SetWidth(24)
-		parent.selected = true
-		parent.highlight:Show()
-	end
-
-	sliderFrame:SetClampedToScreen(false)
-	if not parent.sliderValue then
-		parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2
-	end
-	if parent.sliderMax <= parent.sliderMin then
-		sliderFrame.slider:SetValue(0)
-	else
-		sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin))
-	end
-	sliderFrame.changing = false
-	sliderFrame.bottomText:SetText(parent.sliderMinText or "0")
-	sliderFrame.topText:SetText(parent.sliderMaxText or "1")
-	local text
-	if parent.sliderFunc and not parent.fromAceOptions then
-		text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue))
-	end
-	if type(text) == "number" or type(text) == "string" then
-		sliderFrame.currentText:SetText(text)
-	elseif parent.sliderIsPercent then
-		sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100))
-	else
-		if parent.sliderStep < 0.1 then
-			sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue))
-		elseif parent.sliderStep < 1 then
-			sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue))
-		else
-			sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue))
-		end
-	end
-
-
-	sliderFrame.lastValue = parent.sliderValue
-
-	local level = parent.level
-	sliderFrame:Show()
-	sliderFrame:ClearAllPoints()
-	if level.lastDirection == "RIGHT" then
-		if level.lastVDirection == "DOWN" then
-			sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
-		else
-			sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
-		end
-	else
-		if level.lastVDirection == "DOWN" then
-			sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
-		else
-			sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
-		end
-	end
-	local dirty
-	if level.lastDirection == "RIGHT" then
-		if sliderFrame:GetRight() > GetScreenWidth() then
-			level.lastDirection = "LEFT"
-			dirty = true
-		end
-	elseif sliderFrame:GetLeft() < 0 then
-		level.lastDirection = "RIGHT"
-		dirty = true
-	end
-	if level.lastVDirection == "DOWN" then
-		if sliderFrame:GetBottom() < 0 then
-			level.lastVDirection = "UP"
-			dirty = true
-		end
-	elseif sliderFrame:GetTop() > GetScreenWidth() then
-		level.lastVDirection = "DOWN"
-		dirty = true
-	end
-	if dirty then
-		sliderFrame:ClearAllPoints()
-		if level.lastDirection == "RIGHT" then
-			if level.lastVDirection == "DOWN" then
-				sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
-			else
-				sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
-			end
-		else
-			if level.lastVDirection == "DOWN" then
-				sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
-			else
-				sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
-			end
-		end
-	end
-	local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom()
-	sliderFrame:ClearAllPoints()
-	sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
-	if mod(level.num, 5) == 0 then
-		local left, bottom = level:GetLeft(), level:GetBottom()
-		level:ClearAllPoints()
-		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
-	end
-	sliderFrame:SetClampedToScreen(true)
-end
-
-function OpenEditBox(self, parent)
-	if not editBoxFrame then
-		editBoxFrame = CreateFrame("Frame", nil, nil)
-		editBoxFrame:SetWidth(200)
-		editBoxFrame:SetHeight(40)
-		editBoxFrame:SetScale(UIParent:GetScale())
-		editBoxFrame:SetBackdrop(tmp(
-			'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
-			'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
-			'tile', true,
-			'insets', tmp2(
-				'left', 5,
-				'right', 5,
-				'top', 5,
-				'bottom', 5
-			),
-			'tileSize', 16,
-			'edgeSize', 16
-		))
-		editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG")
-		if editBoxFrame.SetTopLevel then
-			editBoxFrame:SetTopLevel(true)
-		end
-		editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
-		editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
-		editBoxFrame:EnableMouse(true)
-		editBoxFrame:EnableMouseWheel(true)
-		editBoxFrame:Hide()
-		editBoxFrame:SetPoint("CENTER", UIParent, "CENTER")
-
-		local editBox = CreateFrame("EditBox", nil, editBoxFrame)
-		editBoxFrame.editBox = editBox
-		editBox:SetFontObject(ChatFontNormal)
-		editBox:SetWidth(160)
-		editBox:SetHeight(13)
-		editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0)
-
-		local left = editBox:CreateTexture(nil, "BACKGROUND")
-		left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
-		left:SetTexCoord(0, 100 / 256, 0, 1)
-		left:SetWidth(100)
-		left:SetHeight(32)
-		left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
-		local right = editBox:CreateTexture(nil, "BACKGROUND")
-		right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
-		right:SetTexCoord(156/256, 1, 0, 1)
-		right:SetWidth(100)
-		right:SetHeight(32)
-		right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
-
-		editBox:SetScript("OnEnterPressed", function()
-			if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then
-				local t = editBox.realText or editBox:GetText() or ""
-				local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t))
-				if not result then
-					UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0)
-					return
-				end
-			end
-			if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then
-				local t
-				if editBox.realText ~= "NONE" then
-					t = editBox.realText or editBox:GetText() or ""
-				end
-				editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t))
-			end
-			self:Close(editBoxFrame.level)
-			for i = 1, editBoxFrame.level - 1 do
-				Refresh(self, levels[i])
-			end
-			StartCounting(self, editBoxFrame.level-1)
-		end)
-		editBox:SetScript("OnEscapePressed", function()
-			self:Close(editBoxFrame.level)
-			StartCounting(self, editBoxFrame.level-1)
-		end)
-		editBox:SetScript("OnReceiveDrag", function(this)
-			if GetCursorInfo then
-				local type, alpha, bravo = GetCursorInfo()
-				local text
-				if type == "spell" then
-					text = GetSpellName(alpha, bravo)
-				elseif type == "item" then
-					text = bravo
-				end
-				if not text then
-					return
-				end
-				ClearCursor()
-				editBox:SetText(text)
-			end
-		end)
-		local changing = false
-		local skipNext = false
-
-		function editBox:SpecialSetText(text)
-			local oldText = editBox:GetText() or ""
-			if not text then
-				text = ""
-			end
-			if text ~= oldText then
-				changing = true
-				self:SetText(tostring(text))
-				changing = false
-				skipNext = true
-			end
-		end
-
-		editBox:SetScript("OnTextChanged", function()
-			if skipNext then
-				skipNext = false
-			elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then
-				local t
-				if editBox.realText ~= "NONE" then
-					t = editBox.realText or editBox:GetText() or ""
-				end
-				local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t))
-				if text then
-					editBox:SpecialSetText(text)
-				end
-			end
-		end)
-		editBoxFrame:SetScript("OnEnter", function()
-			StopCounting(self, editBoxFrame.level)
-			showGameTooltip(editBoxFrame.parent)
-		end)
-		editBoxFrame:SetScript("OnLeave", function()
-			GameTooltip:Hide()
-		end)
-		editBox:SetScript("OnEnter", function()
-			StopCounting(self, editBoxFrame.level)
-			showGameTooltip(editBoxFrame.parent)
-		end)
-		editBox:SetScript("OnLeave", function()
-			GameTooltip:Hide()
-		end)
-		editBoxFrame:SetScript("OnKeyDown", function(this, a1)
-			if not editBox.keybinding then
-				return
-			end
-			local arg1 = a1 or arg1
-			local screenshotKey = GetBindingKey("SCREENSHOT")
-			if screenshotKey and arg1 == screenshotKey then
-				Screenshot()
-				return
-			end
-
-			if arg1 == "LeftButton" then
-				arg1 = "BUTTON1"
-			elseif arg1 == "RightButton" then
-				arg1 = "BUTTON2"
-			elseif arg1 == "MiddleButton" then
-				arg1 = "BUTTON3"
-			elseif arg1 == "Button4" then
-				arg1 = "BUTTON4"
-			elseif arg1 == "Button5" then
-				arg1 = "BUTTON5"
-			end
-			if arg1 == "UNKNOWN" then
-				return
-			elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then
-				return
-			elseif arg1 == "ENTER" then
-				if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then
-					return editBox:GetScript("OnEscapePressed")()
-				elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then
-					return editBox:GetScript("OnEscapePressed")()
-				else
-					return editBox:GetScript("OnEnterPressed")()
-				end
-			elseif arg1 == "ESCAPE" then
-				if editBox.realText == "NONE" then
-					return editBox:GetScript("OnEscapePressed")()
-				else
-					editBox:SpecialSetText(NONE or "NONE")
-					editBox.realText = "NONE"
-					return
-				end
-			elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then
-				return
-			elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then
-				return
-			end
-			local s = GetBindingText(arg1, "KEY_")
-			if s == "BUTTON1" then
-				s = KEY_BUTTON1
-			elseif s == "BUTTON2" then
-				s = KEY_BUTTON2
-			end
-			local real = arg1
-			if IsShiftKeyDown() then
-				s = "Shift-" .. s
-				real = "SHIFT-" .. real
-			end
-			if IsControlKeyDown() then
-				s = "Ctrl-" .. s
-				real = "CTRL-" .. real
-			end
-			if IsAltKeyDown() then
-				s = "Alt-" .. s
-				real = "ALT-" .. real
-			end
-			if editBox:GetText() ~= s then
-				editBox:SpecialSetText("-")
-				editBox:SpecialSetText(s)
-				editBox.realText = real
-				return editBox:GetScript("OnTextChanged")()
-			end
-		end)
-		editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown"))
-		editBox:SetScript("OnMouseDown", function(this, ...)
-			if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then
-				return editBox:GetScript("OnReceiveDrag")(this, ...)
-			end
-			return editBoxFrame:GetScript("OnKeyDown")(this, ...)
-		end)
-		editBoxFrame:SetScript("OnMouseWheel", function(t, a1)
-			local arg1 = a1 or arg1
-			local up = arg1 > 0
-			arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN"
-			return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1)
-		end)
-		editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel"))
-	end
-	editBoxFrame.parent = parent
-	editBoxFrame.level = parent.level.num + 1
-	editBoxFrame.parentValue = parent.level.value
-	editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
-	editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1)
-	editBoxFrame.editBox.realText = nil
-	editBoxFrame:SetClampedToScreen(false)
-
-	editBoxFrame.editBox:SpecialSetText("")
-	if parent.editBoxIsKeybinding then
-		local s = parent.editBoxText
-		if s == "" then
-			s =  "NONE"
-		end
-		editBoxFrame.editBox.realText = s
-		if s and s ~= "NONE" then
-			local alpha,bravo = s:match("^(.+)%-(.+)$")
-			if not bravo then
-				alpha = nil
-				bravo = s
-			end
-			bravo = GetBindingText(bravo, "KEY_")
-			if alpha then
-				editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo)
-			else
-				editBoxFrame.editBox:SpecialSetText(bravo)
-			end
-		else
-			editBoxFrame.editBox:SpecialSetText(NONE or "NONE")
-		end
-	else
-		editBoxFrame.editBox:SpecialSetText(parent.editBoxText)
-	end
-
-	editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding
-	editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly
-	editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept
-	editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding)
-	editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding)
-
-	if parent.arrow then
---		parent.arrow:SetVertexColor(0.2, 0.6, 0)
---		parent.arrow:SetHeight(24)
---		parent.arrow:SetWidth(24)
-		parent.selected = true
-		parent.highlight:Show()
-	end
-
-	local level = parent.level
-	editBoxFrame:Show()
-	editBoxFrame:ClearAllPoints()
-	if level.lastDirection == "RIGHT" then
-		if level.lastVDirection == "DOWN" then
-			editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
-		else
-			editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
-		end
-	else
-		if level.lastVDirection == "DOWN" then
-			editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
-		else
-			editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
-		end
-	end
-	local dirty
-	if level.lastDirection == "RIGHT" then
-		if editBoxFrame:GetRight() > GetScreenWidth() then
-			level.lastDirection = "LEFT"
-			dirty = true
-		end
-	elseif editBoxFrame:GetLeft() < 0 then
-		level.lastDirection = "RIGHT"
-		dirty = true
-	end
-	if level.lastVDirection == "DOWN" then
-		if editBoxFrame:GetBottom() < 0 then
-			level.lastVDirection = "UP"
-			dirty = true
-		end
-	elseif editBoxFrame:GetTop() > GetScreenWidth() then
-		level.lastVDirection = "DOWN"
-		dirty = true
-	end
-	if dirty then
-		editBoxFrame:ClearAllPoints()
-		if level.lastDirection == "RIGHT" then
-			if level.lastVDirection == "DOWN" then
-				editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
-			else
-				editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
-			end
-		else
-			if level.lastVDirection == "DOWN" then
-				editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
-			else
-				editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
-			end
-		end
-	end
-	local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom()
-	editBoxFrame:ClearAllPoints()
-	editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
-	if mod(level.num, 5) == 0 then
-		local left, bottom = level:GetLeft(), level:GetBottom()
-		level:ClearAllPoints()
-		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
-	end
-	editBoxFrame:SetClampedToScreen(true)
-end
-
-function Dewdrop:EncodeKeybinding(text)
-	if text == nil or text == "NONE" then
-		return nil
-	end
-	text = tostring(text):upper()
-	local shift, ctrl, alt
-	local modifier
-	while true do
-		if text == "-" then
-			break
-		end
-		modifier, text = strsplit('-', text, 2)
-		if text then
-			if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
-				return false
-			end
-			if modifier == "SHIFT" then
-				if shift then
-					return false
-				end
-				shift = true
-			end
-			if modifier == "CTRL" then
-				if ctrl then
-					return false
-				end
-				ctrl = true
-			end
-			if modifier == "ALT" then
-				if alt then
-					return false
-				end
-				alt = true
-			end
-		else
-			text = modifier
-			break
-		end
-	end
-	if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then
-		return false
-	end
-	local s = GetBindingText(text, "KEY_")
-	if s == "BUTTON1" then
-		s = KEY_BUTTON1
-	elseif s == "BUTTON2" then
-		s = KEY_BUTTON2
-	end
-	if shift then
-		s = "Shift-" .. s
-	end
-	if ctrl then
-		s = "Ctrl-" .. s
-	end
-	if alt then
-		s = "Alt-" .. s
-	end
-	return s
-end
-
-function Dewdrop:IsOpen(parent)
-	self:argCheck(parent, 2, "table", "string", "nil")
-	return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent())
-end
-
-function Dewdrop:GetOpenedParent()
-	return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent())
-end
-
-function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY)
-	self:Close(level)
-	if DewdropLib then
-		local d = DewdropLib:GetInstance('1.0')
-		local ret, val = pcall(d, IsOpen, d)
-		if ret and val then
-			DewdropLib:GetInstance('1.0'):Close()
-		end
-	end
-	if type(parent) == "table" then
-		parent:GetCenter()
-	end
-	local frame = AcquireLevel(self, level)
-	if level == 1 then
-		frame.lastDirection = "RIGHT"
-		frame.lastVDirection = "DOWN"
-	else
-		frame.lastDirection = levels[level - 1].lastDirection
-		frame.lastVDirection = levels[level - 1].lastVDirection
-	end
-	frame:SetFrameStrata("FULLSCREEN_DIALOG")
-	frame:ClearAllPoints()
-	frame.parent = parent
-	frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0)
-	frame:Show()
-	if level == 1 then
-		baseFunc = func
-	end
-	levels[level].value = value
---	levels[level].parentText = parent.text and parent.text:GetText() or nil
---	levels[level].parentTooltipTitle = parent.tooltipTitle
---	levels[level].parentTooltipText = parent.tooltipText
---	levels[level].parentTooltipFunc = parent.tooltipFunc
-	if type(parent) == "table" and parent.arrow then
---		parent.arrow:SetVertexColor(0.2, 0.6, 0)
---		parent.arrow:SetHeight(24)
---		parent.arrow:SetWidth(24)
-		parent.selected = true
-		parent.highlight:Show()
-	end
-	relativePoint = relativePoint or point
-	Refresh(self, levels[level])
-	if point or (cursorX and cursorY) then
-		frame:ClearAllPoints()
-		if cursorX and cursorY then
-			local curX, curY = GetScaledCursorPosition()
-			if curY < GetScreenHeight() / 2 then
-				point, relativePoint = "BOTTOM", "BOTTOM"
-			else
-				point, relativePoint = "TOP", "TOP"
-			end
-			if curX < GetScreenWidth() / 2 then
-				point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT"
-			else
-				point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT"
-			end
-		end
-		frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint)
-		if cursorX and cursorY then
-			local left = frame:GetLeft()
-			local width = frame:GetWidth()
-			local bottom = frame:GetBottom()
-			local height = frame:GetHeight()
-			local curX, curY = GetScaledCursorPosition()
-			frame:ClearAllPoints()
-			relativePoint = relativePoint or point
-			if point == "BOTTOM" or point == "TOP" then
-				if curX < GetScreenWidth() / 2 then
-					point = point .. "LEFT"
-				else
-					point = point .. "RIGHT"
-				end
-			elseif point == "CENTER" then
-				if curX < GetScreenWidth() / 2 then
-					point = "LEFT"
-				else
-					point = "RIGHT"
-				end
-			end
-			local xOffset, yOffset = 0, 0
-			if curY > GetScreenHeight() / 2 then
-				yOffset = -height
-			end
-			if curX > GetScreenWidth() / 2 then
-				xOffset = -width
-			end
-			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset)
-			if level == 1 then
-				frame.lastDirection = "RIGHT"
-			end
-		elseif cursorX then
-			local left = frame:GetLeft()
-			local width = frame:GetWidth()
-			local curX, curY = GetScaledCursorPosition()
-			frame:ClearAllPoints()
-			relativePoint = relativePoint or point
-			if point == "BOTTOM" or point == "TOP" then
-				if curX < GetScreenWidth() / 2 then
-					point = point .. "LEFT"
-				else
-					point = point .. "RIGHT"
-				end
-			elseif point == "CENTER" then
-				if curX < GetScreenWidth() / 2 then
-					point = "LEFT"
-				else
-					point = "RIGHT"
-				end
-			end
-			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0)
-			if level == 1 then
-				frame.lastDirection = "RIGHT"
-			end
-		elseif cursorY then
-			local bottom = frame:GetBottom()
-			local height = frame:GetHeight()
-			local curX, curY = GetScaledCursorPosition()
-			frame:ClearAllPoints()
-			relativePoint = relativePoint or point
-			if point == "LEFT" or point == "RIGHT" then
-				if curX < GetScreenHeight() / 2 then
-					point = point .. "BOTTOM"
-				else
-					point = point .. "TOP"
-				end
-			elseif point == "CENTER" then
-				if curX < GetScreenHeight() / 2 then
-					point = "BOTTOM"
-				else
-					point = "TOP"
-				end
-			end
-			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2)
-			if level == 1 then
-				frame.lastDirection = "DOWN"
-			end
-		end
-		if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then
-			if frame:GetBottom() < 0 then
-				local point, parent, relativePoint, x, y = frame:GetPoint(1)
-				local change = GetScreenHeight() - frame:GetTop()
-				local otherChange = -frame:GetBottom()
-				if otherChange < change then
-					change = otherChange
-				end
-				frame:SetPoint(point, parent, relativePoint, x, y + change)
-			elseif frame:GetTop() > GetScreenHeight() then
-				local point, parent, relativePoint, x, y = frame:GetPoint(1)
-				local change = GetScreenHeight() - frame:GetTop()
-				local otherChange = -frame:GetBottom()
-				if otherChange < change then
-					change = otherChange
-				end
-				frame:SetPoint(point, parent, relativePoint, x, y + change)
-			end
-		end
-	end
-	CheckDualMonitor(self, frame)
-	frame:SetClampedToScreen(true)
-	frame:SetClampedToScreen(false)
-	StartCounting(self, level)
-end
-
-function Dewdrop:IsRegistered(parent)
-	self:argCheck(parent, 2, "table", "string")
-	return not not self.registry[parent]
-end
-
-function Dewdrop:Register(parent, ...)
-	self:argCheck(parent, 2, "table", "string")
-	if self.registry[parent] then
-		self:Unregister(parent)
-	end
-	local info = new(...)
-	if type(info.children) == "table" then
-		local err, position = validateOptions(info.children)
-
-		if err then
-			if position then
-				Dewdrop:error(position .. ": " .. err)
-			else
-				Dewdrop:error(err)
-			end
-		end
-	end
-	self.registry[parent] = info
-	if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then
-		if parent:HasScript("OnMouseUp") then
-			local script = parent:GetScript("OnMouseUp")
-			parent:SetScript("OnMouseUp", function(this, ...)
-				if script then
-					script(this, ...)
-				end
-				if arg1 == "RightButton" and self.registry[parent] then
-					if self:IsOpen(parent) then
-						self:Close()
-					else
-						self:Open(parent)
-					end
-				end
-			end)
-		end
-		if parent:HasScript("OnMouseDown") then
-			local script = parent:GetScript("OnMouseDown")
-			parent:SetScript("OnMouseDown", function(this, ...)
-				if script then
-					script(this, ...)
-				end
-				if self.registry[parent] then
-					self:Close()
-				end
-			end)
-		end
-	end
-	self.onceRegistered[parent] = true
-end
-
-function Dewdrop:Unregister(parent)
-	self:argCheck(parent, 2, "table", "string")
-	self.registry[parent] = nil
-end
-
-function Dewdrop:Open(parent, ...)
-	self:argCheck(parent, 2, "table", "string")
-	local info
-	local k1 = ...
-	if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then
-		info = tmp(select(2, ...))
-		for k,v in pairs(self.registry[k1]) do
-			if info[k] == nil then
-				info[k] = v
-			end
-		end
-	else
-		info = tmp(...)
-		if self.registry[parent] then
-			for k,v in pairs(self.registry[parent]) do
-				if info[k] == nil then
-					info[k] = v
-				end
-			end
-		end
-	end
-	local point = info.point
-	local relativePoint = info.relativePoint
-	local cursorX = info.cursorX
-	local cursorY = info.cursorY
-	if type(point) == "function" then
-		local b
-		point, b = point(parent)
-		if b then
-			relativePoint = b
-		end
-	end
-	if type(relativePoint) == "function" then
-		relativePoint = relativePoint(parent)
-	end
-	Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY)
-end
-
-function Clear(self, level)
-	if level then
-		if level.buttons then
-			for i = #level.buttons, 1, -1 do
-				ReleaseButton(self, level, i)
-			end
-		end
-	end
-end
-
-function Dewdrop:Close(level)
-	if DropDownList1:IsShown() then
-		DropDownList1:Hide()
-	end
-	if DewdropLib then
-		local d = DewdropLib:GetInstance('1.0')
-		local ret, val = pcall(d, IsOpen, d)
-		if ret and val then
-			DewdropLib:GetInstance('1.0'):Close()
-		end
-	end
-	self:argCheck(level, 2, "number", "nil")
-	if not level then
-		level = 1
-	end
-	if level == 1 and levels[level] then
-		levels[level].parented = false
-	end
-	if level > 1 and levels[level-1].buttons then
-		local buttons = levels[level-1].buttons
-		for _,button in ipairs(buttons) do
---			button.arrow:SetWidth(16)
---			button.arrow:SetHeight(16)
-			button.selected = nil
-			button.highlight:Hide()
---			button.arrow:SetVertexColor(1, 1, 1)
-		end
-	end
-	if sliderFrame and sliderFrame.level >= level then
-		sliderFrame:Hide()
-	end
-	if editBoxFrame and editBoxFrame.level >= level then
-		editBoxFrame:Hide()
-	end
-	for i = level, #levels do
-		Clear(self, levels[level])
-		levels[i]:Hide()
-		levels[i]:ClearAllPoints()
-		levels[i]:SetPoint("CENTER", UIParent, "CENTER")
-		levels[i].value = nil
-	end
-end
-
-function Dewdrop:AddSeparator(level)
-	level = levels[level or currentLevel]
-	if not level or not level.buttons then return; end
-
-	local prevbutton = level.buttons[#level.buttons]
-	if not prevbutton then return; end
-
-	if prevbutton.disabled and prevbutton.text:GetText() == "" then
-		return
-	end
-	self:AddLine("text", "", "disabled", true)
-end
-
-function Dewdrop:AddLine(...)
-	local info = tmp(...)
-	local level = info.level or currentLevel
-	info.level = nil
-	local button = AcquireButton(self, level)
-	if not next(info) then
-		info.disabled = true
-	end
-	button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure)
-	button.isTitle = info.isTitle
-	button.notClickable = info.notClickable
-	if button.isTitle then
-		button.text:SetFontObject(GameFontNormalSmall)
-	elseif button.notClickable then
-		button.text:SetFontObject(GameFontHighlightSmall)
-	elseif button.disabled then
-		button.text:SetFontObject(GameFontDisableSmall)
-	else
-		button.text:SetFontObject(GameFontHighlightSmall)
-	end
-	if info.disabled then
-		button.arrow:SetDesaturated(true)
-		button.check:SetDesaturated(true)
-	else
-		button.arrow:SetDesaturated(false)
-		button.check:SetDesaturated(false)
-	end
-	if info.textR and info.textG and info.textB then
-		button.textR = info.textR
-		button.textG = info.textG
-		button.textB = info.textB
-		button.text:SetTextColor(button.textR, button.textG, button.textB)
-	else
-		button.text:SetTextColor(button.text:GetFontObject():GetTextColor())
-	end
-	button.notCheckable = info.notCheckable
-	button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0)
-	button.checked = not info.notCheckable and info.checked
-	button.mouseoverUnderline = info.mouseoverUnderline
-	button.isRadio = not info.notCheckable and info.isRadio
-	if info.isRadio then
-		button.check:Show()
-		button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
-		if button.checked then
-			button.check:SetTexCoord(0.25, 0.5, 0, 1)
-			button.check:SetVertexColor(1, 1, 1, 1)
-		else
-			button.check:SetTexCoord(0, 0.25, 0, 1)
-			button.check:SetVertexColor(1, 1, 1, 0.5)
-		end
-		button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
-		button.check:SetWidth(16)
-		button.check:SetHeight(16)
-	elseif info.icon then
-		button.check:Show()
-		button.check:SetTexture(info.icon)
-		if info.iconWidth and info.iconHeight then
-			button.check:SetWidth(info.iconWidth)
-			button.check:SetHeight(info.iconHeight)
-		else
-			button.check:SetWidth(16)
-			button.check:SetHeight(16)
-		end
-		if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then
-			button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom)
-		elseif info.icon:find("^Interface\\Icons\\") then
-			button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
-		else
-			button.check:SetTexCoord(0, 1, 0, 1)
-		end
-		button.check:SetVertexColor(1, 1, 1, 1)
-	else
-		if button.checked then
-			if info.checkIcon then
-				button.check:SetWidth(16)
-				button.check:SetHeight(16)
-				button.check:SetTexture(info.checkIcon)
-				if info.checkIcon:find("^Interface\\Icons\\") then
-					button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
-				else
-					button.check:SetTexCoord(0, 1, 0, 1)
-				end
-			else
-				button.check:SetWidth(24)
-				button.check:SetHeight(24)
-				button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
-				button.check:SetTexCoord(0, 1, 0, 1)
-			end
-			button.check:SetVertexColor(1, 1, 1, 1)
-		else
-			button.check:SetVertexColor(1, 1, 1, 0)
-		end
-	end
-	if not button.disabled then
-		button.func = info.func
-		button.secure = info.secure
-	end
-	button.hasColorSwatch = info.hasColorSwatch
-	if button.hasColorSwatch then
-		button.colorSwatch:Show()
-		button.colorSwatch.texture:Show()
-		button.r = info.r or 1
-		button.g = info.g or 1
-		button.b = info.b or 1
-		button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b)
-		button.checked = false
-		button.func = nil
-		button.colorFunc = info.colorFunc
-		local i = 1
-		while true do
-			local k = "colorArg" .. i
-			local x = info[k]
-			if x == nil then
-				break
-			end
-			button[k] = x
-			i = i + 1
-		end
-		button.hasOpacity = info.hasOpacity
-		button.opacity = info.opacity or 1
-	else
-		button.colorSwatch:Hide()
-		button.colorSwatch.texture:Hide()
-	end
-	button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow
-	if button.hasArrow then
-		button.arrow:SetAlpha(1)
-		if info.hasSlider then
-			button.hasSlider = true
-			button.sliderMin = info.sliderMin or 0
-			button.sliderMax = info.sliderMax or 1
-			button.sliderStep = info.sliderStep or 0
-			button.sliderBigStep = info.sliderBigStep or button.sliderStep
-			if button.sliderBigStep < button.sliderStep then
-				button.sliderBigStep = button.sliderStep
-			end
-			button.sliderIsPercent = info.sliderIsPercent and true or false
-			button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin
-			button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax
-			button.sliderFunc = info.sliderFunc
-			button.sliderValue = info.sliderValue
-			button.fromAceOptions = info.fromAceOptions
-			local i = 1
-			while true do
-				local k = "sliderArg" .. i
-				local x = info[k]
-				if x == nil then
-					break
-				end
-				button[k] = x
-				i = i + 1
-			end
-		elseif info.hasEditBox then
-			button.hasEditBox = true
-			button.editBoxText = info.editBoxText or ""
-			button.editBoxFunc = info.editBoxFunc
-			local i = 1
-			while true do
-				local k = "editBoxArg" .. i
-				local x = info[k]
-				if x == nil then
-					break
-				end
-				button[k] = x
-				i = i + 1
-			end
-			button.editBoxChangeFunc = info.editBoxChangeFunc
-			local i = 1
-			while true do
-				local k = "editBoxChangeArg" .. i
-				local x = info[k]
-				if x == nil then
-					break
-				end
-				button[k] = x
-				i = i + 1
-			end
-			button.editBoxValidateFunc = info.editBoxValidateFunc
-			local i = 1
-			while true do
-				local k = "editBoxValidateArg" .. i
-				local x = info[k]
-				if x == nil then
-					break
-				end
-				button[k] = x
-				i = i + 1
-			end
-			button.editBoxIsKeybinding = info.editBoxIsKeybinding
-			button.editBoxKeybindingOnly = info.editBoxKeybindingOnly
-			button.editBoxKeybindingExcept = info.editBoxKeybindingExcept
-		else
-			button.value = info.value
-			local l = levels[level+1]
-			if l and info.value == l.value then
---				button.arrow:SetWidth(24)
---				button.arrow:SetHeight(24)
-				button.selected = true
-				button.highlight:Show()
-			end
-		end
-	else
-		button.arrow:SetAlpha(0)
-	end
-	local i = 1
-	while true do
-		local k = "arg" .. i
-		local x = info[k]
-		if x == nil then
-			break
-		end
-		button[k] = x
-		i = i + 1
-	end
-	button.closeWhenClicked = info.closeWhenClicked
-	button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10
-	local font,_ = button.text:GetFont()
-	button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight)
-	button:SetHeight(button.textHeight + 6)
-	button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT")
-	button.text:SetJustifyH(info.justifyH or "LEFT")
-	button.text:SetText(info.text)
-	button.tooltipTitle = info.tooltipTitle
-	button.tooltipText = info.tooltipText
-	button.tooltipFunc = info.tooltipFunc
-	local i = 1
-	while true do
-		local k = "tooltipArg" .. i
-		local x = info[k]
-		if x == nil then
-			break
-		end
-		button[k] = x
-		i = i + 1
-	end
-	if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then
-		button.tooltipTitle = info.text
-	end
-	if type(button.func) == "string" then
-		if type(button.arg1) ~= "table" then
-			self:error("Cannot call method %q on a non-table", button.func)
-		end
-		if type(button.arg1[button.func]) ~= "function" then
-			self:error("Method %q nonexistant.", button.func)
-		end
-	end
-end
-
-function Dewdrop:InjectAceOptionsTable(handler, options)
-	self:argCheck(handler, 2, "table")
-	self:argCheck(options, 3, "table")
-	if tostring(options.type):lower() ~= "group" then
-		self:error('Cannot inject into options table argument #3 if its type is not "group"')
-	end
-	if options.handler ~= nil and options.handler ~= handler then
-		self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2")
-	end
-	options.handler = handler
-	local class = handler.class
-	if not AceLibrary:HasInstance("AceOO-2.0") or not class then
-		if Rock then
-			-- possible Rock object
-			for mixin in Rock:IterateObjectMixins(handler) do
-				if type(mixin.GetAceOptionsDataTable) == "function" then
-					local t = mixin:GetAceOptionsDataTable(handler)
-					for k,v in pairs(t) do
-						if type(options.args) ~= "table" then
-							options.args = {}
-						end
-						if options.args[k] == nil then
-							options.args[k] = v
-						end
-					end
-				end
-			end
-		end
-	else
-		-- Ace2 object
-		while class and class ~= AceLibrary("AceOO-2.0").Class do
-			if type(class.GetAceOptionsDataTable) == "function" then
-				local t = class:GetAceOptionsDataTable(handler)
-				for k,v in pairs(t) do
-					if type(options.args) ~= "table" then
-						options.args = {}
-					end
-					if options.args[k] == nil then
-						options.args[k] = v
-					end
-				end
-			end
-			local mixins = class.mixins
-			if mixins then
-				for mixin in pairs(mixins) do
-					if type(mixin.GetAceOptionsDataTable) == "function" then
-						local t = mixin:GetAceOptionsDataTable(handler)
-						for k,v in pairs(t) do
-							if type(options.args) ~= "table" then
-								options.args = {}
-							end
-							if options.args[k] == nil then
-								options.args[k] = v
-							end
-						end
-					end
-				end
-			end
-			class = class.super
-		end
-	end
-	return options
-end
-
-function Dewdrop:OnTooltipHide()
-	if lastSetFont then
-		if lastSetFont == normalFont then
-			lastSetFont = nil
-			return
-		end
-		fillRegionTmp(GameTooltip:GetRegions())
-		for i,v in ipairs(regionTmp) do
-			if v.GetFont then
-				local font,size,outline = v:GetFont()
-				if font == lastSetFont then
-					v:SetFont(normalFont, size, outline)
-				end
-			end
-			regionTmp[i] = nil
-		end
-		lastSetFont = nil
-	end
-end
-
-local function activate(self, oldLib, oldDeactivate)
-	Dewdrop = self
-	if oldLib and oldLib.registry then
-		self.registry = oldLib.registry
-		self.onceRegistered = oldLib.onceRegistered
-	else
-		self.registry = {}
-		self.onceRegistered = {}
-
-		local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown")
-		local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp")
-		local oldX, oldY, clickTime
-		WorldFrame:SetScript("OnMouseDown", function(this, ...)
-			oldX,oldY = GetCursorPosition()
-			clickTime = GetTime()
-			if WorldFrame_OnMouseDown then
-				WorldFrame_OnMouseDown(this, ...)
-			end
-		end)
-
-		WorldFrame:SetScript("OnMouseUp", function(this, ...)
-			local x,y = GetCursorPosition()
-			if not oldX or not oldY or not x or not y or not clickTime then
-				self:Close()
-				if WorldFrame_OnMouseUp then
-					WorldFrame_OnMouseUp(this, ...)
-				end
-				return
-			end
-			local d = math.abs(x - oldX) + math.abs(y - oldY)
-			if d <= 5 and GetTime() - clickTime < 0.5 then
-				self:Close()
-			end
-			if WorldFrame_OnMouseUp then
-				WorldFrame_OnMouseUp(this, ...)
-			end
-		end)
-
-		hooksecurefunc(DropDownList1, "Show", function()
-			if levels[1] and levels[1]:IsVisible() then
-				self:Close()
-			end
-		end)
-
-		hooksecurefunc("HideDropDownMenu", function()
-			if levels[1] and levels[1]:IsVisible() then
-				self:Close()
-			end
-		end)
-
-		hooksecurefunc("CloseDropDownMenus", function()
-			if levels[1] and levels[1]:IsVisible() then
-				local stack = debugstack()
-				if not stack:find("`TargetFrame_OnHide'") then
-					self:Close()
-				end
-			end
-		end)
-	end
-	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
-	self.frame:UnregisterAllEvents()
-	self.frame:RegisterEvent("PLAYER_REGEN_ENABLED")
-	self.frame:RegisterEvent("PLAYER_REGEN_DISABLED")
-	self.frame:Hide()
-	self.frame:SetScript("OnEvent", function(this, event)
-		this:Show()
-		if event=="PLAYER_REGEN_ENABLED" then			-- track combat state for secure frame operations
-			self.combat = false
-		elseif event=="PLAYER_REGEN_DISABLED" then
-			self.combat = true
-		end
-	end)
-	self.frame:SetScript("OnUpdate", function(this)
-		this:Hide()
-		self:Refresh(1)
-	end)
-	self.hookedTooltip = true
-	if not oldLib or not oldLib.hookedTooltip then
-		local OnTooltipHide = GameTooltip:GetScript("OnHide")
-		GameTooltip:SetScript("OnHide", function(this, ...)
-			if OnTooltipHide then
-				OnTooltipHide(this, ...)
-			end
-			if type(self.OnTooltipHide) == "function" then
-				self:OnTooltipHide()
-			end
-		end)
-	end
-	levels = {}
-	buttons = {}
-
-	if oldDeactivate then
-		oldDeactivate(oldLib)
-	end
-end
-
-local function external(lib, major, instance)
-	if major == "SharedMedia-1.0" then
-		SharedMedia = instance
-	end
-end
-
-AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/LibStub/LibStub.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,30 @@
+-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
+-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+	LibStub = LibStub or {libs = {}, minors = {} }
+	_G[LIBSTUB_MAJOR] = LibStub
+	LibStub.minor = LIBSTUB_MINOR
+	
+	function LibStub:NewLibrary(major, minor)
+		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+		minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+		
+		local oldminor = self.minors[major]
+		if oldminor and oldminor >= minor then return nil end
+		self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+		return self.libs[major], oldminor
+	end
+	
+	function LibStub:GetLibrary(major, silent)
+		if not self.libs[major] and not silent then
+			error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+		end
+		return self.libs[major], self.minors[major]
+	end
+	
+	function LibStub:IterateLibraries() return pairs(self.libs) end
+	setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end
--- a/lib/embeds.xml	Tue Mar 11 21:39:34 2008 +0000
+++ b/lib/embeds.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -2,14 +2,11 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
 
-  <Script file="AceLibrary\AceLibrary.lua"/>
-  <Script file="AceOO-2.0\AceOO-2.0.lua"/>
-  <Script file="AceAddon-2.0\AceAddon-2.0.lua"/>
-  <Script file="AceConsole-2.0\AceConsole-2.0.lua"/>
-  <Script file="AceDB-2.0\AceDB-2.0.lua"/>
-  <Script file="AceEvent-2.0\AceEvent-2.0.lua"/>
-  <Script file="AceLocale-2.2\AceLocale-2.2.lua"/>
-  <Script file="AceModuleCore-2.0\AceModuleCore-2.0.lua"/>
-  <Script file="Dewdrop-2.0\Dewdrop-2.0.lua"/>
+  <Script  file="LibStub\LibStub.lua"/>
+  <Include file="CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
+  <Include file="AceAddon-3.0\AceAddon-3.0.xml"/>
+  <Include file="AceLocale-3.0\AceLocale-3.0.xml"/>
+  <Include file="AceDB-3.0\AceDB-3.0.xml"/>
+  <Include file="AceEvent-3.0\AceEvent-3.0.xml"/>
 
 </Ui>
--- a/locale/enUS.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/locale/enUS.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -1,65 +1,61 @@
-AceLibrary("AceLocale-2.2"):new("ReAction"):RegisterTranslations( "enUS", 
-function() 
-return
-{
--- ReAction
-["ReAction"] = true,
-["Toggle ReAction Bar Lock"] = true,
-["ReAction Keybinding Mode"] = true,
+local L = LibStub("AceLocale-3.0"):NewLocale("ReAction","enUS",true)
+if L then
 
--- ReAction_Bar
-["Bar "] = true,
-["Delete Bar"] = true,
-["Remove the bar from the current profile"] = true,
-["Rename Bar"] = true,
-["Set a name for the bar"] = true,
-["ReAction: name already in use"] = true,
+-- bindings.lua
+L["ReAction"] = true
+L["Toggle ReAction Bar Lock"] = true
+L["ReAction Keybinding Mode"] = true
+
+-- ReAction.lua
+L["Bar "] = true
+L["ReAction: name already in use"] = true
 
 -- modules/ReAction_HideBlizzard
-["Hide Default Action Bars"] = true,
-["Hide the default main bar and extra action bars"] = true,
+L["Hide Default Action Bars"] = true
+L["Hide the default main bar and extra action bars"] = true
 
 -- modules/ReAction_Action
-["New Action Bar"] = true,
-["Create a new bar of standard action buttons"] = true,
+L["New Action Bar"] = true
+L["Create a new bar of standard action buttons"] = true
 
 -- modules/ReAction_ConfigUI
+L["Delete Bar"] = true
+L["Remove the bar from the current profile"] = true
+L["Rename Bar"] = true
+L["Set a name for the bar"] = true
   -- console commands
-["/reaction"] = true,
-["/rxn"] = true,
-["unlock"] = true,
-["config"] = true,
+L["/reaction"] = true
+L["/rxn"] = true
+L["unlock"] = true
+L["config"] = true
   -- messages
-["ReAction config mode disabled during combat."] = true,
+L["ReAction config mode disabled during combat."] = true
   -- tooltips
-["Drag to add/remove buttons"] = true,
-["Drag to resize buttons"] = true,
-["Right-click-drag"] = true,
-["to change spacing"] = true,
-["Size:"] = true,
-["Spacing:"] = true,
-["Drag to move"] = true,
-["Shift-drag for sticky mode"] = true,
-["Right-click for options"] = true,
+L["Drag to add/remove buttons"] = true
+L["Drag to resize buttons"] = true
+L["Right-click-drag"] = true
+L["to change spacing"] = true
+L["Size:"] = true
+L["Spacing:"] = true
+L["Drag to move"] = true
+L["Shift-drag for sticky mode"] = true
+L["Right-click for options"] = true
   -- global options
-["Unlock Bars"] = true,
-["Unlock bars for dragging and resizing with the mouse"] = true,
-["Configure..."] = true,
-["Open the configuration dialogue"] = true,
+L["Unlock Bars"] = true
+L["Unlock bars for dragging and resizing with the mouse"] = true
+L["Configure..."] = true
+L["Open the configuration dialogue"] = true
   -- bar menu options
-["Open the configuration dialogue for this bar"] = true,
+L["Open the configuration dialogue for this bar"] = true
   -- waterfall options
-["Global Settings"] = true,
-["Global configuration settings"] = true,
-["Module Settings"] = true,
-["Configuration settings for each module"] = true,
-["Bars"] = true,
-["Configuration settings for bars"] = true,
+L["Global Settings"] = true
+L["Global configuration settings"] = true
+L["Module Settings"] = true
+L["Configuration settings for each module"] = true
+L["Bars"] = true
+L["Configuration settings for bars"] = true
 
 -- modules/ReAction_State
-["Dynamic Behavior"] = true,
+L["Dynamic Behavior"] = true
 
-
-} 
 end
-)
--- a/modules/FuBar_ReActionFu/FuBar_ReActionFu.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/FuBar_ReActionFu/FuBar_ReActionFu.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -12,9 +12,9 @@
 
 -- module declaration
 local moduleID = "ReActionFu"
-local module = ReAction:NewModule( moduleID,
-  "FuBarPlugin-2.0"
-)
+local rmodule = ReAction:NewModule( moduleID )
+local module  = AceLibrary("AceAddon-2.0"):new("FuBarPlugin-2.0")
+rmodule.fubar = module
 
 module.hasIcon = "Interface\\Icons\\INV_Qiraj_JewelEncased"
 module.hasNoColor = true
@@ -25,39 +25,38 @@
 module.defaultPosition = "LEFT"
 module.defaultMinimapPosition = 240 -- degrees
 
-function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
+function rmodule:OnInitialize()
+  self.db = ReAction.db:RegisterNamespace(moduleID,
     {
-      requireFuBar = false
+      profile = {
+        requireFuBar = false
+      }
     }
   )
+  self.db.RegisterCallback(self,"OnProfileChanged")
 
   if self.db.profile.requireFuBar == true then
     self:Hide()
   end
-end
-
-function module:OnEnable()
 
 end
 
-function module:OnDisable()
+function rmodule:OnEnable()
 
 end
 
-function module:OnProfileEnable()
+function rmodule:OnDisable()
+
+end
+
+function rmodule:OnProfileChanged()
   if self.db.profile.requireFuBar == true then
-    self:Hide()
+    module:Hide()
   else
     self:Show()
   end
 end
 
-function module:OnProfileDisable()
-
-end
-
 function module:OnTooltipUpdate()
 
 end
@@ -77,9 +76,11 @@
     Dewdrop:InjectAceOptionsTable(ReAction,opts)
     self.aceOptionsTable = opts
   end
-  for _, m in ReAction:IterateModulesWithMethod("GetGlobalOptions") do
-    for k,v in pairs(m:GetGlobalOptions()) do
-      self.aceOptionsTable.args[k] = v
+  for _, m in ReAction:IterateModules() do
+    if m and type(m.GetGlobalOptions) == "function" then
+      for k,v in pairs(m:GetGlobalOptions()) do
+        self.aceOptionsTable.args[k] = v
+      end
     end
   end
   Dewdrop:FeedAceOptionsTable(self.aceOptionsTable)
--- a/modules/FuBar_ReActionFu/FuBar_ReActionFu.xml	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/FuBar_ReActionFu/FuBar_ReActionFu.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -2,8 +2,14 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
 
+  <Script file="lib\AceLibrary\AceLibrary.lua"/>
+  <Script file="lib\AceOO-2.0\AceOO-2.0.lua"/>
+  <Script file="lib\AceEvent-2.0\AceEvent-2.0.lua"/>
+  <Script file="lib\AceAddon-2.0\AceAddon-2.0.lua"/>
   <Script file="lib\FuBarPlugin-2.0\FuBarPlugin-2.0.lua"/>
   <Script file="lib\Tablet-2.0\Tablet-2.0.lua"/>
+  <Script file="lib\Dewdrop-2.0\Dewdrop-2.0.lua"/>
+
   <Script file="FuBar_ReActionFu.lua"/>
 
 </Ui>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceAddon-2.0/AceAddon-2.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,1394 @@
+--[[
+Name: AceAddon-2.0
+Revision: $Rev: 46764 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Ace 1.x by Turan (turan@gryphon.com)
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/wiki/AceAddon-2.0
+SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceAddon-2.0
+Description: Base for all Ace addons to inherit from.
+Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0
+License: LGPL v2.1
+]]
+
+local MAJOR_VERSION = "AceAddon-2.0"
+local MINOR_VERSION = "$Revision: 46764 $"
+
+-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
+
+local function safecall(func,...)
+	local success, err = pcall(func,...)
+	if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
+end
+-- Localization
+local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, CREDITS, WEBSITE, CATEGORIES, ABOUT, LICENSE, PRINT_ADDON_INFO, DONATE, DONATE_DESC, HOWTO_DONATE_WINDOWS, HOWTO_DONATE_MAC
+if GetLocale() == "deDE" then
+	STANDBY = "|cffff5050(Standby)|r" -- capitalized
+
+	TITLE = "Titel"
+	NOTES = "Anmerkung"
+	VERSION = "Version"
+	AUTHOR = "Autor"
+	DATE = "Datum"
+	CATEGORY = "Kategorie"
+	EMAIL = "E-Mail"
+	WEBSITE = "Webseite"
+	CREDITS = "Credits" -- fix
+	LICENSE = "License" -- fix
+
+	ABOUT = "Über"
+	PRINT_ADDON_INFO = "Gibt Addondaten aus"
+	DONATE = "Donate" -- fix
+	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
+	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+
+	CATEGORIES = {
+		["Action Bars"] = "Aktionsleisten",
+		["Auction"] = "Auktion",
+		["Audio"] = "Audio",
+		["Battlegrounds/PvP"] = "Schlachtfeld/PvP",
+		["Buffs"] = "Stärkungszauber",
+		["Chat/Communication"] = "Chat/Kommunikation",
+		["Druid"] = "Druide",
+		["Hunter"] = "Jäger",
+		["Mage"] = "Magier",
+		["Paladin"] = "Paladin",
+		["Priest"] = "Priester",
+		["Rogue"] = "Schurke",
+		["Shaman"] = "Schamane",
+		["Warlock"] = "Hexenmeister",
+		["Warrior"] = "Krieger",
+		["Healer"] = "Heiler",
+		["Tank"] = "Tank",
+		["Caster"] = "Zauberer",
+		["Combat"] = "Kampf",
+		["Compilations"] = "Zusammenstellungen",
+		["Data Export"] = "Datenexport",
+		["Development Tools"] = "Entwicklungs Tools",
+		["Guild"] = "Gilde",
+		["Frame Modification"] = "Frame Veränderungen",
+		["Interface Enhancements"] = "Interface Verbesserungen",
+		["Inventory"] = "Inventar",
+		["Library"] = "Bibliotheken",
+		["Map"] = "Karte",
+		["Mail"] = "Post",
+		["Miscellaneous"] = "Diverses",
+		["Quest"] = "Quest",
+		["Raid"] = "Schlachtzug",
+		["Tradeskill"] = "Beruf",
+		["UnitFrame"] = "Einheiten-Fenster",
+	}
+elseif GetLocale() == "frFR" then
+	STANDBY = "|cffff5050(attente)|r"
+
+	TITLE = "Titre"
+	NOTES = "Notes"
+	VERSION = "Version"
+	AUTHOR = "Auteur"
+	DATE = "Date"
+	CATEGORY = "Catégorie"
+	EMAIL = "E-mail"
+	WEBSITE = "Site web"
+	CREDITS = "Credits" -- fix
+	LICENSE = "License" -- fix
+
+	ABOUT = "A propos"
+	PRINT_ADDON_INFO = "Afficher les informations sur l'addon"
+	DONATE = "Donate" -- fix
+	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
+	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+
+	CATEGORIES = {
+		["Action Bars"] = "Barres d'action",
+		["Auction"] = "Hôtel des ventes",
+		["Audio"] = "Audio",
+		["Battlegrounds/PvP"] = "Champs de bataille/JcJ",
+		["Buffs"] = "Buffs",
+		["Chat/Communication"] = "Chat/Communication",
+		["Druid"] = "Druide",
+		["Hunter"] = "Chasseur",
+		["Mage"] = "Mage",
+		["Paladin"] = "Paladin",
+		["Priest"] = "Prêtre",
+		["Rogue"] = "Voleur",
+		["Shaman"] = "Chaman",
+		["Warlock"] = "Démoniste",
+		["Warrior"] = "Guerrier",
+		["Healer"] = "Soigneur",
+		["Tank"] = "Tank",
+		["Caster"] = "Casteur",
+		["Combat"] = "Combat",
+		["Compilations"] = "Compilations",
+		["Data Export"] = "Exportation de données",
+		["Development Tools"] = "Outils de développement",
+		["Guild"] = "Guilde",
+		["Frame Modification"] = "Modification des fenêtres",
+		["Interface Enhancements"] = "Améliorations de l'interface",
+		["Inventory"] = "Inventaire",
+		["Library"] = "Bibliothèques",
+		["Map"] = "Carte",
+		["Mail"] = "Courrier",
+		["Miscellaneous"] = "Divers",
+		["Quest"] = "Quêtes",
+		["Raid"] = "Raid",
+		["Tradeskill"] = "Métiers",
+		["UnitFrame"] = "Fenêtres d'unité",
+	}
+elseif GetLocale() == "koKR" then
+	STANDBY = "|cffff5050(사용가능)|r"
+
+	TITLE = "제목"
+	NOTES = "노트"
+	VERSION = "버전"
+	AUTHOR = "저작자"
+	DATE = "날짜"
+	CATEGORY = "분류"
+	EMAIL = "전자 우편"
+	WEBSITE = "웹 사이트"
+	CREDITS = "공로자"
+	LICENSE = "라이센스"
+
+	ABOUT = "정보"
+	PRINT_ADDON_INFO = "애드온에 대한 정보를 출력합니다."
+	DONATE = "기부"
+	DONATE_DESC = "이 애드온의 저작자에게 기부를 합니다."
+	HOWTO_DONATE_WINDOWS = "Ctrl-A를 눌려 링크를 선택후, Ctrl-C로 복사합니다. Alt-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다."
+	HOWTO_DONATE_MAC = "Cmd-A를 눌려 링크를 선택후, Cmd-C로 복사합니다. Cmd-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다."
+
+	CATEGORIES = {
+		["Action Bars"] = "액션바",
+		["Auction"] = "경매",
+		["Audio"] = "음향",
+		["Battlegrounds/PvP"] = "전장/PvP",
+		["Buffs"] = "버프",
+		["Chat/Communication"] = "대화/의사소통",
+		["Druid"] = "드루이드",
+		["Hunter"] = "사냥꾼",
+		["Mage"] = "마법사",
+		["Paladin"] = "성기사",
+		["Priest"] = "사제",
+		["Rogue"] = "도적",
+		["Shaman"] = "주술사",
+		["Warlock"] = "흑마법사",
+		["Warrior"] = "전사",
+		["Healer"] = "힐러",
+		["Tank"] = "탱커",
+		["Caster"] = "캐스터",
+		["Combat"] = "전투",
+		["Compilations"] = "복합",
+		["Data Export"] = "자료 출력",
+		["Development Tools"] = "개발 도구",
+		["Guild"] = "길드",
+		["Frame Modification"] = "구조 변경",
+		["Interface Enhancements"] = "인터페이스 강화",
+		["Inventory"] = "인벤토리",
+		["Library"] = "라이브러리",
+		["Map"] = "지도",
+		["Mail"] = "우편",
+		["Miscellaneous"] = "기타",
+		["Quest"] = "퀘스트",
+		["Raid"] = "공격대",
+		["Tradeskill"] = "전문기술",
+		["UnitFrame"] = "유닛 프레임",
+	}
+elseif GetLocale() == "zhTW" then
+	STANDBY = "|cffff5050(待命)|r"
+
+	TITLE = "標題"
+	NOTES = "註記"
+	VERSION = "版本"
+	AUTHOR = "作者"
+	DATE = "日期"
+	CATEGORY = "類別"
+	EMAIL = "電子郵件"
+	WEBSITE = "網站"
+	CREDITS = "特別感謝"
+	LICENSE = "版權"
+
+	ABOUT = "關於"
+	PRINT_ADDON_INFO = "顯示插件資訊。"
+	DONATE = "捐贈"
+	DONATE_DESC = "捐贈金錢給插件作者。"
+	HOWTO_DONATE_WINDOWS = "請按Ctrl-A選擇網站連結,Ctrl-C複製網址,Alt-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。"
+	HOWTO_DONATE_MAC = "請按Cmd-A選擇網站連結,Cmd-C複製網址,Cmd-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。"
+
+	CATEGORIES = {
+		["Action Bars"] = "動作條",
+		["Auction"] = "拍賣",
+		["Audio"] = "音效",
+		["Battlegrounds/PvP"] = "戰場/PvP",
+		["Buffs"] = "增益",
+		["Chat/Communication"] = "聊天/通訊",
+		["Druid"] = "德魯伊",
+		["Hunter"] = "獵人",
+		["Mage"] = "法師",
+		["Paladin"] = "聖騎士",
+		["Priest"] = "牧師",
+		["Rogue"] = "盜賊",
+		["Shaman"] = "薩滿",
+		["Warlock"] = "術士",
+		["Warrior"] = "戰士",
+		["Healer"] = "治療者",
+		["Tank"] = "坦克",
+		["Caster"] = "施法者",
+		["Combat"] = "戰鬥",
+		["Compilations"] = "整合",
+		["Data Export"] = "資料匯出",
+		["Development Tools"] = "開發工具",
+		["Guild"] = "公會",
+		["Frame Modification"] = "框架修改",
+		["Interface Enhancements"] = "介面增強",
+		["Inventory"] = "庫存",
+		["Library"] = "程式庫",
+		["Map"] = "地圖",
+		["Mail"] = "郵件",
+		["Miscellaneous"] = "雜項",
+		["Quest"] = "任務",
+		["Raid"] = "團隊",
+		["Tradeskill"] = "交易技能",
+		["UnitFrame"] = "單位框架",
+	}
+elseif GetLocale() == "zhCN" then
+	STANDBY = "|cffff5050(暂挂)|r"
+
+	TITLE = "标题"
+	NOTES = "附注"
+	VERSION = "版本"
+	AUTHOR = "作者"
+	DATE = "日期"
+	CATEGORY = "分类"
+	EMAIL = "电子邮件"
+	WEBSITE = "网站"
+	CREDITS = "Credits" -- fix
+	LICENSE = "License" -- fix
+
+	ABOUT = "关于"
+	PRINT_ADDON_INFO = "印列出插件信息"
+	DONATE = "Donate" -- fix
+	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
+	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+
+	CATEGORIES = {
+		["Action Bars"] = "动作条",
+		["Auction"] = "拍卖",
+		["Audio"] = "音频",
+		["Battlegrounds/PvP"] = "战场/PvP",
+		["Buffs"] = "增益魔法",
+		["Chat/Communication"] = "聊天/交流",
+		["Druid"] = "德鲁伊",
+		["Hunter"] = "猎人",
+		["Mage"] = "法师",
+		["Paladin"] = "圣骑士",
+		["Priest"] = "牧师",
+		["Rogue"] = "盗贼",
+		["Shaman"] = "萨满祭司",
+		["Warlock"] = "术士",
+		["Warrior"] = "战士",
+--		["Healer"] = "治疗保障",
+--		["Tank"] = "近战控制",
+--		["Caster"] = "远程输出",
+		["Combat"] = "战斗",
+		["Compilations"] = "编译",
+		["Data Export"] = "数据导出",
+		["Development Tools"] = "开发工具",
+		["Guild"] = "公会",
+		["Frame Modification"] = "框架修改",
+		["Interface Enhancements"] = "界面增强",
+		["Inventory"] = "背包",
+		["Library"] = "库",
+		["Map"] = "地图",
+		["Mail"] = "邮件",
+		["Miscellaneous"] = "杂项",
+		["Quest"] = "任务",
+		["Raid"] = "团队",
+		["Tradeskill"] = "商业技能",
+		["UnitFrame"] = "头像框架",
+	}
+elseif GetLocale() == "esES" then
+	STANDBY = "|cffff5050(espera)|r"
+
+	TITLE = "Título"
+	NOTES = "Notas"
+	VERSION = "Versión"
+	AUTHOR = "Autor"
+	DATE = "Fecha"
+	CATEGORY = "Categoría"
+	EMAIL = "E-mail"
+	WEBSITE = "Web"
+	CREDITS = "Créditos"
+	LICENSE = "License" -- fix
+
+	ABOUT = "Acerca de"
+	PRINT_ADDON_INFO = "Muestra información acerca del accesorio."
+	DONATE = "Donate" -- fix
+	DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix
+	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix
+
+	CATEGORIES = {
+		["Action Bars"] = "Barras de Acción",
+		["Auction"] = "Subasta",
+		["Audio"] = "Audio",
+		["Battlegrounds/PvP"] = "Campos de Batalla/JcJ",
+		["Buffs"] = "Buffs",
+		["Chat/Communication"] = "Chat/Comunicación",
+		["Druid"] = "Druida",
+		["Hunter"] = "Cazador",
+		["Mage"] = "Mago",
+		["Paladin"] = "Paladín",
+		["Priest"] = "Sacerdote",
+		["Rogue"] = "Pícaro",
+		["Shaman"] = "Chamán",
+		["Warlock"] = "Brujo",
+		["Warrior"] = "Guerrero",
+		["Healer"] = "Sanador",
+		["Tank"] = "Tanque",
+		["Caster"] = "Conjurador",
+		["Combat"] = "Combate",
+		["Compilations"] = "Compilaciones",
+		["Data Export"] = "Exportar Datos",
+		["Development Tools"] = "Herramientas de Desarrollo",
+		["Guild"] = "Hermandad",
+		["Frame Modification"] = "Modificación de Marcos",
+		["Interface Enhancements"] = "Mejoras de la Interfaz",
+		["Inventory"] = "Inventario",
+		["Library"] = "Biblioteca",
+		["Map"] = "Mapa",
+		["Mail"] = "Correo",
+		["Miscellaneous"] = "Misceláneo",
+		["Quest"] = "Misión",
+		["Raid"] = "Banda",
+		["Tradeskill"] = "Habilidad de Comercio",
+		["UnitFrame"] = "Marco de Unidades",
+	}
+else -- enUS
+	STANDBY = "|cffff5050(standby)|r"
+
+	TITLE = "Title"
+	NOTES = "Notes"
+	VERSION = "Version"
+	AUTHOR = "Author"
+	DATE = "Date"
+	CATEGORY = "Category"
+	EMAIL = "E-mail"
+	WEBSITE = "Website"
+	CREDITS = "Credits"
+	LICENSE = "License"
+
+	ABOUT = "About"
+	PRINT_ADDON_INFO = "Show information about the addon."
+	DONATE = "Donate"
+	DONATE_DESC = "Give a much-needed donation to the author of this addon."
+	HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar."
+	HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar."
+
+	CATEGORIES = {
+		["Action Bars"] = "Action Bars",
+		["Auction"] = "Auction",
+		["Audio"] = "Audio",
+		["Battlegrounds/PvP"] = "Battlegrounds/PvP",
+		["Buffs"] = "Buffs",
+		["Chat/Communication"] = "Chat/Communication",
+		["Druid"] = "Druid",
+		["Hunter"] = "Hunter",
+		["Mage"] = "Mage",
+		["Paladin"] = "Paladin",
+		["Priest"] = "Priest",
+		["Rogue"] = "Rogue",
+		["Shaman"] = "Shaman",
+		["Warlock"] = "Warlock",
+		["Warrior"] = "Warrior",
+		["Healer"] = "Healer",
+		["Tank"] = "Tank",
+		["Caster"] = "Caster",
+		["Combat"] = "Combat",
+		["Compilations"] = "Compilations",
+		["Data Export"] = "Data Export",
+		["Development Tools"] = "Development Tools",
+		["Guild"] = "Guild",
+		["Frame Modification"] = "Frame Modification",
+		["Interface Enhancements"] = "Interface Enhancements",
+		["Inventory"] = "Inventory",
+		["Library"] = "Library",
+		["Map"] = "Map",
+		["Mail"] = "Mail",
+		["Miscellaneous"] = "Miscellaneous",
+		["Quest"] = "Quest",
+		["Raid"] = "Raid",
+		["Tradeskill"] = "Tradeskill",
+		["UnitFrame"] = "UnitFrame",
+	}
+end
+
+setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive
+	local lowerKey = key:lower()
+	for k,v in pairs(CATEGORIES) do
+		if k:lower() == lowerKey then
+			return v
+		end
+	end
+end })
+
+-- Create the library object
+
+local AceOO = AceLibrary("AceOO-2.0")
+local AceAddon = AceOO.Class()
+local AceEvent
+local AceConsole
+local AceModuleCore
+
+function AceAddon:GetLocalizedCategory(name)
+	self:argCheck(name, 2, "string")
+	return CATEGORIES[name] or UNKNOWN
+end
+
+function AceAddon:ToString()
+	return "AceAddon"
+end
+
+local function print(text)
+	DEFAULT_CHAT_FRAME:AddMessage(text)
+end
+
+function AceAddon:ADDON_LOADED(name)
+	local unregister = true
+	local initAddon = {}
+	while #self.nextAddon > 0 do
+		local addon = table.remove(self.nextAddon, 1)
+		if addon.possibleNames[name] then
+			table.insert(initAddon, addon)
+		else
+			unregister = nil
+			table.insert(self.skipAddon, addon)
+		end
+	end
+	self.nextAddon, self.skipAddon = self.skipAddon, self.nextAddon
+	if unregister then
+		AceAddon:UnregisterEvent("ADDON_LOADED")
+	end
+	while #initAddon > 0 do
+		local addon = table.remove(initAddon, 1)
+		table.insert(self.addons, addon)
+		if not self.addons[name] then
+			self.addons[name] = addon
+		end
+		addon.possibleNames = nil
+		self:InitializeAddon(addon, name)
+	end
+end
+
+local function RegisterOnEnable(self)
+	if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK
+		AceAddon.playerLoginFired = true
+	end
+	if AceAddon.playerLoginFired then
+		AceAddon.addonsStarted[self] = true
+		if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then
+			AceAddon:ManualEnable(self)
+		end
+	else
+		if not AceAddon.addonsToOnEnable then
+			AceAddon.addonsToOnEnable = {}
+		end
+		table.insert(AceAddon.addonsToOnEnable, self)
+	end
+end
+
+function AceAddon:InitializeAddon(addon, name)
+	if addon.name == nil then
+		addon.name = name
+	end
+	if GetAddOnMetadata then
+		-- TOC checks
+		if addon.title == nil then
+			addon.title = GetAddOnMetadata(name, "Title")
+		end
+		if type(addon.title) == "string" then
+			local num = addon.title:find(" |cff7fff7f %-Ace2%-|r$")
+			if num then
+				addon.title = addon.title:sub(1, num - 1)
+			end
+			addon.title = addon.title:trim()
+		end
+		if addon.notes == nil then
+			addon.notes = GetAddOnMetadata(name, "Notes")
+		end
+		if type(addon.notes) == "string" then
+			addon.notes = addon.notes:trim()
+		end
+		if addon.version == nil then
+			addon.version = GetAddOnMetadata(name, "Version")
+		end
+		if type(addon.version) == "string" then
+			if addon.version:find("%$Revision: (%d+) %$") then
+				addon.version = addon.version:gsub("%$Revision: (%d+) %$", "%1")
+			elseif addon.version:find("%$Rev: (%d+) %$") then
+				addon.version = addon.version:gsub("%$Rev: (%d+) %$", "%1")
+			elseif addon.version:find("%$LastChangedRevision: (%d+) %$") then
+				addon.version = addon.version:gsub("%$LastChangedRevision: (%d+) %$", "%1")
+			end
+			addon.version = addon.version:trim()
+		end
+		if addon.author == nil then
+			addon.author = GetAddOnMetadata(name, "Author")
+		end
+		if type(addon.author) == "string" then
+			addon.author = addon.author:trim()
+		end
+		if addon.credits == nil then
+			addon.credits = GetAddOnMetadata(name, "X-Credits")
+		end
+		if type(addon.credits) == "string" then
+			addon.credits = addon.credits:trim()
+		end
+		if addon.donate == nil then
+			addon.donate = GetAddOnMetadata(name, "X-Donate")
+		end
+		if type(addon.donate) == "string" then
+			addon.donate = addon.donate:trim()
+		end
+		if addon.date == nil then
+			addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate")
+		end
+		if type(addon.date) == "string" then
+			if addon.date:find("%$Date: (.-) %$") then
+				addon.date = addon.date:gsub("%$Date: (.-) %$", "%1")
+			elseif addon.date:find("%$LastChangedDate: (.-) %$") then
+				addon.date = addon.date:gsub("%$LastChangedDate: (.-) %$", "%1")
+			end
+			addon.date = addon.date:trim()
+		end
+
+		if addon.category == nil then
+			addon.category = GetAddOnMetadata(name, "X-Category")
+		end
+		if type(addon.category) == "string" then
+			addon.category = addon.category:trim()
+		end
+		if addon.email == nil then
+			addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email")
+		end
+		if type(addon.email) == "string" then
+			addon.email = addon.email:trim()
+		end
+		if addon.license == nil then
+			addon.license = GetAddOnMetadata(name, "X-License")
+		end
+		if type(addon.license) == "string" then
+			addon.license = addon.license:trim()
+		end
+		if addon.website == nil then
+			addon.website = GetAddOnMetadata(name, "X-Website")
+		end
+		if type(addon.website) == "string" then
+			addon.website = addon.website:trim()
+		end
+	end
+	local current = addon.class
+	while true do
+		if current == AceOO.Class or not current then
+			break
+		end
+		if current.mixins then
+			for mixin in pairs(current.mixins) do
+				if type(mixin.OnEmbedInitialize) == "function" then
+					mixin:OnEmbedInitialize(addon, name)
+				end
+			end
+		end
+		current = current.super
+	end
+	local n = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0
+
+	if type(addon.OnInitialize) == "function" then
+		safecall(addon.OnInitialize, addon, name)
+	end
+	if AceEvent then
+		AceEvent:TriggerEvent("Ace2_AddonInitialized", addon)
+	end
+	RegisterOnEnable(addon)
+	local n2 = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0
+	if n2 - n > 1 then
+		local mine = table.remove(AceAddon.addonsToOnEnable)
+		table.insert(AceAddon.addonsToOnEnable, n+1, mine)
+	end
+end
+
+local aboutFrame
+local function createAboutFrame()
+	aboutFrame = CreateFrame("Frame", "AceAddon20AboutFrame", UIParent, "DialogBoxFrame")
+	aboutFrame:SetWidth(500)
+	aboutFrame:SetHeight(400)
+	aboutFrame:SetPoint("CENTER")
+	aboutFrame:SetBackdrop({
+		bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
+	    edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
+	    tile = true, tileSize = 16, edgeSize = 16,
+	    insets = { left = 5, right = 5, top = 5, bottom = 5 }
+	})
+	aboutFrame:SetBackdropColor(0,0,0,1)
+
+	local donateButton = CreateFrame("Button", "AceAddon20AboutFrameDonateButton", aboutFrame, "UIPanelButtonTemplate2")
+	aboutFrame.donateButton = donateButton
+	donateButton:SetPoint("BOTTOMRIGHT", -20, 20)
+	_G.AceAddon20AboutFrameDonateButtonText:SetText(DONATE)
+	donateButton:SetWidth(_G.AceAddon20AboutFrameDonateButtonText:GetWidth()+20)
+	donateButton:SetScript("OnClick", function()
+		aboutFrame.currentAddon:OpenDonationFrame()
+	end)
+
+	local text = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
+	aboutFrame.title = text
+	text:SetPoint("TOP", 0, -5)
+
+	aboutFrame:Hide()
+
+	aboutFrame.lefts = {}
+	aboutFrame.rights = {}
+	aboutFrame.textLefts = {}
+	aboutFrame.textRights = {}
+	function aboutFrame:Clear()
+		self.title:SetText("")
+		for i = 1, #self.lefts do
+			self.lefts[i] = nil
+			self.rights[i] = nil
+		end
+	end
+
+	function aboutFrame:AddLine(left, right)
+		aboutFrame.lefts[#aboutFrame.lefts+1] = left
+		aboutFrame.rights[#aboutFrame.rights+1] = right
+	end
+
+	local aboutFrame_Show = aboutFrame.Show
+	function aboutFrame:Show(...)
+		local maxLeftWidth = 0
+		local maxRightWidth = 0
+		local textHeight = 0
+		for i = 1, #self.lefts do
+			if not self.textLefts[i] then
+				local left = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+				self.textLefts[i] = left
+				local right = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+				self.textRights[i] = right
+				if i == 1 then
+					left:SetPoint("TOPRIGHT", aboutFrame, "TOPLEFT", 75, -35)
+				else
+					left:SetPoint("TOPRIGHT", self.textLefts[i-1], "BOTTOMRIGHT", 0, -5)
+				end
+				right:SetPoint("LEFT", left, "RIGHT", 5, 0)
+			end
+			self.textLefts[i]:SetText(self.lefts[i] .. ":")
+			self.textRights[i]:SetText(self.rights[i])
+			local leftWidth = self.textLefts[i]:GetWidth()
+			local rightWidth = self.textRights[i]:GetWidth()
+			textHeight = self.textLefts[i]:GetHeight()
+			if maxLeftWidth < leftWidth then
+				maxLeftWidth = leftWidth
+			end
+			if maxRightWidth < rightWidth then
+				maxRightWidth = rightWidth
+			end
+		end
+		for i = #self.lefts+1, #self.textLefts do
+			self.textLefts[i]:SetText('')
+			self.textRights[i]:SetText('')
+		end
+		aboutFrame:SetWidth(75 + maxRightWidth + 20)
+		aboutFrame:SetHeight(#self.lefts * (textHeight + 5) + 100)
+
+		aboutFrame_Show(self, ...)
+	end
+	aboutFrame:Hide()
+
+	createAboutFrame = nil
+end
+local donateFrame
+
+local function unobfuscateEmail(email)
+	return email:gsub(" AT ", "@"):gsub(" DOT ", ".")
+end
+
+local function isGoodVariable(var)
+	return type(var) == "string" or type(var) == "number"
+end
+function AceAddon.prototype:PrintAddonInfo()
+	if createAboutFrame then
+		createAboutFrame()
+	end
+	aboutFrame:Clear()
+	local x
+	if isGoodVariable(self.title) then
+		x = tostring(self.title)
+	elseif isGoodVariable(self.name) then
+		x = tostring(self.name)
+	else
+		x = "<" .. tostring(self.class) .. " instance>"
+	end
+	if type(self.IsActive) == "function" then
+		if not self:IsActive() then
+			x = x .. " " .. STANDBY
+		end
+	end
+	aboutFrame.title:SetText(x)
+
+	if isGoodVariable(self.version) then
+		aboutFrame:AddLine(VERSION, tostring(self.version))
+	end
+	if isGoodVariable(self.notes) then
+		aboutFrame:AddLine(NOTES, tostring(self.notes))
+	end
+	if isGoodVariable(self.author) then
+		aboutFrame:AddLine(AUTHOR, tostring(self.author))
+	end
+	if isGoodVariable(self.credits) then
+		aboutFrame:AddLine(CREDITS, tostring(self.credits))
+	end
+	if isGoodVariable(self.date) then
+		aboutFrame:AddLine(DATE, tostring(self.date))
+	end
+	if self.category then
+		local category = CATEGORIES[self.category]
+		if category then
+			aboutFrame:AddLine(CATEGORY, tostring(self.category))
+		end
+	end
+	if isGoodVariable(self.email) then
+		aboutFrame:AddLine(EMAIL, unobfuscateEmail(tostring(self.email)))
+	end
+	if isGoodVariable(self.website) then
+		aboutFrame:AddLine(WEBSITE, tostring(self.website))
+	end
+	if isGoodVariable(self.license) then
+		aboutFrame:AddLine(LICENSE, tostring(self.license))
+	end
+
+	if donateFrame and donateFrame:IsShown() then
+		donateFrame:Hide()
+	end
+
+	aboutFrame.currentAddon = self
+
+	aboutFrame:Show()
+
+	if self.donate then
+		aboutFrame.donateButton:Show()
+	else
+		aboutFrame.donateButton:Hide()
+	end
+end
+
+local function createDonateFrame()
+	donateFrame = CreateFrame("Frame", "AceAddon20Frame", UIParent, "DialogBoxFrame")
+
+	donateFrame:SetWidth(500)
+	donateFrame:SetHeight(200)
+	donateFrame:SetPoint("CENTER")
+	donateFrame:SetBackdrop({
+		bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
+		edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
+		tile = true, tileSize = 16, edgeSize = 16,
+		insets = { left = 5, right = 5, top = 5, bottom = 5 }
+	})
+	donateFrame:SetBackdropColor(0,0,0,1)
+
+	local text = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
+	text:SetPoint("TOP", 0, -5)
+	text:SetText(DONATE)
+
+	local howto = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+	howto:SetPoint("TOP", text, "BOTTOM", 0, -5)
+	howto:SetPoint("LEFT", 16, 0)
+	howto:SetPoint("RIGHT", -16, 0)
+	if not IsMacClient() then
+		-- Windows or Linux
+		howto:SetText(HOWTO_DONATE_WINDOWS)
+	else
+		howto:SetText(HOWTO_DONATE_MAC)
+	end
+
+	local scrollFrame = CreateFrame("ScrollFrame", "AceAddon20FrameScrollFrame", donateFrame, "UIPanelScrollFrameTemplate")
+	scrollFrame:SetToplevel(true)
+	scrollFrame:SetPoint("TOP", -10, -76)
+	scrollFrame:SetWidth(455)
+	scrollFrame:SetHeight(70)
+	howto:SetPoint("BOTTOM", scrollFrame, "TOP")
+
+	local editBox = CreateFrame("EditBox", nil, scrollFrame)
+	donateFrame.editBox = editBox
+	scrollFrame:SetScrollChild(editBox)
+	editBox:SetFontObject(ChatFontNormal)
+	editBox:SetMultiLine(true)
+	editBox:SetMaxLetters(99999)
+	editBox:SetWidth(450)
+	editBox:SetHeight(54)
+	editBox:SetPoint("BOTTOM", 5, 0)
+	editBox:SetJustifyH("LEFT")
+	editBox:SetJustifyV("TOP")
+	editBox:SetAutoFocus(false)
+	editBox:SetScript("OnTextChanged", function(this)
+		if this:GetText() ~= this.text then
+			this:SetText(this.text)
+		end
+	end)
+	editBox:SetScript("OnEscapePressed", function(this)
+		this:ClearFocus()
+	end)
+	createDonateFrame = nil
+end
+
+local function fix(char)
+	return ("%%%02x"):format(char:byte())
+end
+
+local function urlencode(text)
+	return text:gsub("[^0-9A-Za-z]", fix)
+end
+
+function AceAddon.prototype:OpenDonationFrame()
+	if createDonateFrame then
+		createDonateFrame()
+	end
+	local donate = self.donate
+	if type(donate) ~= "string" then
+		donate = "Wowace"
+	end
+	local style, data = (":"):split(donate, 2)
+	style = style:lower()
+	if style ~= "website" and style ~= "paypal" then
+		style = "wowace"
+	end
+	if style == "wowace" then
+		donateFrame.editBox.text = "http://www.wowace.com/wiki/Donations"
+	elseif style == "website" then
+		donateFrame.editBox.text = data
+	else -- PayPal
+		local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data))
+		local name
+		if type(self.title) == "string" then
+			name = self.title
+		elseif type(self.name) == "string" then
+			name = self.name
+		end
+		if name then
+			name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
+			text = text .. "&item_name=" .. urlencode(name)
+		end
+		donateFrame.editBox.text = text
+	end
+	donateFrame.editBox:SetText(donateFrame.editBox.text)
+
+	if aboutFrame and aboutFrame:IsShown() then
+		aboutFrame:Hide()
+	end
+
+	donateFrame:Show()
+
+	donateFrame.editBox:SetFocus()
+end
+
+local options
+function AceAddon:GetAceOptionsDataTable(target)
+	return {
+		about = {
+			name = ABOUT,
+			desc = PRINT_ADDON_INFO,
+			type = "execute",
+			func = "PrintAddonInfo",
+			order = -1,
+		},
+		donate = {
+			name = DONATE,
+			desc = DONATE_DESC,
+			type = "execute",
+			func = "OpenDonationFrame",
+			order = -1,
+			hidden = function()
+				return not target.donate
+			end
+		}
+	}
+end
+
+function AceAddon:PLAYER_LOGIN()
+	self.playerLoginFired = true
+	if self.addonsToOnEnable then
+		while #self.addonsToOnEnable > 0 do
+			local addon = table.remove(self.addonsToOnEnable, 1)
+			self.addonsStarted[addon] = true
+			if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then
+				AceAddon:ManualEnable(addon)
+			end
+		end
+		self.addonsToOnEnable = nil
+	end
+end
+
+function AceAddon.prototype:Inject(t)
+	AceAddon:argCheck(t, 2, "table")
+	for k,v in pairs(t) do
+		self[k] = v
+	end
+end
+
+function AceAddon.prototype:init()
+	if not AceEvent then
+		error(MAJOR_VERSION .. " requires AceEvent-2.0", 4)
+	end
+	AceAddon.super.prototype.init(self)
+
+	self.super = self.class.prototype
+
+	AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED")
+	local names = {}
+	for i = 1, GetNumAddOns() do
+		if IsAddOnLoaded(i) then names[GetAddOnInfo(i)] = true end
+	end
+	self.possibleNames = names
+	table.insert(AceAddon.nextAddon, self)
+end
+
+function AceAddon.prototype:ToString()
+	local x
+	if type(self.title) == "string" then
+		x = self.title
+	elseif type(self.name) == "string" then
+		x = self.name
+	else
+		x = "<" .. tostring(self.class) .. " instance>"
+	end
+	if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then
+		x = x .. " " .. STANDBY
+	end
+	return x
+end
+
+AceAddon.new = function(self, ...)
+	local class = AceAddon:pcall(AceOO.Classpool, self, ...)
+	return class:new()
+end
+
+function AceAddon:ManualEnable(addon)
+	AceAddon:argCheck(addon, 2, "table")
+	local first = nil
+	if AceOO.inherits(addon, "AceAddon-2.0") then
+		if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[addon] then
+			first = true
+			AceAddon.addonsEnabled[addon] = true
+		end
+	end
+	local current = addon.class
+	while current and current ~= AceOO.Class do
+		if current.mixins then
+			for mixin in pairs(current.mixins) do
+				if type(mixin.OnEmbedEnable) == "function" then
+					safecall(mixin.OnEmbedEnable, mixin, addon, first)
+				end
+			end
+		end
+		current = current.super
+	end
+	if type(addon.OnEnable) == "function" then
+		safecall(addon.OnEnable, addon, first)
+	end
+	if AceEvent then
+		AceEvent:TriggerEvent("Ace2_AddonEnabled", addon, first)
+	end
+end
+
+function AceAddon:ManualDisable(addon)
+	AceAddon:argCheck(addon, 2, "table")
+	local current = addon.class
+	while current and current ~= AceOO.Class do
+		if current.mixins then
+			for mixin in pairs(current.mixins) do
+				if type(mixin.OnEmbedDisable) == "function" then
+					safecall(mixin.OnEmbedDisable, mixin, addon)
+				end
+			end
+		end
+		current = current.super
+	end
+	if type(module.OnDisable) == "function" then
+		safecall(module.OnDisable, addon)
+	end
+	if AceEvent then
+		AceEvent:TriggerEvent("Ace2_AddonDisabled", addon)
+	end
+end
+
+local function external(self, major, instance)
+	if major == "AceEvent-2.0" then
+		AceEvent = instance
+
+		AceEvent:embed(self)
+
+		self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true)
+	elseif major == "AceConsole-2.0" then
+		AceConsole = instance
+
+		local slashCommands = { "/ace2" }
+		local _,_,_,enabled,loadable = GetAddOnInfo("Ace")
+		if not enabled or not loadable then
+			table.insert(slashCommands, "/ace")
+		end
+		local function listAddon(addon, depth)
+			if not depth then
+				depth = 0
+			end
+
+			local s = ("  "):rep(depth) .. " - " .. tostring(addon)
+			if rawget(addon, 'version') then
+				s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r"
+			end
+			if rawget(addon, 'slashCommand') then
+				s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r"
+			end
+			print(s)
+			if type(rawget(addon, 'modules')) == "table" then
+				local i = 0
+				for k,v in pairs(addon.modules) do
+					i = i + 1
+					if i == 6 then
+						print(("  "):rep(depth + 1) .. " - more...")
+						break
+					else
+						listAddon(v, depth + 1)
+					end
+				end
+			end
+		end
+		local function listNormalAddon(i)
+			local name,_,_,enabled,loadable = GetAddOnInfo(i)
+			if not loadable then
+				enabled = false
+			end
+			if self.addons[name] then
+				listAddon(self.addons[name])
+			else
+				local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name)
+				local version = GetAddOnMetadata(i, "Version")
+				if version then
+					if version:find("%$Revision: (%d+) %$") then
+						version = version:gsub("%$Revision: (%d+) %$", "%1")
+					elseif version:find("%$Rev: (%d+) %$") then
+						version = version:gsub("%$Rev: (%d+) %$", "%1")
+					elseif version:find("%$LastChangedRevision: (%d+) %$") then
+						version = version:gsub("%$LastChangedRevision: (%d+) %$", "%1")
+					end
+					s = s .. " - |cffffff7f" .. version .. "|r"
+				end
+				if not enabled then
+					s = s .. " |cffff0000(disabled)|r"
+				end
+				if IsAddOnLoadOnDemand(i) then
+					s = s .. " |cff00ff00[LoD]|r"
+				end
+				print(s)
+			end
+		end
+		local function mySort(alpha, bravo)
+			return tostring(alpha) < tostring(bravo)
+		end
+		AceConsole.RegisterChatCommand(self, slashCommands, {
+			desc = "AddOn development framework",
+			name = "Ace2",
+			type = "group",
+			args = {
+				about = {
+					desc = "Get information about Ace2",
+					name = "About",
+					type = "execute",
+					func = function()
+						print("|cffffff7fAce2|r - |cffffff7f2.0." .. MINOR_VERSION:gsub("%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework")
+						print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team")
+						print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/")
+					end
+				},
+				list = {
+					desc = "List addons",
+					name = "List",
+					type = "group",
+					args = {
+						ace2 = {
+							desc = "List addons using Ace2",
+							name = "Ace2",
+							type = "execute",
+							func = function()
+								print("|cffffff7fAddon list:|r")
+								table.sort(self.addons, mySort)
+								for _,v in ipairs(self.addons) do
+									listAddon(v)
+								end
+							end
+						},
+						all = {
+							desc = "List all addons",
+							name = "All",
+							type = "execute",
+							func = function()
+								print("|cffffff7fAddon list:|r")
+								local count = GetNumAddOns()
+								for i = 1, count do
+									listNormalAddon(i)
+								end
+							end
+						},
+						enabled = {
+							desc = "List all enabled addons",
+							name = "Enabled",
+							type = "execute",
+							func = function()
+								print("|cffffff7fAddon list:|r")
+								local count = GetNumAddOns()
+								for i = 1, count do
+									local _,_,_,enabled,loadable = GetAddOnInfo(i)
+									if enabled and loadable then
+										listNormalAddon(i)
+									end
+								end
+							end
+						},
+						disabled = {
+							desc = "List all disabled addons",
+							name = "Disabled",
+							type = "execute",
+							func = function()
+								print("|cffffff7fAddon list:|r")
+								local count = GetNumAddOns()
+								for i = 1, count do
+									local _,_,_,enabled,loadable = GetAddOnInfo(i)
+									if not enabled or not loadable then
+										listNormalAddon(i)
+									end
+								end
+							end
+						},
+						lod = {
+							desc = "List all LoadOnDemand addons",
+							name = "LoadOnDemand",
+							type = "execute",
+							func = function()
+								print("|cffffff7fAddon list:|r")
+								local count = GetNumAddOns()
+								for i = 1, count do
+									if IsAddOnLoadOnDemand(i) then
+										listNormalAddon(i)
+									end
+								end
+							end
+						},
+						ace1 = {
+							desc = "List all addons using Ace1",
+							name = "Ace 1.x",
+							type = "execute",
+							func = function()
+								print("|cffffff7fAddon list:|r")
+								local count = GetNumAddOns()
+								for i = 1, count do
+									local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
+									if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
+										listNormalAddon(i)
+									end
+								end
+							end
+						},
+						libs = {
+							desc = "List all libraries using AceLibrary",
+							name = "Libraries",
+							type = "execute",
+							func = function()
+								if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
+									print("|cffffff7fLibrary list:|r")
+									for name, data in pairs(AceLibrary.libs) do
+										local s
+										if data.minor then
+											s = " - " .. tostring(name) .. "." .. tostring(data.minor)
+										else
+											s = " - " .. tostring(name)
+										end
+										if rawget(AceLibrary(name), 'slashCommand') then
+											s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)"
+										end
+										print(s)
+									end
+								end
+							end
+						},
+						search = {
+							desc = "Search by name",
+							name = "Search",
+							type = "text",
+							usage = "<keyword>",
+							input = true,
+							get = false,
+							set = function(...)
+								local arg = { ... }
+								for i,v in ipairs(arg) do
+									arg[i] = v:gsub('%*', '.*'):gsub('%%', '%%%%'):lower()
+								end
+								local count = GetNumAddOns()
+								for i = 1, count do
+									local name = GetAddOnInfo(i)
+									local good = true
+									for _,v in ipairs(arg) do
+										if not name:lower():find(v) then
+											good = false
+											break
+										end
+									end
+									if good then
+										listNormalAddon(i)
+									end
+								end
+							end
+						}
+					},
+				},
+				enable = {
+					desc = "Enable addon(s).",
+					name = "Enable",
+					type = "text",
+					usage = "<addon 1> <addon 2> ...",
+					get = false,
+					input = true,
+					set = function(...)
+						for i = 1, select("#", ...) do
+							local addon = select(i, ...)
+							local name, title, _, enabled, _, reason = GetAddOnInfo(addon)
+							if reason == "MISSING" then
+								print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon))
+							elseif not enabled then
+								EnableAddOn(addon)
+								print(("|cffffff7fAce2:|r %s is now enabled."):format(addon or name))
+							else
+								print(("|cffffff7fAce2:|r %s is already enabled."):format(addon or name))
+							end
+						end
+					end,
+				},
+				disable = {
+					desc = "Disable addon(s).",
+					name = "Disable",
+					type = "text",
+					usage = "<addon 1> <addon 2> ...",
+					get = false,
+					input = true,
+					set = function(...)
+						for i = 1, select("#", ...) do
+							local addon = select(i, ...)
+							local name, title, _, enabled, _, reason = GetAddOnInfo(addon)
+							if reason == "MISSING" then
+							print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon))
+							elseif enabled then
+								DisableAddOn(addon)
+								print(("|cffffff7fAce2:|r %s is now disabled."):format(addon or name))
+							else
+								print(("|cffffff7fAce2:|r %s is already disabled."):format(addon or name))
+							end
+						end
+					end,
+				},
+				load = {
+					desc = "Load addon(s).",
+					name = "Load",
+					type = "text",
+					usage = "<addon 1> <addon 2> ...",
+					get = false,
+					input = true,
+					set = function(...)
+						for i = 1, select("#", ...) do
+							local addon = select(i, ...)
+							local name, title, _, _, loadable, reason = GetAddOnInfo(addon)
+							if reason == "MISSING" then
+								print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon))
+							elseif not loadable then
+								print(("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s."):format(addon, reason))
+							else
+								LoadAddOn(addon)
+								print(("|cffffff7fAce2:|r %s is now loaded."):format(addon or name))
+							end
+						end
+					end
+				},
+				info = {
+					desc = "Display information",
+					name = "Information",
+					type = "execute",
+					func = function()
+						local mem, threshold = gcinfo()
+						print((" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r"):format(mem / 1024))
+						if threshold then
+							print((" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r"):format(threshold / 1024))
+						end
+						print((" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r"):format(GetFramerate()))
+						local bandwidthIn, bandwidthOut, latency = GetNetStats()
+						bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024)
+						print((" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r"):format(latency))
+						print((" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r"):format(bandwidthIn))
+						print((" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r"):format(bandwidthOut))
+						print((" - |cffffff7fTotal addons [|r%d|cffffff7f]|r"):format(GetNumAddOns()))
+						print((" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r"):format(#self.addons))
+						local ace = 0
+						local enabled = 0
+						local disabled = 0
+						local lod = 0
+						for i = 1, GetNumAddOns() do
+							local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
+							if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
+								ace = ace + 1
+							end
+							if IsAddOnLoadOnDemand(i) then
+								lod = lod + 1
+							end
+							local isActive, loadable = select(4, GetAddOnInfo(i))
+							if not isActive or not loadable then
+								disabled = disabled + 1
+							else
+								enabled = enabled + 1
+							end
+						end
+						print((" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r"):format(ace))
+						print((" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r"):format(lod))
+						print((" - |cffffff7fenabled addons [|r%d|cffffff7f]|r"):format(enabled))
+						print((" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r"):format(disabled))
+						local libs = 0
+						if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
+							for _ in pairs(AceLibrary.libs) do
+								libs = libs + 1
+							end
+						end
+						print((" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r"):format(libs))
+					end
+				}
+			}
+		})
+	elseif major == "AceModuleCore-2.0" then
+		AceModuleCore = instance
+	end
+end
+
+local function activate(self, oldLib, oldDeactivate)
+	AceAddon = self
+
+	self.playerLoginFired = oldLib and oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage
+	self.addonsToOnEnable = oldLib and oldLib.addonsToOnEnable
+	self.addons = oldLib and oldLib.addons or {}
+	self.nextAddon = oldLib and oldLib.nextAddon or {}
+	self.skipAddon = oldLib and oldLib.skipAddon or {}
+	self.addonsStarted = oldLib and oldLib.addonsStarted or {}
+	self.addonsEnabled = oldLib and oldLib.addonsEnabled or {}
+
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceAddon-2.0/AceAddon-2.0.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,12 @@
+## Interface: 20200
+
+## Title: Lib: AceAddon-2.0
+## Notes: AddOn development framework
+## Author: Ace Development Team
+## LoadOnDemand: 1
+## X-Website: http://www.wowace.com
+## X-Category: Library
+## X-License: LGPL v2.1 + MIT for AceOO-2.0
+## Dependencies: AceLibrary, AceOO-2.0
+ 
+AceAddon-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,1082 @@
+--[[
+Name: AceEvent-2.0
+Revision: $Rev: 49307 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Ace 1.x by Turan (turan@gryphon.com)
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/index.php/AceEvent-2.0
+SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
+Description: Mixin to allow for event handling, scheduling, and inter-addon
+             communication.
+Dependencies: AceLibrary, AceOO-2.0
+License: LGPL v2.1
+]]
+
+local MAJOR_VERSION = "AceEvent-2.0"
+local MINOR_VERSION = "$Revision: 49307 $"
+
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
+
+local AceOO = AceLibrary:GetInstance("AceOO-2.0")
+local Mixin = AceOO.Mixin
+local AceEvent = Mixin {
+	"RegisterEvent",
+	"RegisterAllEvents",
+	"UnregisterEvent",
+	"UnregisterAllEvents",
+	"TriggerEvent",
+	"ScheduleEvent",
+	"ScheduleRepeatingEvent",
+	"CancelScheduledEvent",
+	"CancelAllScheduledEvents",
+	"IsEventRegistered",
+	"IsEventScheduled",
+	"RegisterBucketEvent",
+	"UnregisterBucketEvent",
+	"UnregisterAllBucketEvents",
+	"IsBucketEventRegistered",
+	"ScheduleLeaveCombatAction",
+	"CancelAllCombatSchedules",
+}
+
+local weakKey = {__mode="k"}
+
+local FAKE_NIL
+local RATE
+
+local eventsWhichHappenOnce = {
+	PLAYER_LOGIN = true,
+	AceEvent_FullyInitialized = true,
+	VARIABLES_LOADED = true,
+	PLAYER_LOGOUT = true,
+}
+local next = next
+local pairs = pairs
+local pcall = pcall
+local type = type
+local GetTime = GetTime
+local gcinfo = gcinfo
+local unpack = unpack
+local geterrorhandler = geterrorhandler
+
+local build = GetBuildInfo()
+local useTablesAsIDs = build:find("^2%.0%.") or build:find("^2%.1%.") or build:find("^0%.1%.")
+
+local new, del
+do
+	local cache = setmetatable({}, {__mode='k'})
+	function new(...)
+		local t = next(cache)
+		if t then
+			cache[t] = nil
+			for i = 1, select('#', ...) do
+				t[i] = select(i, ...)
+			end
+			return t
+		else
+			return { ... }
+		end
+	end
+	function del(t)
+		for k in pairs(t) do
+			t[k] = nil
+		end
+		cache[t] = true
+		return nil
+	end
+end
+
+local registeringFromAceEvent
+--[[----------------------------------------------------------------------------------
+Notes:
+	* Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered.
+Arguments:
+	string - name of the event to register
+	[optional] string or function - name of the method or function to call. Default: same name as "event".
+	[optional] boolean - whether to have method called only once. Default: false
+------------------------------------------------------------------------------------]]
+function AceEvent:RegisterEvent(event, method, once)
+	AceEvent:argCheck(event, 2, "string")
+	if self == AceEvent and not registeringFromAceEvent then
+		AceEvent:argCheck(method, 3, "function")
+		self = method
+	else
+		AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
+		if type(method) == "boolean" or type(method) == "number" then
+			AceEvent:argCheck(once, 4, "nil")
+			once, method = method, event
+		end
+	end
+	AceEvent:argCheck(once, 4, "number", "boolean", "nil")
+	if eventsWhichHappenOnce[event] then
+		once = true
+	end
+	local throttleRate
+	if type(once) == "number" then
+		throttleRate, once = once
+	end
+	if not method then
+		method = event
+	end
+	if type(method) == "string" and type(self[method]) ~= "function" then
+		AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
+	else
+		assert(type(method) == "function" or type(method) == "string")
+	end
+
+	local AceEvent_registry = AceEvent.registry
+	if not AceEvent_registry[event] then
+		AceEvent_registry[event] = new()
+		AceEvent.frame:RegisterEvent(event)
+	end
+
+	local remember = true
+	if AceEvent_registry[event][self] then
+		remember = false
+	end
+	AceEvent_registry[event][self] = method
+
+	local AceEvent_onceRegistry = AceEvent.onceRegistry
+	if once then
+		if not AceEvent_onceRegistry then
+			AceEvent.onceRegistry = {}
+			AceEvent_onceRegistry = AceEvent.onceRegistry
+		end
+		if not AceEvent_onceRegistry[event] then
+			AceEvent_onceRegistry[event] = new()
+		end
+		AceEvent_onceRegistry[event][self] = true
+	else
+		if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
+			AceEvent_onceRegistry[event][self] = nil
+			if not next(AceEvent_onceRegistry[event]) then
+				AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
+			end
+		end
+	end
+
+	local AceEvent_throttleRegistry = AceEvent.throttleRegistry
+	if throttleRate then
+		if not AceEvent_throttleRegistry then
+			AceEvent.throttleRegistry = {}
+			AceEvent_throttleRegistry = AceEvent.throttleRegistry
+		end
+		if not AceEvent_throttleRegistry[event] then
+			AceEvent_throttleRegistry[event] = new()
+		end
+		if AceEvent_throttleRegistry[event][self] then
+			AceEvent_throttleRegistry[event][self] = nil
+		end
+		AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
+		local t = AceEvent_throttleRegistry[event][self]
+		t[RATE] = throttleRate
+	else
+		if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
+			if AceEvent_throttleRegistry[event][self] then
+				AceEvent_throttleRegistry[event][self] = nil
+			end
+			if not next(AceEvent_throttleRegistry[event]) then
+				AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
+			end
+		end
+	end
+
+	if remember then
+		AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
+	end
+end
+
+local ALL_EVENTS
+
+--[[----------------------------------------------------------------------------------
+Notes:
+	* Registers all events to the given method
+	* To access the current event, check AceEvent.currentEvent
+	* To access the current event's unique identifier, check AceEvent.currentEventUID
+	* This is only for debugging purposes.
+Arguments:
+	[optional] string or function - name of the method or function to call. Default: same name as "event".
+------------------------------------------------------------------------------------]]
+function AceEvent:RegisterAllEvents(method)
+	if self == AceEvent then
+		AceEvent:argCheck(method, 1, "function")
+		self = method
+	else
+		AceEvent:argCheck(method, 1, "string", "function")
+		if type(method) == "string" and type(self[method]) ~= "function" then
+			AceEvent:error("Cannot register all events to method %q, it does not exist", method)
+		end
+	end
+	
+	local AceEvent_registry = AceEvent.registry
+	if not AceEvent_registry[ALL_EVENTS] then
+		AceEvent_registry[ALL_EVENTS] = new()
+		AceEvent.frame:RegisterAllEvents()
+	end
+	
+	local remember = not AceEvent_registry[ALL_EVENTS][self]
+	AceEvent_registry[ALL_EVENTS][self] = method
+	if remember then
+		AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all")
+	end
+end
+
+--[[----------------------------------------------------------------------------------
+Notes:
+	* Trigger a custom AceEvent.
+	* This should never be called to simulate fake Blizzard events.
+	* Custom events should be in the form of AddonName_SpecificEvent
+Arguments:
+	string - name of the event
+	tuple - list of arguments to pass along
+------------------------------------------------------------------------------------]]
+function AceEvent:TriggerEvent(event, ...)
+	if type(event) ~= "string" then
+		DEFAULT_CHAT_FRAME:AddMessage(debugstack())
+	end
+	AceEvent:argCheck(event, 2, "string")
+	local AceEvent_registry = AceEvent.registry
+	if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
+		return
+	end
+	local lastEvent = AceEvent.currentEvent
+	AceEvent.currentEvent = event
+	local lastEventUID = AceEvent.currentEventUID
+	local uid = AceEvent.UID_NUM + 1
+	AceEvent.UID_NUM = uid
+	AceEvent.currentEventUID = uid
+
+	local tmp = new()
+
+	local AceEvent_onceRegistry = AceEvent.onceRegistry
+	if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
+		for obj, method in pairs(AceEvent_onceRegistry[event]) do
+			tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
+		end
+		local obj = next(tmp)
+		while obj do
+			local method = tmp[obj]
+			AceEvent.UnregisterEvent(obj, event)
+			if type(method) == "string" then
+				local obj_method = obj[method]
+				if obj_method then
+					local success, err = pcall(obj_method, obj, ...)
+					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+				end
+			elseif method then -- function
+				local success, err = pcall(method, ...)
+				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+			end
+			tmp[obj] = nil
+			obj = next(tmp)
+		end
+	end
+
+	local AceEvent_throttleRegistry = AceEvent.throttleRegistry
+	local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
+	if AceEvent_registry[event] then
+		for obj, method in pairs(AceEvent_registry[event]) do
+			tmp[obj] = method
+		end
+		local obj = next(tmp)
+		while obj do
+			local method = tmp[obj]
+			local continue = false
+			if throttleTable and throttleTable[obj] then
+				local a1 = ...
+				if a1 == nil then
+					a1 = FAKE_NIL
+				end
+				if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
+					throttleTable[obj][a1] = GetTime()
+				else
+					continue = true
+				end
+			end
+			if not continue then
+				if type(method) == "string" then
+					local obj_method = obj[method]
+					if obj_method then
+						local success, err = pcall(obj_method, obj, ...)
+						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+					end
+				elseif method then -- function
+					local success, err = pcall(method, ...)
+					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+				end
+			end
+			tmp[obj] = nil
+			obj = next(tmp)
+		end
+	end
+	if AceEvent_registry[ALL_EVENTS] then
+		for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
+			tmp[obj] = method
+		end
+		local obj = next(tmp)
+		while obj do
+			local method = tmp[obj]
+			if type(method) == "string" then
+				local obj_method = obj[method]
+				if obj_method then
+					local success, err = pcall(obj_method, obj, ...)
+					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+				end
+			elseif method then -- function
+				local success, err = pcall(method, ...)
+				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+			end
+			tmp[obj] = nil
+			obj = next(tmp)
+		end
+	end
+	tmp = del(tmp)
+	AceEvent.currentEvent = lastEvent
+	AceEvent.currentEventUID = lastEventUID
+end
+
+local delayRegistry
+local OnUpdate
+do
+	local tmp = {}
+	OnUpdate = function()
+		local t = GetTime()
+		for k,v in pairs(delayRegistry) do
+			tmp[k] = true
+		end
+		for k in pairs(tmp) do
+			local v = delayRegistry[k]
+			if v then
+				local v_time = v.time
+				if not v_time then
+					delayRegistry[k] = nil
+				elseif v_time <= t then
+					local v_repeatDelay = v.repeatDelay
+					if v_repeatDelay then
+						-- use the event time, not the current time, else timing inaccuracies add up over time
+						v.time = v_time + v_repeatDelay
+					end
+					local event = v.event
+					if type(event) == "function" then
+						local uid = AceEvent.UID_NUM + 1
+						AceEvent.UID_NUM = uid
+						AceEvent.currentEventUID = uid
+						local success, err = pcall(event, unpack(v, 1, v.n))
+						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+						AceEvent.currentEventUID = nil
+					else
+						AceEvent:TriggerEvent(event, unpack(v, 1, v.n))
+					end
+					if not v_repeatDelay then
+						local x = delayRegistry[k]
+						if x and x.time == v_time then -- check if it was manually reset
+							if not useTablesAsIDs or type(k) == "string" then
+								del(delayRegistry[k])
+							end
+							delayRegistry[k] = nil
+						end
+					end
+				end
+			end
+		end
+		for k in pairs(tmp) do
+			tmp[k] = nil
+		end
+		if not next(delayRegistry) then
+			AceEvent.frame:Hide()
+		end
+	end
+end
+
+local function ScheduleEvent(self, repeating, event, delay, ...)
+	local id
+	if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
+		if useTablesAsIDs and type(event) == "table" then
+			if not delayRegistry or not delayRegistry[event] then
+				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
+			end
+		end
+		if type(delay) ~= "number" then
+			id, event, delay = event, delay, ...
+			AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
+			AceEvent:argCheck(delay, 4, "number")
+			self:CancelScheduledEvent(id)
+		end
+	else
+		AceEvent:argCheck(event, 2, "string", "function")
+		AceEvent:argCheck(delay, 3, "number")
+	end
+
+	if not delayRegistry then
+		AceEvent.delayRegistry = {}
+		delayRegistry = AceEvent.delayRegistry
+		AceEvent.frame:SetScript("OnUpdate", OnUpdate)
+	end
+	local t
+	if useTablesAsIDs and type(id) == "table" then
+		for k in pairs(id) do
+			id[k] = nil
+		end
+		t = id
+		for i = 2, select('#', ...) do
+			t[i-1] = select(i, ...)
+		end
+		t.n = select('#', ...) - 1
+	elseif id then
+		t = new(select(2, ...))
+		t.n = select('#', ...) - 1
+	else
+		t = new(...)
+		t.n = select('#', ...)
+	end
+	t.event = event
+	t.time = GetTime() + delay
+	t.self = self
+	t.id = id or t
+	t.repeatDelay = repeating and delay
+	delayRegistry[t.id] = t
+	AceEvent.frame:Show()
+	if useTablesAsIDs then
+		return t.id
+	else
+		return
+	end
+end
+
+--[[----------------------------------------------------------------------------------
+Notes:
+	* Schedule an event to fire.
+	* To fire on the next frame, specify a delay of 0.
+Arguments:
+	string or function - name of the event to fire, or a function to call.
+	number - the amount of time to wait until calling.
+	tuple - a list of arguments to pass along.
+------------------------------------------------------------------------------------]]
+function AceEvent:ScheduleEvent(event, delay, ...)
+	if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
+		if useTablesAsIDs and type(event) == "table" then
+			if not delayRegistry or not delayRegistry[event] then
+				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
+			end
+		end
+		if type(delay) ~= "number" then
+			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
+			AceEvent:argCheck(..., 4, "number")
+		end
+	else
+		AceEvent:argCheck(event, 2, "string", "function")
+		AceEvent:argCheck(delay, 3, "number")
+	end
+
+	return ScheduleEvent(self, false, event, delay, ...)
+end
+
+function AceEvent:ScheduleRepeatingEvent(event, delay, ...)
+	if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
+		if useTablesAsIDs and type(event) == "table" then
+			if not delayRegistry or not delayRegistry[event] then
+				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
+			end
+		end
+		if type(delay) ~= "number" then
+			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
+			AceEvent:argCheck(..., 4, "number")
+		end
+	else
+		AceEvent:argCheck(event, 2, "string", "function")
+		AceEvent:argCheck(delay, 3, "number")
+	end
+
+	return ScheduleEvent(self, true, event, delay, ...)
+end
+
+function AceEvent:CancelScheduledEvent(t)
+	if useTablesAsIDs then
+		AceEvent:argCheck(t, 2, "string", "table")
+	else
+		AceEvent:argCheck(t, 2, "string")
+	end
+	if delayRegistry then
+		local v = delayRegistry[t]
+		if v then
+			if not useTablesAsIDs or type(t) == "string" then
+				del(delayRegistry[t])
+			end
+			delayRegistry[t] = nil
+			if not next(delayRegistry) then
+				AceEvent.frame:Hide()
+			end
+			return true
+		end
+	end
+	return false
+end
+
+function AceEvent:IsEventScheduled(t)
+	if useTablesAsIDs then
+		AceEvent:argCheck(t, 2, "string", "table")
+	else
+		AceEvent:argCheck(t, 2, "string")
+	end
+	if delayRegistry then
+		local v = delayRegistry[t]
+		if v then
+			return true, v.time - GetTime()
+		end
+	end
+	return false, nil
+end
+
+function AceEvent:UnregisterEvent(event)
+	AceEvent:argCheck(event, 2, "string")
+	local AceEvent_registry = AceEvent.registry
+	if AceEvent_registry[event] and AceEvent_registry[event][self] then
+		AceEvent_registry[event][self] = nil
+		local AceEvent_onceRegistry = AceEvent.onceRegistry
+		if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
+			AceEvent_onceRegistry[event][self] = nil
+			if not next(AceEvent_onceRegistry[event]) then
+				AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
+			end
+		end
+		local AceEvent_throttleRegistry = AceEvent.throttleRegistry
+		if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
+			AceEvent_throttleRegistry[event][self] = nil
+			if not next(AceEvent_throttleRegistry[event]) then
+				AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
+			end
+		end
+		if not next(AceEvent_registry[event]) then
+			AceEvent_registry[event] = del(AceEvent_registry[event])
+			if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
+				AceEvent.frame:UnregisterEvent(event)
+			end
+		end
+	else
+		if self == AceEvent then
+			error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2)
+		else
+			AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
+		end
+	end
+	AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
+end
+
+function AceEvent:UnregisterAllEvents()
+	local AceEvent_registry = AceEvent.registry
+	if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
+		AceEvent_registry[ALL_EVENTS][self] = nil
+		if not next(AceEvent_registry[ALL_EVENTS]) then
+			AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS])
+			AceEvent.frame:UnregisterAllEvents()
+			for k,v in pairs(AceEvent_registry) do
+				AceEvent.frame:RegisterEvent(k)
+			end
+		end
+	end
+	if AceEvent_registry.AceEvent_EventUnregistered then
+		local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered
+		local x = data[self]
+		data[self] = nil
+		if x then
+			if not next(data) then
+				if not AceEvent_registry[ALL_EVENTS] then
+					AceEvent.frame:UnregisterEvent(event)
+				end
+				AceEvent_registry[event] = del(AceEvent_registry[event])
+			end
+			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
+		end
+	end
+	for event, data in pairs(AceEvent_registry) do
+		local x = data[self]
+		data[self] = nil
+		if x and event ~= ALL_EVENTS then
+			if not next(data) then
+				if not AceEvent_registry[ALL_EVENTS] then
+					AceEvent.frame:UnregisterEvent(event)
+				end
+				AceEvent_registry[event] = del(AceEvent_registry[event])
+			end
+			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
+		end
+	end
+	if AceEvent.onceRegistry then
+		for event, data in pairs(AceEvent.onceRegistry) do
+			data[self] = nil
+		end
+	end
+end
+
+function AceEvent:CancelAllScheduledEvents()
+	if delayRegistry then
+		for k,v in pairs(delayRegistry) do
+			if v.self == self then
+				if not useTablesAsIDs or type(k) == "string" then
+					del(delayRegistry[k])
+				end
+				delayRegistry[k] = nil
+			end
+		end
+		if not next(delayRegistry) then
+			AceEvent.frame:Hide()
+		end
+	end
+end
+
+function AceEvent:IsEventRegistered(event)
+	AceEvent:argCheck(event, 2, "string")
+	local AceEvent_registry = AceEvent.registry
+	if self == AceEvent then
+		return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false
+	end
+	if AceEvent_registry[event] and AceEvent_registry[event][self] then
+		return true, AceEvent_registry[event][self]
+	end
+	if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
+		return true, AceEvent_registry[ALL_EVENTS][self]
+	end
+	return false, nil
+end
+
+local UnitExists = UnitExists
+local bucketfunc
+function AceEvent:RegisterBucketEvent(event, delay, method, ...)
+	AceEvent:argCheck(event, 2, "string", "table")
+	if type(event) == "table" then
+		for k,v in pairs(event) do
+			if type(k) ~= "number" then
+				AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
+			elseif type(v) ~= "string" then
+				AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
+			end
+		end
+	end
+	AceEvent:argCheck(delay, 3, "number")
+	if AceEvent == self then
+		AceEvent:argCheck(method, 4, "function")
+		self = method
+	else
+		if type(event) == "string" then
+			AceEvent:argCheck(method, 4, "string", "function", "nil")
+			if not method then
+				method = event
+			end
+		else
+			AceEvent:argCheck(method, 4, "string", "function")
+		end
+
+		if type(method) == "string" and type(self[method]) ~= "function" then
+			AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
+		end
+	end
+	local buckets = AceEvent.buckets
+	if not buckets[event] then
+		buckets[event] = new()
+	end
+	if not buckets[event][self] then
+		local t = new()
+		t.current = new()
+		t.self = self
+		buckets[event][self] = t
+	else
+		AceEvent.CancelScheduledEvent(self, buckets[event][self].id)
+	end
+	local bucket = buckets[event][self]
+	bucket.method = method
+	
+	local n = select('#', ...)
+	if n > 0 then
+		for i = 1, n do
+			bucket[i] = select(i, ...)
+		end
+	end
+	bucket.n = n
+
+	local func = function(arg1)
+		bucket.run = true
+		if arg1 then
+			bucket.current[arg1] = true
+		end
+	end
+	buckets[event][self].func = func
+	local isUnitBucket = true
+	if type(event) == "string" then
+		AceEvent.RegisterEvent(self, event, func)
+		if not event:find("^UNIT_") then
+			isUnitBucket = false
+		end
+	else
+		for _,v in ipairs(event) do
+			AceEvent.RegisterEvent(self, v, func)
+			if isUnitBucket and not v:find("^UNIT_") then
+				isUnitBucket = false
+			end
+		end
+	end
+	bucket.unit = isUnitBucket
+	if not bucketfunc then
+		bucketfunc = function(bucket)
+			local current = bucket.current
+			local method = bucket.method
+			local self = bucket.self
+			if bucket.run then
+				if bucket.unit then
+					for unit in pairs(current) do
+						if not UnitExists(unit) then
+							current[unit] = nil
+						end
+					end
+				end
+				if type(method) == "string" then
+					self[method](self, current, unpack(bucket, 1, bucket.n))
+				elseif method then -- function
+					method(current, unpack(bucket, 1, bucket.n))
+				end
+				for k in pairs(current) do
+					current[k] = nil
+					k = nil
+				end
+				bucket.run = false
+			end
+		end
+	end
+	bucket.id = "AceEvent-Bucket-" .. tostring(bucket)
+	AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket)
+end
+
+function AceEvent:IsBucketEventRegistered(event)
+	AceEvent:argCheck(event, 2, "string", "table")
+	return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
+end
+
+function AceEvent:UnregisterBucketEvent(event)
+	AceEvent:argCheck(event, 2, "string", "table")
+	if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
+		AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
+	end
+
+	local bucket = AceEvent.buckets[event][self]
+
+	if type(event) == "string" then
+		AceEvent.UnregisterEvent(self, event)
+	else
+		for _,v in ipairs(event) do
+			AceEvent.UnregisterEvent(self, v)
+		end
+	end
+	AceEvent:CancelScheduledEvent(bucket.id)
+
+	bucket.current = del(bucket.current)
+	AceEvent.buckets[event][self] = del(bucket)
+	if not next(AceEvent.buckets[event]) then
+		AceEvent.buckets[event] = del(AceEvent.buckets[event])
+	end
+end
+
+function AceEvent:UnregisterAllBucketEvents()
+	if not AceEvent.buckets or not next(AceEvent.buckets) then
+		return
+	end
+	for k,v in pairs(AceEvent.buckets) do
+		if v == self then
+			AceEvent.UnregisterBucketEvent(self, k)
+			k = nil
+		end
+	end
+end
+
+local combatSchedules
+function AceEvent:CancelAllCombatSchedules()
+	local i = 0
+	while true do
+		i = i + 1
+		if not combatSchedules[i] then
+			break
+		end
+		local v = combatSchedules[i]
+		if v.self == self then
+			v = del(v)
+			table.remove(combatSchedules, i)
+			i = i - 1
+		end
+	end
+end
+
+local inCombat = false
+
+function AceEvent:PLAYER_REGEN_DISABLED()
+	inCombat = true
+end
+
+do
+	local tmp = {}
+	function AceEvent:PLAYER_REGEN_ENABLED()
+		inCombat = false
+		for i, v in ipairs(combatSchedules) do
+			tmp[i] = v
+			combatSchedules[i] = nil
+		end
+		for i, v in ipairs(tmp) do
+			local func = v.func
+			if func then
+				local success, err = pcall(func, unpack(v, 1, v.n))
+				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+			else
+				local obj = v.obj or v.self
+				local method = v.method
+				local obj_method = obj[method]
+				if obj_method then
+					local success, err = pcall(obj_method, obj, unpack(v, 1, v.n))
+					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+				end
+			end
+			tmp[i] = del(v)
+		end
+	end
+end
+
+function AceEvent:ScheduleLeaveCombatAction(method, ...)
+	local style = type(method)
+	if self == AceEvent then
+		if style == "table" then
+			local func = (...)
+			AceEvent:argCheck(func, 3, "string")
+			if type(method[func]) ~= "function" then
+				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
+			end
+		else
+			AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table")
+		end
+		self = method
+	else
+		AceEvent:argCheck(method, 2, "function", "string", "table")
+		if style == "string" and type(self[method]) ~= "function" then
+			AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method)
+		elseif style == "table" then
+			local func = (...)
+			AceEvent:argCheck(func, 3, "string")
+			if type(method[func]) ~= "function" then
+				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
+			end
+		end
+	end
+	
+	if not inCombat then
+		local success, err
+		if type(method) == "function" then
+			success, err = pcall(method, ...)
+		elseif type(method) == "table" then
+			local func = (...)
+			success, err = pcall(method[func], method, select(2, ...))
+		else
+			success, err = pcall(self[method], self, ...)
+		end
+		if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
+		return
+	end
+	local t
+	local n = select('#', ...)
+	if style == "table" then
+		t = new(select(2, ...))
+		t.obj = method
+		t.method = (...)
+		t.n = n-1
+	else
+		t = new(...)
+		t.n = n
+		if style == "function" then
+			t.func = method
+		else
+			t.method = method
+		end
+	end
+	t.self = self
+	table.insert(combatSchedules, t)
+end
+
+function AceEvent:OnEmbedDisable(target)
+	self.UnregisterAllEvents(target)
+
+	self.CancelAllScheduledEvents(target)
+
+	self.UnregisterAllBucketEvents(target)
+	
+	self.CancelAllCombatSchedules(target)
+end
+
+function AceEvent:IsFullyInitialized()
+	return self.postInit or false
+end
+
+function AceEvent:IsPostPlayerLogin()
+	return IsLoggedIn() and true or false
+end
+
+local function activate(self, oldLib, oldDeactivate)
+	AceEvent = self
+	
+	self.onceRegistry = oldLib and oldLib.onceRegistry or {}
+	self.throttleRegistry = oldLib and oldLib.throttleRegistry or {}
+	self.delayRegistry = oldLib and oldLib.delayRegistry or {}
+	self.buckets = oldLib and oldLib.buckets or {}
+	self.registry = oldLib and oldLib.registry or {}
+	self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame")
+	self.playerLogin = IsLoggedIn() and true
+	self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
+	self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy()
+	self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy()
+	self.RATE = oldLib and oldLib.RATE or _G.newproxy()
+	self.combatSchedules = oldLib and oldLib.combatSchedules or {}
+	self.UID_NUM = oldLib and oldLib.UID_NUM or 0
+	
+	-- Delete this down the road.  Makes sure that the addonframes from revisions 33121 - 36174 get their events unregistered.
+	local addonframes = oldLib and oldLib.addonframes
+	if addonframes then
+		for _, v in pairs(addonframes) do
+			v:UnregisterAllEvents()
+		end
+	end
+	
+	combatSchedules = self.combatSchedules
+	ALL_EVENTS = self.ALL_EVENTS
+	FAKE_NIL = self.FAKE_NIL
+	RATE = self.RATE
+	local inPlw = false
+	local blacklist = {
+		UNIT_INVENTORY_CHANGED = true,
+		BAG_UPDATE = true,
+		ITEM_LOCK_CHANGED = true,
+		ACTIONBAR_SLOT_CHANGED = true,
+	}
+	self.frame:SetScript("OnEvent", function(_, event, ...)
+		if event == "PLAYER_ENTERING_WORLD" then
+			inPlw = false
+		elseif event == "PLAYER_LEAVING_WORLD" then
+			inPlw = true
+		end
+		if event and (not inPlw or not blacklist[event]) then
+			self:TriggerEvent(event, ...)
+		end
+	end)
+	if self.delayRegistry then
+		delayRegistry = self.delayRegistry
+		self.frame:SetScript("OnUpdate", OnUpdate)
+	end
+
+	self:UnregisterAllEvents()
+	self:CancelAllScheduledEvents()
+
+	registeringFromAceEvent = true
+	self:RegisterEvent("LOOT_OPENED", function()
+		SendAddonMessage("LOOT_OPENED", "", "RAID")
+	end)
+	registeringFromAceEvent = nil
+
+	local function handleFullInit()
+		if not self.postInit then
+			local function func()
+				self.postInit = true
+				self:TriggerEvent("AceEvent_FullyInitialized")
+				if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
+					self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
+				end
+				if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
+					self:UnregisterEvent("MEETINGSTONE_CHANGED")
+				end
+				if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
+					self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
+				end
+				if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
+					self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
+				end
+				collectgarbage('collect')
+			end
+			registeringFromAceEvent = true
+			local f = function()
+				self.playerLogin = true
+				self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
+			end
+			self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
+			self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
+				self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15)
+			end)
+			self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
+				if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
+					registeringFromAceEvent = true
+					self:UnregisterEvent("MEETINGSTONE_CHANGED")
+					self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true)
+					registeringFromAceEvent = nil
+				end
+			end)
+			self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
+			registeringFromAceEvent = nil
+		end
+	end
+	
+	if not self.playerLogin then
+		registeringFromAceEvent = true
+		self:RegisterEvent("PLAYER_LOGIN", function()
+			self.playerLogin = true
+			handleFullInit()
+			handleFullInit = nil
+			collectgarbage('collect')
+		end, true)
+		registeringFromAceEvent = nil
+	else
+		handleFullInit()
+		handleFullInit = nil
+	end
+	
+	if not AceEvent20EditBox then
+	    CreateFrame("Editbox", "AceEvent20EditBox")
+	end
+	local editbox = AceEvent20EditBox
+	function editbox:Execute(line)
+		local defaulteditbox = DEFAULT_CHAT_FRAME.editBox
+		self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType"))
+		self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget"))
+		self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget"))
+		self:SetText(line)
+		ChatEdit_SendText(self)
+	end
+	editbox:Hide()
+	_G["SLASH_IN1"] = "/in"
+	SlashCmdList["IN"] = function(msg)
+		local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$")
+		seconds = tonumber(seconds)
+		if not seconds then
+			DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'")
+			return
+		end
+		if IsSecureCmd(command) then
+			DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command))
+			return
+		end
+		self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest)
+	end
+	registeringFromAceEvent = true
+	self:RegisterEvent("PLAYER_REGEN_ENABLED")
+	self:RegisterEvent("PLAYER_REGEN_DISABLED")
+	inCombat = InCombatLockdown()
+	registeringFromAceEvent = nil
+	
+	-- another hack to make sure that we clean up properly from rev 33121 - 36174
+	if self.registry[ALL_EVENTS] then
+		self.frame:RegisterAllEvents()
+	else
+		for event in pairs(self.registry) do
+			self.frame:RegisterEvent(event)
+		end
+	end
+	
+	self:activate(oldLib, oldDeactivate)
+	if oldLib then
+		oldDeactivate(oldLib)
+	end
+end
+
+AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,12 @@
+## Interface: 20200
+
+## Title: Lib: AceEvent-2.0
+## Notes: AddOn development framework
+## Author: Ace Development Team
+## LoadOnDemand: 1
+## X-Website: http://www.wowace.com
+## X-Category: Library
+## X-License: LGPL v2.1 + MIT for AceOO-2.0
+## Dependencies: AceLibrary, AceOO-2.0
+ 
+AceEvent-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,856 @@
+--[[
+Name: AceLibrary
+Revision: $Rev: 49421 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Iriel (iriel@vigilance-committee.org)
+             Tekkub (tekkub@gmail.com)
+             Revision: $Rev: 49421 $
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/index.php/AceLibrary
+SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
+Description: Versioning library to handle other library instances, upgrading,
+             and proper access.
+             It also provides a base for libraries to work off of, providing
+             proper error tools. It is handy because all the errors occur in the
+             file that called it, not in the library file itself.
+Dependencies: None
+License: LGPL v2.1
+]]
+
+local ACELIBRARY_MAJOR = "AceLibrary"
+local ACELIBRARY_MINOR = "$Revision: 49421 $"
+
+local _G = getfenv(0)
+local previous = _G[ACELIBRARY_MAJOR]
+if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
+
+do
+	-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
+	-- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+	local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+	local LibStub = _G[LIBSTUB_MAJOR]
+
+	if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+		LibStub = LibStub or {libs = {}, minors = {} }
+		_G[LIBSTUB_MAJOR] = LibStub
+		LibStub.minor = LIBSTUB_MINOR
+		
+		function LibStub:NewLibrary(major, minor)
+			assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+			minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+			local oldminor = self.minors[major]
+			if oldminor and oldminor >= minor then return nil end
+			self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+			return self.libs[major], oldminor
+		end
+		
+		function LibStub:GetLibrary(major, silent)
+			if not self.libs[major] and not silent then
+				error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+			end
+			return self.libs[major], self.minors[major]
+		end
+		
+		function LibStub:IterateLibraries() return pairs(self.libs) end
+		setmetatable(LibStub, { __call = LibStub.GetLibrary })
+	end
+end
+local LibStub = _G.LibStub
+
+-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
+-- disabled in the addon screen, set this to true.
+local DONT_ENABLE_LIBRARIES = nil
+
+local function safecall(func,...)
+    local success, err = pcall(func,...)
+    if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
+end
+
+local WoW22 = false
+if type(GetBuildInfo) == "function" then
+	local success, buildinfo = pcall(GetBuildInfo)
+	if success and type(buildinfo) == "string" then
+		local num = tonumber(buildinfo:match("^(%d+%.%d+)"))
+		if num and num >= 2.2 then
+			WoW22 = true
+		end
+	end
+end
+
+-- @table AceLibrary
+-- @brief System to handle all versioning of libraries.
+local AceLibrary = {}
+local AceLibrary_mt = {}
+setmetatable(AceLibrary, AceLibrary_mt)
+
+local function error(self, message, ...)
+	if type(self) ~= "table" then
+		return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
+	end
+	
+	local stack = debugstack()
+	if not message then
+		local second = stack:match("\n(.-)\n")
+		message = "error raised! " .. second
+	else
+		local arg = { ... } -- not worried about table creation, as errors don't happen often
+		
+		for i = 1, #arg do
+			arg[i] = tostring(arg[i])
+		end
+		for i = 1, 10 do
+			table.insert(arg, "nil")
+		end
+		message = message:format(unpack(arg))
+	end
+	
+	if getmetatable(self) and getmetatable(self).__tostring then
+		message = ("%s: %s"):format(tostring(self), message)
+	elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
+		message = ("%s: %s"):format(self:GetLibraryVersion(), message)
+	elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
+		message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
+	end
+	
+	local first = stack:gsub("\n.*", "")
+	local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
+	file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
+	
+	
+	local i = 0
+	for s in stack:gmatch("\n([^\n]*)") do
+		i = i + 1
+		if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
+			file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
+			file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
+			break
+		end
+	end
+	local j = 0
+	for s in stack:gmatch("\n([^\n]*)") do
+		j = j + 1
+		if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
+			return _G.error(message, j+1)
+		end
+	end
+	return _G.error(message, 2)
+end
+
+local assert
+if not WoW22 then
+	function assert(self, condition, message, ...)
+		if not condition then
+			if not message then
+				local stack = debugstack()
+				local second = stack:match("\n(.-)\n")
+				message = "assertion failed! " .. second
+			end
+			return error(self, message, ...)
+		end
+		return condition
+	end
+end
+
+local type = type
+local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
+	if type(num) ~= "number" then
+		return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
+	elseif type(kind) ~= "string" then
+		return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
+	end
+	arg = type(arg)
+	if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
+		local stack = debugstack()
+		local func = stack:match("`argCheck'.-([`<].-['>])")
+		if not func then
+			func = stack:match("([`<].-['>])")
+		end
+		if kind5 then
+			return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
+		elseif kind4 then
+			return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
+		elseif kind3 then
+			return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
+		elseif kind2 then
+			return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
+		else
+			return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
+		end
+	end
+end
+
+local pcall
+do
+	local function check(self, ret, ...)
+		if not ret then
+			local s = ...
+			return error(self, (s:gsub(".-%.lua:%d-: ", "")))
+		else
+			return ...
+		end
+	end
+
+	function pcall(self, func, ...)
+		return check(self, _G.pcall(func, ...))
+	end
+end
+
+local recurse = {}
+local function addToPositions(t, major)
+	if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
+		rawset(t, recurse, true)
+		AceLibrary.positions[t] = major
+		for k,v in pairs(t) do
+			if type(v) == "table" and not rawget(v, recurse) then
+				addToPositions(v, major)
+			end
+			if type(k) == "table" and not rawget(k, recurse) then
+				addToPositions(k, major)
+			end
+		end
+		local mt = getmetatable(t)
+		if mt and not rawget(mt, recurse) then
+			addToPositions(mt, major)
+		end
+		rawset(t, recurse, nil)
+	end
+end
+
+local function svnRevisionToNumber(text)
+	local kind = type(text)
+	if kind == "number" or tonumber(text) then
+		return tonumber(text)
+	elseif kind == "string" then
+		if text:find("^%$Revision: (%d+) %$$") then
+			return tonumber((text:match("^%$Revision: (%d+) %$$")))
+		elseif text:find("^%$Rev: (%d+) %$$") then
+			return tonumber((text:match("^%$Rev: (%d+) %$$")))
+		elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
+			return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
+		end
+	end
+	return nil
+end
+
+local crawlReplace
+do
+	local recurse = {}
+	local function func(t, to, from)
+		if recurse[t] then
+			return
+		end
+		recurse[t] = true
+		local mt = getmetatable(t)
+		setmetatable(t, nil)
+		rawset(t, to, rawget(t, from))
+		rawset(t, from, nil)
+		for k,v in pairs(t) do
+			if v == from then
+				t[k] = to
+			elseif type(v) == "table" then
+				if not recurse[v] then
+					func(v, to, from)
+				end
+			end
+			
+			if type(k) == "table" then
+				if not recurse[k] then
+					func(k, to, from)
+				end
+			end
+		end
+		setmetatable(t, mt)
+		if mt then
+			if mt == from then
+				setmetatable(t, to)
+			elseif not recurse[mt] then
+				func(mt, to, from)
+			end
+		end
+	end
+	function crawlReplace(t, to, from)
+		func(t, to, from)
+		for k in pairs(recurse) do
+			recurse[k] = nil
+		end
+	end
+end
+
+-- @function destroyTable
+-- @brief    remove all the contents of a table
+-- @param t  table to destroy
+local function destroyTable(t)
+	setmetatable(t, nil)
+	for k,v in pairs(t) do
+		t[k] = nil 
+	end
+end
+
+local function isFrame(frame)
+	return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
+end
+
+-- @function   copyTable
+-- @brief      Create a shallow copy of a table and return it.
+-- @param from The table to copy from
+-- @return     A shallow copy of the table
+local function copyTable(from, to)
+	if not to then
+		to = {}
+	end
+	for k,v in pairs(from) do
+		to[k] = v
+	end
+	setmetatable(to, getmetatable(from))
+	return to
+end
+
+-- @function         deepTransfer
+-- @brief            Fully transfer all data, keeping proper previous table
+--                   backreferences stable.
+-- @param to         The table with which data is to be injected into
+-- @param from       The table whose data will be injected into the first
+-- @param saveFields If available, a shallow copy of the basic data is saved
+--                   in here.
+-- @param list       The account of table references
+-- @param list2      The current status on which tables have been traversed.
+local deepTransfer
+do
+	-- @function   examine
+	-- @brief      Take account of all the table references to be shared
+	--             between the to and from tables.
+	-- @param to   The table with which data is to be injected into
+	-- @param from The table whose data will be injected into the first
+	-- @param list An account of the table references
+	local function examine(to, from, list, major)
+		list[from] = to
+		for k,v in pairs(from) do
+			if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
+				if from[k] == to[k] then
+					list[from[k]] = to[k]
+				elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
+					list[from[k]] = from[k]
+				elseif not list[from[k]] then
+					examine(to[k], from[k], list, major)
+				end
+			end
+		end
+		return list
+	end
+	
+	function deepTransfer(to, from, saveFields, major, list, list2)
+		setmetatable(to, nil)
+		if not list then
+			list = {}
+			list2 = {}
+			examine(to, from, list, major)
+		end
+		list2[to] = to
+		for k,v in pairs(to) do
+			if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
+				if saveFields then
+					saveFields[k] = v
+				end
+				to[k] = nil
+			elseif v ~= _G then
+				if saveFields then
+					saveFields[k] = copyTable(v)
+				end
+			end
+		end
+		for k in pairs(from) do
+			if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
+				if not list2[to[k]] then
+					deepTransfer(to[k], from[k], nil, major, list, list2)
+				end
+				to[k] = list[to[k]] or list2[to[k]]
+			else
+				rawset(to, k, from[k])
+			end
+		end
+		setmetatable(to, getmetatable(from))
+		local mt = getmetatable(to)
+		if mt then
+			if list[mt] then
+				setmetatable(to, list[mt])
+			elseif mt.__index and list[mt.__index] then
+				mt.__index = list[mt.__index]
+			end
+		end
+		destroyTable(from)
+	end
+end
+
+local function TryToEnable(addon)
+	if DONT_ENABLE_LIBRARIES then return end
+	local isondemand = IsAddOnLoadOnDemand(addon)
+	if isondemand then
+		local _, _, _, enabled = GetAddOnInfo(addon)
+		EnableAddOn(addon)
+		local _, _, _, _, loadable = GetAddOnInfo(addon)
+		if not loadable and not enabled then
+			DisableAddOn(addon)
+		end
+
+		return loadable
+	end
+end
+
+-- @method      TryToLoadStandalone
+-- @brief       Attempt to find and load a standalone version of the requested library
+-- @param major A string representing the major version
+-- @return      If library is found and loaded, true is return. If not loadable, false is returned.
+--              If the library has been requested previously, nil is returned.
+local function TryToLoadStandalone(major)
+	if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
+	if AceLibrary.scannedlibs[major] then return end
+
+	AceLibrary.scannedlibs[major] = true
+
+	local name, _, _, enabled, loadable = GetAddOnInfo(major)
+	
+	loadable = (enabled and loadable) or TryToEnable(name)
+	
+	local loaded = false
+	if loadable then
+		loaded = true
+		LoadAddOn(name)
+	end
+	
+	local field = "X-AceLibrary-" .. major 
+	for i = 1, GetNumAddOns() do
+		if GetAddOnMetadata(i, field) then
+			name, _, _, enabled, loadable = GetAddOnInfo(i)
+			
+			loadable = (enabled and loadable) or TryToEnable(name)
+			if loadable then
+				loaded = true
+				LoadAddOn(name)
+			end
+		end
+	end
+	return loaded
+end
+
+-- @method      IsNewVersion
+-- @brief       Obtain whether the supplied version would be an upgrade to the
+--              current version. This allows for bypass code in library
+--              declaration.
+-- @param major A string representing the major version
+-- @param minor An integer or an svn revision string representing the minor version
+-- @return      whether the supplied version would be newer than what is
+--              currently available.
+function AceLibrary:IsNewVersion(major, minor)
+	argCheck(self, major, 2, "string")
+	TryToLoadStandalone(major)
+
+	if type(minor) == "string" then
+		local m = svnRevisionToNumber(minor)
+		if m then
+			minor = m
+		else
+			_G.error(("Bad argument #3 to  `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+		end
+	end
+	argCheck(self, minor, 3, "number")
+	local lib, oldMinor = LibStub:GetLibrary(major, true)
+	if lib then
+		return oldMinor < minor
+	end
+	local data = self.libs[major]
+	if not data then
+		return true
+	end
+	return data.minor < minor
+end
+
+-- @method      HasInstance
+-- @brief       Returns whether an instance exists. This allows for optional support of a library.
+-- @param major A string representing the major version.
+-- @param minor (optional) An integer or an svn revision string representing the minor version.
+-- @return      Whether an instance exists.
+function AceLibrary:HasInstance(major, minor)
+	argCheck(self, major, 2, "string")
+	if minor ~= false then
+		TryToLoadStandalone(major)
+	end
+	
+	local lib, ver = LibStub:GetLibrary(major, true)
+	if not lib and self.libs[major] then
+		lib, ver = self.libs[major].instance, self.libs[major].minor
+	end
+	if minor then
+		if type(minor) == "string" then
+			local m = svnRevisionToNumber(minor)
+			if m then
+				minor = m
+			else
+				_G.error(("Bad argument #3 to  `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+			end
+		end
+		argCheck(self, minor, 3, "number")
+		if not lib then
+			return false
+		end
+		return ver == minor
+	end
+	return not not lib
+end
+
+-- @method      GetInstance
+-- @brief       Returns the library with the given major/minor version.
+-- @param major A string representing the major version.
+-- @param minor (optional) An integer or an svn revision string representing the minor version.
+-- @return      The library with the given major/minor version.
+function AceLibrary:GetInstance(major, minor)
+	argCheck(self, major, 2, "string")
+	if minor ~= false then
+		TryToLoadStandalone(major)
+	end
+
+	local data, ver = LibStub:GetLibrary(major, true)
+	if not data then
+		if self.libs[major] then
+			data, ver = self.libs[major].instance, self.libs[major].minor
+		else
+			_G.error(("Cannot find a library instance of %s."):format(major), 2)
+			return
+		end
+	end
+	if minor then
+		if type(minor) == "string" then
+			local m = svnRevisionToNumber(minor)
+			if m then
+				minor = m
+			else
+				_G.error(("Bad argument #3 to  `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+			end
+		end
+		argCheck(self, minor, 2, "number")
+		if ver ~= minor then
+			_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
+		end
+	end
+	return data
+end
+
+-- Syntax sugar.  AceLibrary("FooBar-1.0")
+AceLibrary_mt.__call = AceLibrary.GetInstance
+
+local donothing = function() end
+
+local AceEvent
+
+local tmp = {}
+
+-- @method               Register
+-- @brief                Registers a new version of a given library.
+-- @param newInstance    the library to register
+-- @param major          the major version of the library
+-- @param minor          the minor version of the library
+-- @param activateFunc   (optional) A function to be called when the library is
+--                       fully activated. Takes the arguments
+--                       (newInstance [, oldInstance, oldDeactivateFunc]). If
+--                       oldInstance is given, you should probably call
+--                       oldDeactivateFunc(oldInstance).
+-- @param deactivateFunc (optional) A function to be called by a newer library's
+--                       activateFunc.
+-- @param externalFunc   (optional) A function to be called whenever a new
+--                       library is registered.
+function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
+	argCheck(self, newInstance, 2, "table")
+	argCheck(self, major, 3, "string")
+	if major ~= ACELIBRARY_MAJOR then
+		for k,v in pairs(_G) do
+			if v == newInstance then
+				geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
+			end
+		end
+	end
+	if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
+		_G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
+	end
+	if type(minor) == "string" then
+		local m = svnRevisionToNumber(minor)
+		if m then
+			minor = m
+		else
+			_G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+		end
+	end
+	argCheck(self, minor, 4, "number")
+	if math.floor(minor) ~= minor or minor < 0 then
+		error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
+	end
+	argCheck(self, activateFunc, 5, "function", "nil")
+	argCheck(self, deactivateFunc, 6, "function", "nil")
+	argCheck(self, externalFunc, 7, "function", "nil")
+	if not deactivateFunc then
+		deactivateFunc = donothing
+	end
+	local data = self.libs[major]
+	if not data then
+		-- This is new
+		if LibStub:GetLibrary(major, true) then
+			error(self, "Cannot register library %q. It is already registered with LibStub.", major)
+		end
+		local instance = LibStub:NewLibrary(major, minor)
+		copyTable(newInstance, instance)
+		crawlReplace(instance, instance, newInstance)
+		destroyTable(newInstance)
+		if AceLibrary == newInstance then
+			self = instance
+			AceLibrary = instance
+		end
+		self.libs[major] = {
+			instance = instance,
+			minor = minor,
+			deactivateFunc = deactivateFunc,
+			externalFunc = externalFunc,
+		}
+		rawset(instance, 'GetLibraryVersion', function(self)
+			return major, minor
+		end)
+		if not rawget(instance, 'error') then
+			rawset(instance, 'error', error)
+		end
+		if not WoW22 and not rawget(instance, 'assert') then
+			rawset(instance, 'assert', assert)
+		end
+		if not rawget(instance, 'argCheck') then
+			rawset(instance, 'argCheck', argCheck)
+		end
+		if not rawget(instance, 'pcall') then
+			rawset(instance, 'pcall', pcall)
+		end
+		addToPositions(instance, major)
+		if activateFunc then
+			safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
+			
+--[[			if major ~= ACELIBRARY_MAJOR then
+				for k,v in pairs(_G) do
+					if v == instance then
+						geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
+					end
+				end
+			end]]
+		end
+		
+		if externalFunc then
+			for k, data_instance in LibStub:IterateLibraries() do -- all libraries
+				tmp[k] = data_instance
+			end
+			for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
+				tmp[k] = data.instance
+			end
+			for k, data_instance in pairs(tmp) do
+				if k ~= major then
+					safecall(externalFunc, instance, k, data_instance)
+				end
+				tmp[k] = nil
+			end
+		end
+		
+		for k,data in pairs(self.libs) do -- only Ace libraries
+			if k ~= major and data.externalFunc then
+				safecall(data.externalFunc, data.instance, major, instance)
+			end
+		end
+		if major == "AceEvent-2.0" then
+			AceEvent = instance
+		end
+		if AceEvent then
+			AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
+		end
+		
+		return instance
+	end
+	if minor <= data.minor then
+		-- This one is already obsolete, raise an error.
+		_G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
+		return
+	end
+	local instance = data.instance
+	-- This is an update
+	local oldInstance = {}
+	
+	local libStubInstance = LibStub:GetLibrary(major, true)
+	if not libStubInstance then -- non-LibStub AceLibrary registered the library
+		-- pass
+	elseif libStubInstance ~= instance then	
+		error(self, "Cannot register library %q. It is already registered with LibStub.", major)
+	else
+		LibStub:NewLibrary(major, minor) -- upgrade the minor version
+	end
+	
+	addToPositions(newInstance, major)
+	local isAceLibrary = (AceLibrary == newInstance)
+	local old_error, old_assert, old_argCheck, old_pcall
+	if isAceLibrary then
+		self = instance
+		AceLibrary = instance
+		
+		old_error = instance.error
+		if not WoW22 then
+			old_assert = instance.assert
+		end
+		old_argCheck = instance.argCheck
+		old_pcall = instance.pcall
+		
+		self.error = error
+		if not WoW22 then
+			self.assert = assert
+		end
+		self.argCheck = argCheck
+		self.pcall = pcall
+	end
+	deepTransfer(instance, newInstance, oldInstance, major)
+	crawlReplace(instance, instance, newInstance)
+	local oldDeactivateFunc = data.deactivateFunc
+	data.minor = minor
+	data.deactivateFunc = deactivateFunc
+	data.externalFunc = externalFunc
+	rawset(instance, 'GetLibraryVersion', function()
+		return major, minor
+	end)
+	if not rawget(instance, 'error') then
+		rawset(instance, 'error', error)
+	end
+	if not WoW22 and not rawget(instance, 'assert') then
+		rawset(instance, 'assert', assert)
+	end
+	if not rawget(instance, 'argCheck') then
+		rawset(instance, 'argCheck', argCheck)
+	end
+	if not rawget(instance, 'pcall') then
+		rawset(instance, 'pcall', pcall)
+	end
+	if isAceLibrary then
+		for _,v in pairs(self.libs) do
+			local i = type(v) == "table" and v.instance
+			if type(i) == "table" then
+				if not rawget(i, 'error') or i.error == old_error then
+					rawset(i, 'error', error)
+				end
+				if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then
+					rawset(i, 'assert', assert)
+				end
+				if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
+					rawset(i, 'argCheck', argCheck)
+				end
+				if not rawget(i, 'pcall') or i.pcall == old_pcall then
+					rawset(i, 'pcall', pcall)
+				end
+			end
+		end
+	end
+	if activateFunc then
+		safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)	
+				
+--[[		if major ~= ACELIBRARY_MAJOR then
+			for k,v in pairs(_G) do
+				if v == instance then
+					geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
+				end
+			end
+		end]]
+	else
+		safecall(oldDeactivateFunc, oldInstance)
+	end
+	oldInstance = nil
+	
+	if externalFunc then
+		for k, data_instance in LibStub:IterateLibraries() do -- all libraries
+			tmp[k] = data_instance
+		end
+		for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
+			tmp[k] = data.instance
+		end
+		for k, data_instance in pairs(tmp) do
+			if k ~= major then
+				safecall(externalFunc, instance, k, data_instance)
+			end
+			tmp[k] = nil
+		end
+	end
+	
+	return instance
+end
+
+function AceLibrary:IterateLibraries()
+	local t = {}
+	for major, instance in LibStub:IterateLibraries() do
+		t[major] = instance
+	end
+	for major, data in pairs(self.libs) do
+		t[major] = data.instance
+	end
+	return pairs(t)
+end
+
+local function manuallyFinalize(major, instance)
+	if AceLibrary.libs[major] then
+		-- don't work on Ace libraries
+		return
+	end
+	local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
+	if finalizedExternalLibs[major] then
+		return
+	end
+	finalizedExternalLibs[major] = true
+	
+	for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
+		if k ~= major and data.externalFunc then
+			safecall(data.externalFunc, data.instance, major, instance)
+		end
+	end
+end
+
+-- @function            Activate
+-- @brief               The activateFunc for AceLibrary itself. Called when
+--                      AceLibrary properly registers.
+-- @param self          Reference to AceLibrary
+-- @param oldLib        (optional) Reference to an old version of AceLibrary
+-- @param oldDeactivate (optional) Function to deactivate the old lib
+local function activate(self, oldLib, oldDeactivate)
+	AceLibrary = self
+	if not self.libs then
+		self.libs = oldLib and oldLib.libs or {}
+		self.scannedlibs = oldLib and oldLib.scannedlibs or {}
+	end
+	if not self.positions then
+		self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
+	end
+	self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
+	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
+	self.frame:UnregisterAllEvents()
+	self.frame:RegisterEvent("ADDON_LOADED")
+	self.frame:SetScript("OnEvent", function()
+		for major, instance in LibStub:IterateLibraries() do
+			manuallyFinalize(major, instance)
+		end
+	end)
+	for major, instance in LibStub:IterateLibraries() do
+		manuallyFinalize(major, instance)
+	end
+	
+	-- Expose the library in the global environment
+	_G[ACELIBRARY_MAJOR] = self
+	
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+if not previous then
+	previous = AceLibrary
+end
+if not previous.libs then
+	previous.libs = {}
+end
+AceLibrary.libs = previous.libs
+if not previous.positions then
+	previous.positions = setmetatable({}, { __mode = "k" })
+end
+AceLibrary.positions = previous.positions
+AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,10 @@
+## Interface: 20200
+
+## Title: Lib: AceLibrary
+## Notes: AddOn development framework
+## Author: Ace Development Team
+## X-Website: http://www.wowace.com
+## X-Category: Library
+## X-License: LGPL v2.1 + MIT for AceOO-2.0
+ 
+AceLibrary.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceOO-2.0/AceOO-2.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,980 @@
+--[[
+Name: AceOO-2.0
+Revision: $Rev: 38641 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Ace 1.x by Turan (turan@gryphon.com)
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/index.php/AceOO-2.0
+SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0
+Description: Library to provide an object-orientation framework.
+Dependencies: AceLibrary
+License: MIT
+]]
+
+local MAJOR_VERSION = "AceOO-2.0"
+local MINOR_VERSION = "$Revision: 38641 $"
+
+-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+local AceOO = {
+	error = AceLibrary.error,
+	argCheck = AceLibrary.argCheck
+}
+
+-- @function	getuid
+-- @brief		Obtain a unique string identifier for the object in question.
+-- @param t		The object to obtain the uid for.
+-- @return		The uid string.
+local function getuid(t)
+	local mt = getmetatable(t)
+	setmetatable(t, nil)
+	local str = tostring(t)
+	setmetatable(t, mt)
+	local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$")
+	if cap then
+		return ("0"):rep(8 - #cap) .. cap
+	end
+end
+
+local function getlibrary(o)
+	if type(o) == "table" then
+		return o
+	elseif type(o) == "string" then
+		if not AceLibrary:HasInstance(o) then
+			AceOO:error("Library %q does not exist.", o)
+		end
+		return AceLibrary(o)
+	end
+end
+
+local function deeprawget(self, k)
+	while true do
+		local v = rawget(self, k)
+		if v ~= nil then
+			return v
+		end
+		local mt = getmetatable(self)
+		if not mt or type(mt.__index) ~= "table" then
+			return nil
+		end
+		self = mt.__index
+	end
+end
+
+-- @function		Factory
+-- @brief			Construct a factory for the creation of objects.
+-- @param obj		The object whose init method will be called on the new factory
+--					object.
+-- @param newobj	The object whose init method will be called on the new
+--					objects that the Factory creates, to initialize them.
+-- @param (...) Arguments which will be passed to obj.init() in addition
+--					to the Factory object.
+-- @return			The new factory which creates a newobj when its new method is called,
+--					or when it is called directly (__call metamethod).
+local Factory
+do
+	local function getlibraries(...)
+		if select('#', ...) == 0 then
+			return
+		end
+		return getlibrary((select(1, ...))), getlibraries(select(2, ...))
+	end
+	local arg = {}
+	local function new(obj, ...)
+		local t = {}
+		local uid = getuid(t)
+		obj:init(t, getlibraries(...))
+		t.uid = uid
+		return t
+	end
+	
+	local function createnew(self, ...)
+		local o = self.prototype
+		local x = new(o, getlibraries(...))
+		return x
+	end
+
+	function Factory(obj, newobj, ...)
+		local t = new(obj, ...)
+		t.prototype = newobj
+		t.new = createnew
+		getmetatable(t).__call = t.new
+		return t
+	end
+end
+
+
+local function objtostring(self)
+	if self.ToString then
+		return self:ToString()
+	elseif self.GetLibraryVersion then
+		return (self:GetLibraryVersion())
+	elseif self.super then
+		local s = "Sub-" .. tostring(self.super)
+		local first = true
+		if self.interfaces then
+			for interface in pairs(self.interfaces) do
+				if first then
+					s = s .. "(" .. tostring(interface)
+					first = false
+				else
+					s = s .. ", " .. tostring(interface)
+				end
+			end
+		end
+		if self.mixins then
+			for mixin in pairs(self.mixins) do
+				if first then
+					s = s .. tostring(mixin)
+					first = false
+				else
+					s = s .. ", " .. tostring(mixin)
+				end
+			end
+		end
+		if first then
+			if self.uid then
+				return s .. ":" .. self.uid
+			else
+				return s
+			end
+		else
+			return s .. ")"
+		end
+	else
+		return self.uid and 'Subclass:' .. self.uid or 'Subclass'
+	end
+end
+
+-- @table			Object
+-- @brief			Base of all objects, including Class.
+--
+-- @method			init
+-- @brief			Initialize a new object.
+-- @param newobject The object to initialize
+-- @param class		The class to make newobject inherit from
+local Object
+do
+	Object = {}
+	function Object:init(newobject, class)
+		local parent = class or self
+		if not rawget(newobject, 'uid') then
+			newobject.uid = getuid(newobject)
+		end
+		local mt = {
+			__index = parent,
+			__tostring = objtostring,
+		}
+		setmetatable(newobject, mt)
+	end
+	Object.uid = getuid(Object)
+	setmetatable(Object, { __tostring = function() return 'Object' end })
+end
+
+local Interface
+
+local function validateInterface(object, interface)
+	if not object.class and object.prototype then
+		object = object.prototype
+	end
+	for k,v in pairs(interface.interface) do
+		if tostring(type(object[k])) ~= v then
+			return false
+		end
+	end
+	if interface.superinterfaces then
+		for superinterface in pairs(interface.superinterfaces) do
+			if not validateInterface(object, superinterface) then
+				return false
+			end
+		end
+	end
+	if type(object.class) == "table" and rawequal(object.class.prototype, object) then
+		if not object.class.interfaces then
+			rawset(object.class, 'interfaces', {})
+		end
+		object.class.interfaces[interface] = true
+	elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
+		validateInterface(object.class.prototype, interface)
+		-- check if class is proper, thus preventing future checks.
+	end
+	return true
+end
+
+-- @function		inherits
+-- @brief			Return whether an Object or Class inherits from a given
+--					parent.
+-- @param object	Object or Class to check
+-- @param parent	Parent to test inheritance from
+-- @return			whether an Object or Class inherits from a given
+--					parent.
+local function inherits(object, parent)
+	object = getlibrary(object)
+	if type(parent) == "string" then
+		if not AceLibrary:HasInstance(parent) then
+			return false
+		else
+			parent = AceLibrary(parent)
+		end
+	end
+	AceOO:argCheck(parent, 2, "table")
+	if type(object) ~= "table" then
+		return false
+	end
+	local current
+	local class = deeprawget(object, 'class')
+	if class then
+		current = class
+	else
+		current = object
+	end
+	if type(current) ~= "table" then
+		return false
+	end
+	if rawequal(current, parent) then
+		return true
+	end
+	if parent.class then
+		while true do
+			if rawequal(current, Object) then
+				break
+			end
+			if current.mixins then
+				for mixin in pairs(current.mixins) do
+					if rawequal(mixin, parent) then
+						return true
+					end
+				end
+			end
+			if current.interfaces then
+				for interface in pairs(current.interfaces) do
+					if rawequal(interface, parent) then
+						return true
+					end
+				end
+			end
+			current = deeprawget(current, 'super')
+			if type(current) ~= "table" then
+				break
+			end
+		end
+		
+		local isInterface = false
+		local curr = parent.class
+		while true do
+			if rawequal(curr, Object) then
+				break
+			elseif rawequal(curr, Interface) then
+				isInterface = true
+				break
+			end
+			curr = deeprawget(curr, 'super')
+			if type(curr) ~= "table" then
+				break
+			end
+		end
+		return isInterface and validateInterface(object, parent)
+	else
+		while true do
+			if rawequal(current, parent) then
+				return true
+			elseif rawequal(current, Object) then
+				return false
+			end
+			current = deeprawget(current, 'super')
+			if type(current) ~= "table" then
+				return false
+			end
+		end
+	end
+end
+
+-- @table			Class
+-- @brief			An object factory which sets up inheritence and supports
+--					'mixins'.
+--
+-- @metamethod		Class call
+-- @brief			Call ClassFactory:new() to create a new class.
+--
+-- @method			Class new
+-- @brief			Construct a new object.
+-- @param (...) Arguments to pass to the object init function.
+-- @return			The new object.
+--
+-- @method			Class init
+-- @brief			Initialize a new class.
+-- @param parent	Superclass.
+-- @param (...) Mixins.
+--
+-- @method			Class ToString
+-- @return			A string representing the object, in this case 'Class'.
+local initStatus
+local Class
+local Mixin
+local autoEmbed = false
+local function traverseInterfaces(bit, total)
+	if bit.superinterfaces then
+		for interface in pairs(bit.superinterfaces) do
+			if not total[interface] then
+				total[interface] = true
+				traverseInterfaces(interface, total)
+			end
+		end
+	end
+end
+local class_new
+do
+	Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
+	Class.super = Object
+	
+	local function protostring(t)
+		return '<' .. tostring(t.class) .. ' prototype>'
+	end
+	local function classobjectstring(t)
+		if t.ToString then
+			return t:ToString()
+		elseif t.GetLibraryVersion then
+			return (t:GetLibraryVersion())
+		else
+			return '<' .. tostring(t.class) .. ' instance>'
+		end
+	end
+	local function classobjectequal(self, other)
+		if type(self) == "table" and self.Equals then
+			return self:Equals(other)
+		elseif type(other) == "table" and other.Equals then
+			return other:Equals(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) == 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) == 0
+		else
+			return rawequal(self, other)
+		end
+	end
+	local function classobjectlessthan(self, other)
+		if type(self) == "table" and self.IsLessThan then
+			return self:IsLessThan(other)
+		elseif type(other) == "table" and other.IsLessThanOrEqualTo then
+			return not other:IsLessThanOrEqualTo(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) < 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) > 0
+		elseif type(other) == "table" and other.IsLessThan and other.Equals then
+			return other:Equals(self) or other:IsLessThan(self)
+		else
+			AceOO:error("cannot compare two objects")
+		end
+	end
+	local function classobjectlessthanequal(self, other)
+		if type(self) == "table" and self.IsLessThanOrEqualTo then
+			return self:IsLessThanOrEqualTo(other)
+		elseif type(other) == "table" and other.IsLessThan then
+			return not other:IsLessThan(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) <= 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) >= 0
+		elseif type(self) == "table" and self.IsLessThan and self.Equals then
+			return self:Equals(other) or self:IsLessThan(other)
+		else
+			AceOO:error("cannot compare two incompatible objects")
+		end
+	end
+	local function classobjectadd(self, other)
+		if type(self) == "table" and self.Add then
+			return self:Add(other)
+		else
+			AceOO:error("cannot add two incompatible objects")
+		end
+	end
+	local function classobjectsub(self, other)
+		if type(self) == "table" and self.Subtract then
+			return self:Subtract(other)
+		else
+			AceOO:error("cannot subtract two incompatible objects")
+		end
+	end
+	local function classobjectunm(self, other)
+		if type(self) == "table" and self.UnaryNegation then
+			return self:UnaryNegation(other)
+		else
+			AceOO:error("attempt to negate an incompatible object")
+		end
+	end
+	local function classobjectmul(self, other)
+		if type(self) == "table" and self.Multiply then
+			return self:Multiply(other)
+		else
+			AceOO:error("cannot multiply two incompatible objects")
+		end
+	end
+	local function classobjectdiv(self, other)
+		if type(self) == "table" and self.Divide then
+			return self:Divide(other)
+		else
+			AceOO:error("cannot divide two incompatible objects")
+		end
+	end
+	local function classobjectpow(self, other)
+		if type(self) == "table" and self.Exponent then
+			return self:Exponent(other)
+		else
+			AceOO:error("cannot exponentiate two incompatible objects")
+		end
+	end
+	local function classobjectconcat(self, other)
+		if type(self) == "table" and self.Concatenate then
+			return self:Concatenate(other)
+		else
+			AceOO:error("cannot concatenate two incompatible objects")
+		end
+	end
+	function class_new(self, ...)
+		if self.virtual then
+			AceOO:error("Cannot instantiate a virtual class.")
+		end
+		
+		local o = self.prototype
+		local newobj = {}
+		if o.class and o.class.instancemeta then
+			setmetatable(newobj, o.class.instancemeta)
+		else
+			Object:init(newobj, o)
+		end
+		
+		if self.interfaces and not self.interfacesVerified then
+			-- Verify the interfaces
+			
+			for interface in pairs(self.interfaces) do
+				for field,kind in pairs(interface.interface) do
+					if tostring(type(newobj[field])) ~= kind then
+						AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field])))
+					end
+				end
+			end
+			self.interfacesVerified = true
+		end
+		local tmp = initStatus
+		initStatus = newobj
+		newobj:init(...)
+		if initStatus then
+			initStatus = tmp
+			AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
+			return
+		end
+		initStatus = tmp
+		return newobj
+	end
+	local classmeta = {
+		__tostring = objtostring,
+		__call = function(self, ...)
+			return self:new(...)
+		end,
+	}
+	function Class:init(newclass, parent, ...)
+		parent = parent or self
+		
+		local total
+		
+		if parent.class then
+			total = { parent, ... }
+			parent = self
+		else
+			total = { ... }
+		end
+		if not inherits(parent, Class) then
+			AceOO:error("Classes must inherit from a proper class")
+		end
+		if parent.sealed then
+			AceOO:error("Cannot inherit from a sealed class")
+		end
+		for i,v in ipairs(total) do
+			if inherits(v, Mixin) and v.class then
+				if v.__deprecated then
+					AceOO:error(v.__deprecated)
+				end
+				if not newclass.mixins then
+					newclass.mixins = {}
+				end
+				if newclass.mixins[v] then
+					AceOO:error("Cannot explicitly inherit from the same mixin twice")
+				end
+				newclass.mixins[v] = true
+			elseif inherits(v, Interface) and v.class then
+				if not newclass.interfaces then
+					newclass.interfaces = {}
+				end
+				if newclass.interfaces[v] then
+					AceOO:error("Cannot explicitly inherit from the same interface twice")
+				end
+				newclass.interfaces[v] = true
+			else
+				AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
+			end
+		end
+		if parent.interfaces then
+			if not newclass.interfaces then
+				newclass.interfaces = {}
+			end
+			for interface in pairs(parent.interfaces) do
+				newclass.interfaces[interface] = true
+			end
+		end
+		for k in pairs(total) do
+			total[k] = nil
+		end
+		
+		newclass.super = parent
+		
+		newclass.prototype = setmetatable(total, {
+			__index = parent.prototype,
+			__tostring = protostring,
+		})
+		total = nil
+		
+		newclass.instancemeta = {
+			__index = newclass.prototype,
+			__tostring = classobjectstring,
+			__eq = classobjectequal,
+			__lt = classobjectlessthan,
+			__le = classobjectlessthanequal,
+			__add = classobjectadd,
+			__sub = classobjectsub,
+			__unm = classobjectunm,
+			__mul = classobjectmul,
+			__div = classobjectdiv,
+			__pow = classobjectpow,
+			__concat = classobjectconcat,
+		}
+		
+		setmetatable(newclass, classmeta)
+		
+		newclass.new = class_new
+		
+		if newclass.mixins then
+			-- Fold in the mixins
+			local err, msg
+			for mixin in pairs(newclass.mixins) do
+				local ret
+				autoEmbed = true
+				ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
+				autoEmbed = false
+				if not ret then
+					err = true
+					break
+				end
+			end
+	
+			if err then
+				local pt = newclass.prototype
+				for k,v in pairs(pt) do
+					pt[k] = nil
+				end
+	
+				-- method conflict
+				AceOO:error(msg)
+			end
+		end
+		
+		newclass.prototype.class = newclass
+		
+		if newclass.interfaces then
+			for interface in pairs(newclass.interfaces) do
+				traverseInterfaces(interface, newclass.interfaces)
+			end
+		end
+		if newclass.mixins then
+			for mixin in pairs(newclass.mixins) do
+				if mixin.interfaces then
+					if not newclass.interfaces then
+						newclass.interfaces = {}
+					end
+					for interface in pairs(mixin.interfaces) do
+						newclass.interfaces[interface] = true
+					end
+				end
+			end
+		end
+	end
+	function Class:ToString()
+		if type(self.GetLibraryVersion) == "function" then
+			return (self:GetLibraryVersion())
+		else
+			return "Class"
+		end
+	end
+	
+	local tmp
+	function Class.prototype:init()
+		if rawequal(self, initStatus) then
+			initStatus = nil
+		else
+			AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
+		end
+		self.uid = getuid(self)
+		local current = self.class
+		while true do
+			if current == Class then
+				break
+			end
+			if current.mixins then
+				for mixin in pairs(current.mixins) do
+					if type(mixin.OnInstanceInit) == "function" then
+						mixin:OnInstanceInit(self)
+					end
+				end
+			end
+			current = current.super
+		end
+	end
+end
+
+
+-- @object	ClassFactory
+-- @brief	A factory for creating classes.	Rarely used directly.
+local ClassFactory = Factory(Object, Class, Object)
+
+function Class:new(...)
+	local x = ClassFactory:new(...)
+	if AceOO.classes then
+		AceOO.classes[x] = true
+	end
+	return x
+end
+getmetatable(Class).__call = Class.new
+
+-- @class	Mixin
+-- @brief	A class to create mixin objects, which contain methods that get
+-- "mixed in" to class prototypes.
+--
+-- @object	Mixin prototype
+-- @brief	The prototype that mixin objects inherit their methods from.
+--
+-- @method	Mixin prototype embed
+-- @brief	Mix in the methods of our object which are listed in our interface
+--		 to the supplied target table.
+--
+-- @method	Mixin prototype init
+-- @brief	Initialize the mixin object.
+-- @param	newobj	 The new object we're initializing.
+-- @param	interface	The interface we implement (the list of methods our
+--					prototype provides which should be mixed into the target
+--					table by embed).
+do
+	Mixin = Class()
+	function Mixin:ToString()
+		if self.GetLibraryVersion then
+			return (self:GetLibraryVersion())
+		else
+			return 'Mixin'
+		end
+	end
+	local function _Embed(state, field, target)
+		field = next(state.export, field)
+		if field == nil then
+			return
+		end
+
+		if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
+			AceOO:error("Method conflict in attempt to mixin. Field %q", field)
+		end
+
+		target[field] = state[field]
+
+		local ret,msg = pcall(_Embed, state, field, target)
+		if not ret then
+			-- Mix in the next method according to the defined interface.	If that
+			-- fails due to a conflict, re-raise to back out the previous mixed
+			-- methods.
+
+			target[field] = nil
+			AceOO:error(msg)
+		end
+	end
+	function Mixin.prototype:embed(target)
+		if self.__deprecated then
+			AceOO:error(self.__deprecated)
+		end
+		local mt = getmetatable(target)
+		setmetatable(target, nil)
+		local err, msg = pcall(_Embed, self, nil, target)
+		if not err then
+			setmetatable(target, mt)
+			AceOO:error(msg)
+			return
+		end
+		if type(self.embedList) == "table" then
+			self.embedList[target] = true
+		end
+		if type(target.class) ~= "table" then
+			target[self] = true
+		end
+		if not autoEmbed and type(self.OnManualEmbed) == "function" then
+			self:OnManualEmbed(target)
+		end
+		setmetatable(target, mt)
+	end
+	
+	function Mixin.prototype:activate(oldLib, oldDeactivate)
+		if oldLib and oldLib.embedList then
+			for target in pairs(oldLib.embedList) do
+				local mt = getmetatable(target)
+				setmetatable(target, nil)
+				for field in pairs(oldLib.export) do
+					target[field] = nil
+				end
+				setmetatable(target, mt)
+			end
+			self.embedList = oldLib.embedList
+			for target in pairs(self.embedList) do
+				self:embed(target)
+			end
+		else
+			self.embedList = setmetatable({}, {__mode="k"})
+		end
+	end
+	
+	function Mixin.prototype:init(export, ...)
+		AceOO:argCheck(export, 2, "table")
+		for k,v in pairs(export) do
+			if type(k) ~= "number" then
+				AceOO:error("All keys to argument #2 must be numbers.")
+			elseif type(v) ~= "string" then
+				AceOO:error("All values to argument #2 must be strings.")
+			end
+		end
+		local num = #export
+		for i = 1, num do
+			local v = export[i]
+			export[i] = nil
+			export[v] = true
+		end
+		
+		local interfaces
+		if select('#', ...) >= 1 then
+			interfaces = { ... }
+			for i,v in ipairs(interfaces) do
+				v = getlibrary(v)
+				interfaces[i] = v
+				if not v.class or not inherits(v, Interface) then
+					AceOO:error("Mixins can inherit only from interfaces")
+				end
+			end
+			local num = #interfaces
+			for i = 1, num do
+				local v = interfaces[i]
+				interfaces[i] = nil
+				interfaces[v] = true
+			end
+			for interface in pairs(interfaces) do
+				traverseInterfaces(interface, interfaces)
+			end
+			for interface in pairs(interfaces) do
+				for field,kind in pairs(interface.interface) do
+					if kind ~= "nil" then
+						local good = false
+						for bit in pairs(export) do
+							if bit == field then
+								good = true
+								break
+							end
+						end
+						if not good then
+							AceOO:error("Mixin does not fully accommodate field %q", field)
+						end
+					end
+				end
+			end
+		end
+		self.super = Mixin.prototype
+		Mixin.super.prototype.init(self)
+		self.export = export
+		self.interfaces = interfaces
+	end
+end
+
+-- @class Interface
+-- @brief A class to create interfaces, which contain contracts that classes
+--			which inherit from this must comply with.
+--
+-- @object Interface prototype
+-- @brief	The prototype that interface objects must adhere to.
+--
+-- @method Interface prototype init
+-- @brief	Initialize the mixin object.
+-- @param	interface	The interface we contract (the hash of fields forced).
+-- @param	(...)	Superinterfaces
+do
+	Interface = Class()
+	function Interface:ToString()
+		if self.GetLibraryVersion then
+			return (self:GetLibraryVersion())
+		else
+			return 'Instance'
+		end
+	end
+	function Interface.prototype:init(interface, ...)
+		Interface.super.prototype.init(self)
+		AceOO:argCheck(interface, 2, "table")
+		for k,v in pairs(interface) do
+			if type(k) ~= "string" then
+				AceOO:error("All keys to argument #2 must be numbers.")
+			elseif type(v) ~= "string" then
+				AceOO:error("All values to argument #2 must be strings.")
+			elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
+				AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
+			end
+		end
+		if select('#', ...) >= 1 then
+			self.superinterfaces = { ... }
+			for i,v in ipairs(self.superinterfaces) do
+				v = getlibrary(v)
+				self.superinterfaces[i] = v
+				if not inherits(v, Interface) or not v.class then
+					AceOO:error('Cannot provide a non-Interface to inherit from')
+				end
+			end
+			local num = #self.superinterfaces
+			for i = 1, num do
+				local v = self.superinterfaces[i]
+				self.superinterfaces[i] = nil
+				self.superinterfaces[v] = true
+			end
+		end
+		self.interface = interface
+	end
+end
+
+-- @function Classpool
+-- @brief	Obtain a read only class from our pool of classes, indexed by the
+--		 superclass and mixins.
+-- @param	sc		 The superclass of the class we want.
+-- @param	(m1..m20)	Mixins of the class we want's objects.
+-- @return A read only class from the class pool.
+local Classpool
+do
+	local pool = setmetatable({}, {__mode = 'v'})
+	local function newindex(k, v)
+		AceOO:error('Attempt to modify a read-only class.')
+	end
+	local function protonewindex(k, v)
+		AceOO:error('Attempt to modify a read-only class prototype.')
+	end
+	local function ts(bit)
+		if type(bit) ~= "table" then
+			return tostring(bit)
+		elseif getmetatable(bit) and bit.__tostring then
+			return tostring(bit)
+		elseif type(bit.GetLibraryVersion) == "function" then
+			return bit:GetLibraryVersion()
+		else
+			return tostring(bit)
+		end
+	end
+	local t = {}
+	local function getcomplexuid(sc, ...)
+		if sc then
+			if sc.uid then
+				table.insert(t, sc.uid)
+			else
+				AceOO:error("%s is not an appropriate class/mixin", ts(sc))
+			end
+		end
+		for i = 1, select('#', ...) do
+			local m = select(i, ...)
+			if m.uid then
+				table.insert(t, m.uid)
+			else
+				AceOO:error("%s is not an appropriate mixin", ts(m))
+			end
+		end
+		table.sort(t)
+		local uid = table.concat(t, '')
+		local num = #t
+		for i = 1, num do
+			t[i] = nil
+		end
+		return uid
+	end
+	local classmeta
+	local arg = {}
+	function Classpool(superclass, ...)
+		local l = getlibrary
+		superclass = getlibrary(superclass)
+		arg = { ... }
+		for i, v in ipairs(arg) do
+			arg[i] = getlibrary(v)
+		end
+		if superclass then
+			if superclass.class then -- mixin
+				table.insert(arg, 1, superclass)
+				superclass = Class
+			end
+		else
+			superclass = Class
+		end
+		local key = getcomplexuid(superclass, unpack(arg))
+		if not pool[key] then
+			local class = Class(superclass, unpack(arg))
+			if not classmeta then
+				classmeta = {}
+				local mt = getmetatable(class)
+				for k,v in pairs(mt) do
+					classmeta[k] = v
+				end
+				classmeta.__newindex = newindex
+			end
+			-- Prevent the user from adding methods to this class.
+			-- NOTE: I'm not preventing modifications of existing class members,
+			-- but it's likely that only a truly malicious user will be doing so.
+			class.sealed = true
+			setmetatable(class, classmeta)
+			getmetatable(class.prototype).__newindex = protonewindex
+			pool[key] = class
+		end
+		return pool[key]
+	end
+end
+
+AceOO.Factory = Factory
+AceOO.Object = Object
+AceOO.Class = Class
+AceOO.Mixin = Mixin
+AceOO.Interface = Interface
+AceOO.Classpool = Classpool
+AceOO.inherits = inherits
+
+-- Library handling bits
+
+local function activate(self, oldLib, oldDeactivate)
+	AceOO = self
+	Factory = self.Factory
+	Object = self.Object
+	Class = self.Class
+	ClassFactory.prototype = Class
+	Mixin = self.Mixin
+	Interface = self.Interface
+	Classpool = self.Classpool
+	
+	if oldLib then
+		self.classes = oldLib.classes
+	end
+	if not self.classes then
+		self.classes = setmetatable({}, {__mode="k"})
+	else
+		for class in pairs(self.classes) do
+			class.new = class_new
+		end
+	end
+	
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
+AceOO = AceLibrary(MAJOR_VERSION)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/AceOO-2.0/AceOO-2.0.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,12 @@
+## Interface: 20200
+
+## Title: Lib: AceOO-2.0
+## Notes: AddOn development framework
+## Author: Ace Development Team
+## LoadOnDemand: 1
+## X-Website: http://www.wowace.com
+## X-Category: Library
+## X-License: LGPL v2.1 + MIT for AceOO-2.0
+## Dependencies: AceLibrary
+ 
+AceOO-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/FuBar_ReActionFu/lib/Dewdrop-2.0/Dewdrop-2.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,3487 @@
+--[[
+Name: Dewdrop-2.0
+Revision: $Rev: 48630 $
+Author(s): ckknight (ckknight@gmail.com)
+Website: http://ckknight.wowinterface.com/
+Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0
+SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0
+Description: A library to provide a clean dropdown menu interface.
+Dependencies: AceLibrary
+License: LGPL v2.1
+]]
+
+local MAJOR_VERSION = "Dewdrop-2.0"
+local MINOR_VERSION = "$Revision: 48630 $"
+
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+local Dewdrop = {}
+
+local SharedMedia
+
+local CLOSE = "Close"
+local CLOSE_DESC = "Close the menu."
+local VALIDATION_ERROR = "Validation error."
+local USAGE_TOOLTIP = "Usage: %s."
+local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one."
+local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding."
+local KEY_BUTTON1 = "Left Mouse"
+local KEY_BUTTON2 = "Right Mouse"
+local DISABLED = "Disabled"
+local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?"
+
+if GetLocale() == "deDE" then
+	CLOSE = "Schlie\195\159en"
+	CLOSE_DESC = "Men\195\188 schlie\195\159en."
+	VALIDATION_ERROR = "Validierungsfehler."
+	USAGE_TOOLTIP = "Benutzung: %s."
+	RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen."
+	RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen."
+	KEY_BUTTON1 = "Linke Maustaste"
+	KEY_BUTTON2 = "Rechte Maustaste"
+	DISABLED = "Deaktiviert"
+	DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?"
+elseif GetLocale() == "koKR" then
+	CLOSE = "닫기"
+	CLOSE_DESC = "메뉴를 닫습니다."
+	VALIDATION_ERROR = "오류 확인."
+	USAGE_TOOLTIP = "사용법: %s."
+	RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다."
+	RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요."
+	KEY_BUTTON1 = "왼쪽 마우스"
+	KEY_BUTTON2 = "오른쪽 마우스"
+	DISABLED = "비활성화됨"
+	DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?"
+elseif GetLocale() == "frFR" then
+	CLOSE = "Fermer"
+	CLOSE_DESC = "Ferme le menu."
+	VALIDATION_ERROR = "Erreur de validation."
+	USAGE_TOOLTIP = "Utilisation : %s."
+	RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement."
+	RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci."
+	KEY_BUTTON1 = "Clic gauche"
+	KEY_BUTTON2 = "Clic droit"
+	DISABLED = "D\195\169sactiv\195\169"
+	DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?"
+elseif GetLocale() == "esES" then
+	CLOSE = "Cerrar"
+	CLOSE_DESC = "Cierra el menú."
+	VALIDATION_ERROR = "Error de validación."
+	USAGE_TOOLTIP = "Uso: %s."
+	RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador."
+	RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla."
+	KEY_BUTTON1 = "Clic Izquierdo"
+	KEY_BUTTON2 = "Clic Derecho"
+	DISABLED = "Desactivado"
+	DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?"
+elseif GetLocale() == "zhTW" then
+	CLOSE = "關閉"
+	CLOSE_DESC = "關閉選單。"
+	VALIDATION_ERROR = "驗證錯誤。"
+	USAGE_TOOLTIP = "用法: %s。"
+	RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。"
+	RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。"
+	KEY_BUTTON1 = "滑鼠左鍵"
+	KEY_BUTTON2 = "滑鼠右鍵"
+	DISABLED = "停用"
+	DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?"
+elseif GetLocale() == "zhCN" then
+	CLOSE = "关闭"
+	CLOSE_DESC = "关闭菜单"
+	VALIDATION_ERROR = "验证错误."
+	USAGE_TOOLTIP = "用法: %s."
+	RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页."
+	RESET_KEYBINDING_DESC = "按ESC键清除按键绑定"
+	KEY_BUTTON1 = "鼠标左键"
+	KEY_BUTTON2 = "鼠标右键"
+	DISABLED = "禁用"
+	DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?"
+end
+
+Dewdrop.KEY_BUTTON1 = KEY_BUTTON1
+Dewdrop.KEY_BUTTON2 = KEY_BUTTON2
+
+local function new(...)
+	local t = {}
+	for i = 1, select('#', ...), 2 do
+		local k = select(i, ...)
+		if k then
+			t[k] = select(i+1, ...)
+		else
+			break
+		end
+	end
+	return t
+end
+
+local tmp
+do
+	local t = {}
+	function tmp(...)
+		for k in pairs(t) do
+			t[k] = nil
+		end
+		for i = 1, select('#', ...), 2 do
+			local k = select(i, ...)
+			if k then
+				t[k] = select(i+1, ...)
+			else
+				break
+			end
+		end
+		return t
+	end
+end
+local tmp2
+do
+	local t = {}
+	function tmp2(...)
+		for k in pairs(t) do
+			t[k] = nil
+		end
+		for i = 1, select('#', ...), 2 do
+			local k = select(i, ...)
+			if k then
+				t[k] = select(i+1, ...)
+			else
+				break
+			end
+		end
+		return t
+	end
+end
+local levels
+local buttons
+
+
+-- Secure frame handling:
+-- Rather than using secure buttons in the menu (has problems), we have one
+-- master secureframe that we pop onto menu items on mouseover. This requires
+-- some dark magic with OnLeave etc, but it's not too bad.
+
+local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate")
+secureFrame:Hide()
+
+local function secureFrame_Show(self)
+  local owner = self.owner
+
+  if self.secure then	-- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..)
+	  for k,v in pairs(self.secure) do
+	    self:SetAttribute(k, nil)
+	  end
+  end
+  self.secure = owner.secure;	-- Grab hold of new secure data
+
+  local scale = owner:GetEffectiveScale()
+
+  self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale)
+  self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale)
+  self:EnableMouse(true)
+  for k,v in pairs(self.secure) do
+    self:SetAttribute(k, v)
+  end
+
+	secureFrame:SetFrameStrata(owner:GetFrameStrata())
+	secureFrame:SetFrameLevel(owner:GetFrameLevel()+1)
+
+  self:Show()
+end
+
+local function secureFrame_Hide(self)
+  self:Hide()
+  if self.secure then
+	  for k,v in pairs(self.secure) do
+	    self:SetAttribute(k, nil)
+	  end
+	end
+  self.secure = nil
+end
+
+secureFrame:SetScript("OnEvent",
+	function()
+		if event=="PLAYER_REGEN_ENABLED" then
+			this.combat = false
+			if not this:IsShown() and this.owner then
+				secureFrame_Show(this)
+			end
+		elseif event=="PLAYER_REGEN_DISABLED" then
+			this.combat = true
+			if this:IsShown() then
+				secureFrame_Hide(this)
+			end
+		end
+	end
+)
+secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
+secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
+
+secureFrame:SetScript("OnLeave",
+	function()
+		local owner=this.owner
+		this:Deactivate()
+		owner:GetScript("OnLeave")()
+	end
+)
+
+secureFrame:HookScript("OnClick",
+	function()
+		local realthis = this
+		this = this.owner
+		this:GetScript("OnClick")()
+	end
+)
+
+function secureFrame:IsOwnedBy(frame)
+	return self.owner == frame
+end
+
+function secureFrame:Activate(owner)
+	if self.owner then		-- "Shouldn't" happen but apparently it does and I cba to troubleshoot...
+		if not self.combat then
+			secureFrame_Hide(self)
+		end
+	end
+	self.owner = owner
+	if not self.combat then
+		secureFrame_Show(self)
+	end
+end
+
+function secureFrame:Deactivate()
+	if not self.combat then
+		secureFrame_Hide(self)
+	end
+	self.owner = nil
+end
+
+-- END secure frame utilities
+
+
+-- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies
+local underlineFrame = CreateFrame("Frame", nil)
+underlineFrame.tx = underlineFrame:CreateTexture()
+underlineFrame.tx:SetTexture(1,1,0.5,0.75)
+underlineFrame:SetScript("OnHide", function(this) this:Hide(); end)
+underlineFrame:SetScript("OnShow", function(this) 	-- change sizing on the fly to catch runtime uiscale changes
+    underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale())
+    underlineFrame.tx:SetPoint("RIGHT", 1,0)
+    underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale());
+end)
+underlineFrame:SetHeight(1)
+
+-- END underline on mouseover
+
+
+local function GetScaledCursorPosition()
+	local x, y = GetCursorPosition()
+	local scale = UIParent:GetEffectiveScale()
+	return x / scale, y / scale
+end
+
+local function StartCounting(self, level)
+	for i = level, 1, -1 do
+		if levels[i] then
+			levels[i].count = 3
+		end
+	end
+end
+
+local function StopCounting(self, level)
+	for i = level, 1, -1 do
+		if levels[i] then
+			levels[i].count = nil
+		end
+	end
+end
+
+local function OnUpdate(self, elapsed)
+	for _,level in ipairs(levels) do
+		local count = level.count
+		if count then
+			count = count - elapsed
+			if count < 0 then
+				level.count = nil
+				self:Close(level.num)
+			else
+				level.count = count
+			end
+		end
+	end
+end
+
+local function CheckDualMonitor(self, frame)
+	local ratio = GetScreenWidth() / GetScreenHeight()
+	if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then
+		local offsetx
+		if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then
+			offsetx = GetScreenWidth() / 2 - frame:GetRight()
+		else
+			offsetx = GetScreenWidth() / 2 - frame:GetLeft()
+		end
+		local point, parent, relativePoint, x, y = frame:GetPoint(1)
+		frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0)
+	end
+end
+
+local function CheckSize(self, level)
+	if not level.buttons then
+		return
+	end
+	local height = 20
+	for _, button in ipairs(level.buttons) do
+		height = height + button:GetHeight()
+	end
+	level:SetHeight(height)
+	local width = 160
+	for _, button in ipairs(level.buttons) do
+		local extra = 1
+		if button.hasArrow or button.hasColorSwatch then
+			extra = extra + 16
+		end
+		if not button.notCheckable then
+			extra = extra + 24
+		end
+		button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight)
+		if button.text:GetWidth() + extra > width then
+			width = button.text:GetWidth() + extra
+		end
+	end
+	level:SetWidth(width + 20)
+	if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then
+		level:ClearAllPoints()
+		local parent = level.parent or level:GetParent()
+		if type(parent) ~= "table" then
+			parent = UIParent
+		end
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	local dirty = false
+	if not level:GetRight() then
+		self:Close()
+		return
+	end
+	if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then
+		level.lastDirection = "LEFT"
+		dirty = true
+	elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then
+		level.lastDirection = "RIGHT"
+		dirty = true
+	end
+	if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then
+		level.lastVDirection = "DOWN"
+		dirty = true
+	elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then
+		level.lastVDirection = "UP"
+		dirty = true
+	end
+	if dirty then
+		level:ClearAllPoints()
+		local parent = level.parent or level:GetParent()
+		if type(parent) ~= "table" then
+			parent = UIParent
+		end
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	if level:GetTop() > GetScreenHeight() then
+		local top = level:GetTop()
+		local point, parent, relativePoint, x, y = level:GetPoint(1)
+		level:ClearAllPoints()
+		level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top)
+	elseif level:GetBottom() < 0 then
+		local bottom = level:GetBottom()
+		local point, parent, relativePoint, x, y = level:GetPoint(1)
+		level:ClearAllPoints()
+		level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom)
+	end
+	CheckDualMonitor(self, level)
+	if mod(level.num, 5) == 0 then
+		local left, bottom = level:GetLeft(), level:GetBottom()
+		level:ClearAllPoints()
+		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	end
+end
+
+local Open
+local OpenSlider
+local OpenEditBox
+local Refresh
+local Clear
+local function ReleaseButton(self, level, index)
+	if not level.buttons then
+		return
+	end
+	if not level.buttons[index] then
+		return
+	end
+	local button = level.buttons[index]
+	button:Hide()
+	if button.highlight then
+		button.highlight:Hide()
+	end
+--	button.arrow:SetVertexColor(1, 1, 1)
+--	button.arrow:SetHeight(16)
+--	button.arrow:SetWidth(16)
+	table.remove(level.buttons, index)
+	table.insert(buttons, button)
+	for k in pairs(button) do
+		if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then
+			button[k] = nil
+		end
+	end
+	return true
+end
+
+local function Scroll(self, level, down)
+	if down then
+		if level:GetBottom() < 0 then
+			local point, parent, relativePoint, x, y = level:GetPoint(1)
+			level:SetPoint(point, parent, relativePoint, x, y + 50)
+			if level:GetBottom() > 0 then
+				level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom())
+			end
+		end
+	else
+		if level:GetTop() > GetScreenHeight() then
+			local point, parent, relativePoint, x, y = level:GetPoint(1)
+			level:SetPoint(point, parent, relativePoint, x, y - 50)
+			if level:GetTop() < GetScreenHeight() then
+				level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop())
+			end
+		end
+	end
+end
+
+local function getArgs(t, str, num, ...)
+	local x = t[str .. num]
+	if x == nil then
+		return ...
+	else
+		return x, getArgs(t, str, num + 1, ...)
+	end
+end
+
+local sliderFrame
+local editBoxFrame
+
+local normalFont
+local lastSetFont
+local justSetFont = false
+local regionTmp = {}
+local function fillRegionTmp(...)
+	for i = 1, select('#', ...) do
+		regionTmp[i] = select(i, ...)
+	end
+end
+
+local function showGameTooltip(this)
+	if this.tooltipTitle or this.tooltipText then
+		GameTooltip_SetDefaultAnchor(GameTooltip, this)
+		local disabled = not this.isTitle and this.disabled
+		local font
+		if this.tooltipTitle then
+			if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then
+				font = SharedMedia:Fetch("font", this.tooltipTitle)
+			end
+			if disabled then
+				GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1)
+			else
+				GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1)
+			end
+			if this.tooltipText then
+				if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then
+					font = SharedMedia:Fetch("font", this.tooltipText)
+				end
+				if disabled then
+					GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1)
+				else
+					GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
+				end
+			end
+		else
+			if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then
+				font = SharedMedia:Fetch("font", this.tooltipText)
+			end
+			if disabled then
+				GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1)
+			else
+				GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1)
+			end
+		end
+		if font then
+			fillRegionTmp(GameTooltip:GetRegions())
+			lastSetFont = font
+			justSetFont = true
+			for i,v in ipairs(regionTmp) do
+				if v.SetFont then
+					local norm,size,outline = v:GetFont()
+					v:SetFont(font, size, outline)
+					if not normalFont then
+						normalFont = norm
+					end
+				end
+				regionTmp[i] = nil
+			end
+		elseif not normalFont then
+			fillRegionTmp(GameTooltip:GetRegions())
+			for i,v in ipairs(regionTmp) do
+				if v.GetFont and not normalFont then
+					normalFont = v:GetFont()
+				end
+				regionTmp[i] = nil
+			end
+		end
+		GameTooltip:Show()
+	end
+	if this.tooltipFunc then
+		GameTooltip:SetOwner(this, "ANCHOR_NONE")
+		GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0)
+		this.tooltipFunc(getArgs(this, 'tooltipArg', 1))
+		GameTooltip:Show()
+	end
+end
+
+local tmpt = setmetatable({}, {mode='v'})
+local numButtons = 0
+local function AcquireButton(self, level)
+	if not levels[level] then
+		return
+	end
+	level = levels[level]
+	if not level.buttons then
+		level.buttons = {}
+	end
+	local button
+	if #buttons == 0 then
+		numButtons = numButtons + 1
+		button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil)
+		button:SetFrameStrata("FULLSCREEN_DIALOG")
+		button:SetHeight(16)
+		local highlight = button:CreateTexture(nil, "BACKGROUND")
+		highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
+		button.highlight = highlight
+		highlight:SetBlendMode("ADD")
+		highlight:SetAllPoints(button)
+		highlight:Hide()
+		local check = button:CreateTexture(nil, "ARTWORK")
+		button.check = check
+		check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+		check:SetPoint("CENTER", button, "LEFT", 12, 0)
+		check:SetWidth(24)
+		check:SetHeight(24)
+		local radioHighlight = button:CreateTexture(nil, "ARTWORK")
+		button.radioHighlight = radioHighlight
+		radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
+		radioHighlight:SetAllPoints(check)
+		radioHighlight:SetBlendMode("ADD")
+		radioHighlight:SetTexCoord(0.5, 0.75, 0, 1)
+		radioHighlight:Hide()
+		button:SetScript("OnEnter", function()
+			if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then
+				for i = 1, this.level.num do
+					Refresh(self, levels[i])
+				end
+				return
+			end
+			self:Close(this.level.num + 1)
+			if not this.disabled then
+				if this.secure then
+					secureFrame:Activate(this)
+				elseif this.hasSlider then
+					OpenSlider(self, this)
+				elseif this.hasEditBox then
+					OpenEditBox(self, this)
+				elseif this.hasArrow then
+					Open(self, this, nil, this.level.num + 1, this.value)
+				end
+			end
+			if not this.level then -- button reclaimed
+				return
+			end
+			StopCounting(self, this.level.num + 1)
+			if not this.disabled then
+				highlight:Show()
+				if this.isRadio then
+					button.radioHighlight:Show()
+				end
+				if this.mouseoverUnderline then
+					underlineFrame:SetParent(this)
+					underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0)
+					underlineFrame:SetWidth(this.text:GetWidth())
+					underlineFrame:Show()
+				end
+			end
+			showGameTooltip(this)
+		end)
+		button:SetScript("OnHide", function()
+			if this.secure and secureFrame:IsOwnedBy(this) then
+				secureFrame:Deactivate()
+			end
+		end)
+		button:SetScript("OnLeave", function()
+			if this.secure and secureFrame:IsShown() then
+				return;	-- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it
+			end
+			underlineFrame:Hide()
+			if not this.selected then
+				highlight:Hide()
+			end
+			button.radioHighlight:Hide()
+			if this.level then
+				StartCounting(self, this.level.num)
+			end
+			GameTooltip:Hide()
+		end)
+		local first = true
+		button:SetScript("OnClick", function()
+			if not this.disabled then
+				if this.hasColorSwatch then
+					local func = button.colorFunc
+					local hasOpacity = this.hasOpacity
+					local this = this
+					for k in pairs(tmpt) do
+						tmpt[k] = nil
+					end
+					for i = 1, 1000 do
+						local x = this['colorArg'..i]
+						if x == nil then
+							break
+						else
+							tmpt[i] = x
+						end
+					end
+					ColorPickerFrame.func = function()
+						if func then
+							local r,g,b = ColorPickerFrame:GetColorRGB()
+							local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil
+							local n = #tmpt
+							tmpt[n+1] = r
+							tmpt[n+2] = g
+							tmpt[n+3] = b
+							tmpt[n+4] = a
+							func(unpack(tmpt))
+							tmpt[n+1] = nil
+							tmpt[n+2] = nil
+							tmpt[n+3] = nil
+							tmpt[n+4] = nil
+						end
+					end
+					ColorPickerFrame.hasOpacity = this.hasOpacity
+					ColorPickerFrame.opacityFunc = ColorPickerFrame.func
+					ColorPickerFrame.opacity = 1 - this.opacity
+					ColorPickerFrame:SetColorRGB(this.r, this.g, this.b)
+					local r, g, b, a = this.r, this.g, this.b, this.opacity
+					ColorPickerFrame.cancelFunc = function()
+						if func then
+							local n = #tmpt
+							tmpt[n+1] = r
+							tmpt[n+2] = g
+							tmpt[n+3] = b
+							tmpt[n+4] = a
+							func(unpack(tmpt))
+							for i = 1, n+4 do
+								tmpt[i] = nil
+							end
+						end
+					end
+					self:Close(1)
+					ShowUIPanel(ColorPickerFrame)
+				elseif this.func then
+					local level = this.level
+					if type(this.func) == "string" then
+						if type(this.arg1[this.func]) ~= "function" then
+							self:error("Cannot call method %q", this.func)
+						end
+						this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2))
+					else
+						this.func(getArgs(this, 'arg', 1))
+					end
+					if this.closeWhenClicked then
+						self:Close()
+					elseif level:IsShown() then
+						for i = 1, level.num do
+							Refresh(self, levels[i])
+						end
+						local value = levels[level.num].value
+						for i = level.num-1, 1, -1 do
+							local level = levels[i]
+							local good = false
+							for _,button in ipairs(level.buttons) do
+								if button.value == value then
+									good = true
+									break
+								end
+							end
+							if not good then
+								Dewdrop:Close(i+1)
+							end
+							value = levels[i].value
+						end
+					end
+				elseif this.closeWhenClicked then
+					self:Close()
+				end
+			end
+		end)
+		local text = button:CreateFontString(nil, "ARTWORK")
+		button.text = text
+		text:SetFontObject(GameFontHighlightSmall)
+		button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT)
+		button:SetScript("OnMouseDown", function()
+			if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
+				text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1)
+			end
+		end)
+		button:SetScript("OnMouseUp", function()
+			if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
+				text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0)
+			end
+		end)
+		local arrow = button:CreateTexture(nil, "ARTWORK")
+		button.arrow = arrow
+		arrow:SetPoint("LEFT", button, "RIGHT", -16, 0)
+		arrow:SetWidth(16)
+		arrow:SetHeight(16)
+		arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
+		local colorSwatch = button:CreateTexture(nil, "ARTWORK")
+		button.colorSwatch = colorSwatch
+		colorSwatch:SetWidth(20)
+		colorSwatch:SetHeight(20)
+		colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
+		local texture = button:CreateTexture(nil, "OVERLAY")
+		colorSwatch.texture = texture
+		texture:SetTexture("Interface\\Buttons\\WHITE8X8")
+		texture:SetWidth(11.5)
+		texture:SetHeight(11.5)
+		texture:Show()
+		texture:SetPoint("CENTER", colorSwatch, "CENTER")
+		colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0)
+	else
+		button = table.remove(buttons)
+	end
+	button:ClearAllPoints()
+	button:SetParent(level)
+	button:SetFrameStrata(level:GetFrameStrata())
+	button:SetFrameLevel(level:GetFrameLevel() + 1)
+	button:SetPoint("LEFT", level, "LEFT", 10, 0)
+	button:SetPoint("RIGHT", level, "RIGHT", -10, 0)
+	if #level.buttons == 0 then
+		button:SetPoint("TOP", level, "TOP", 0, -10)
+	else
+		button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0)
+	end
+	button.text:SetPoint("LEFT", button, "LEFT", 24, 0)
+	button:Show()
+	button.level = level
+	table.insert(level.buttons, button)
+	if not level.parented then
+		level.parented = true
+		level:ClearAllPoints()
+		if level.num == 1 then
+			if level.parent ~= UIParent and type(level.parent) == "table" then
+				level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT")
+			else
+				level:SetPoint("CENTER", UIParent, "CENTER")
+			end
+		else
+			if level.lastDirection == "RIGHT" then
+				if level.lastVDirection == "DOWN" then
+					level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10)
+				else
+					level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10)
+				end
+			else
+				if level.lastVDirection == "DOWN" then
+					level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10)
+				else
+					level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10)
+				end
+			end
+		end
+		level:SetFrameStrata("FULLSCREEN_DIALOG")
+	end
+	button:SetAlpha(1)
+	return button
+end
+
+local numLevels = 0
+local function AcquireLevel(self, level)
+	if not levels[level] then
+		for i = #levels + 1, level, -1 do
+			local i = i
+			numLevels = numLevels + 1
+			local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil)
+			if i == 1 then
+				local old_CloseSpecialWindows = CloseSpecialWindows
+				function CloseSpecialWindows()
+					local found = old_CloseSpecialWindows()
+					if levels[1]:IsShown() then
+						self:Close()
+						return 1
+					end
+					return found
+				end
+			end
+			levels[i] = frame
+			frame.num = i
+			frame:SetParent(UIParent)
+			frame:SetFrameStrata("FULLSCREEN_DIALOG")
+			frame:Hide()
+			frame:SetWidth(180)
+			frame:SetHeight(10)
+			frame:SetFrameLevel(i * 3)
+			frame:SetScript("OnHide", function()
+				self:Close(level + 1)
+			end)
+			if frame.SetTopLevel then
+				frame:SetTopLevel(true)
+			end
+			frame:EnableMouse(true)
+			frame:EnableMouseWheel(true)
+			local backdrop = CreateFrame("Frame", nil, frame)
+			backdrop:SetAllPoints(frame)
+			backdrop:SetBackdrop(tmp(
+				'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
+				'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
+				'tile', true,
+				'insets', tmp2(
+					'left', 5,
+					'right', 5,
+					'top', 5,
+					'bottom', 5
+				),
+				'tileSize', 16,
+				'edgeSize', 16
+			))
+			backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
+			backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
+			frame:SetScript("OnClick", function()
+				self:Close(i)
+			end)
+			frame:SetScript("OnEnter", function()
+				StopCounting(self, i)
+			end)
+			frame:SetScript("OnLeave", function()
+				StartCounting(self, i)
+			end)
+			frame:SetScript("OnMouseWheel", function()
+				Scroll(self, frame, arg1 < 0)
+			end)
+			if i == 1 then
+				frame:SetScript("OnUpdate", function(this, arg1)
+					OnUpdate(self, arg1)
+				end)
+				levels[1].lastDirection = "RIGHT"
+				levels[1].lastVDirection = "DOWN"
+			else
+				levels[i].lastDirection = levels[i - 1].lastDirection
+				levels[i].lastVDirection = levels[i - 1].lastVDirection
+			end
+		end
+	end
+	local fullscreenFrame = GetUIPanel("fullscreen")
+	local l = levels[level]
+	local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel()
+	if fullscreenFrame then
+		l:SetParent(fullscreenFrame)
+	else
+		l:SetParent(UIParent)
+	end
+	l:SetFrameStrata(strata)
+	l:SetFrameLevel(framelevel)
+	l:SetAlpha(1)
+	return l
+end
+
+local function validateOptions(options, position, baseOptions, fromPass)
+	if not baseOptions then
+		baseOptions = options
+	end
+	if type(options) ~= "table" then
+		return "Options must be a table.", position
+	end
+	local kind = options.type
+	if type(kind) ~= "string" then
+		return '"type" must be a string.', position
+	elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then
+		return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position
+	end
+	if options.aliases then
+		if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then
+			return '"alias" must be a table or string', position
+		end
+	end
+	if not fromPass then
+		if kind == "execute" then
+			if type(options.func) ~= "string" and type(options.func) ~= "function" then
+				return '"func" must be a string or function', position
+			end
+		elseif kind == "range" or kind == "text" or kind == "toggle" then
+			if type(options.set) ~= "string" and type(options.set) ~= "function" then
+				return '"set" must be a string or function', position
+			end
+			if kind == "text" and options.get == false then
+			elseif type(options.get) ~= "string" and type(options.get) ~= "function" then
+				return '"get" must be a string or function', position
+			end
+		elseif kind == "group" and options.pass then
+			if options.pass ~= true then
+				return '"pass" must be either nil, true, or false', position
+			end
+			if not options.func then
+				if type(options.set) ~= "string" and type(options.set) ~= "function" then
+					return '"set" must be a string or function', position
+				end
+				if type(options.get) ~= "string" and type(options.get) ~= "function" then
+					return '"get" must be a string or function', position
+				end
+			elseif type(options.func) ~= "string" and type(options.func) ~= "function" then
+				return '"func" must be a string or function', position
+			end
+		end
+	end
+	if options ~= baseOptions then
+		if kind == "header" then
+		elseif type(options.desc) ~= "string" then
+			return '"desc" must be a string', position
+		elseif options.desc:len() == 0 then
+			return '"desc" cannot be a 0-length string', position
+		end
+	end
+	if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then
+		if options.type == "header" and not options.cmdName and not options.name then
+		elseif options.cmdName then
+			if type(options.cmdName) ~= "string" then
+				return '"cmdName" must be a string or nil', position
+			elseif options.cmdName:len() == 0 then
+				return '"cmdName" cannot be a 0-length string', position
+			end
+			if type(options.guiName) ~= "string" then
+				if not options.guiNameIsMap then
+					return '"guiName" must be a string or nil', position
+				end
+			elseif options.guiName:len() == 0 then
+				return '"guiName" cannot be a 0-length string', position
+			end
+		else
+			if type(options.name) ~= "string" then
+				return '"name" must be a string', position
+			elseif options.name:len() == 0 then
+				return '"name" cannot be a 0-length string', position
+			end
+		end
+	end
+	if options.guiNameIsMap then
+		if type(options.guiNameIsMap) ~= "boolean" then
+			return '"guiNameIsMap" must be a boolean or nil', position
+		elseif options.type ~= "toggle" then
+			return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position
+		elseif type(options.map) ~= "table" then
+			return '"map" must be a table', position
+		end
+	end
+	if options.message and type(options.message) ~= "string" then
+		return '"message" must be a string or nil', position
+	end
+	if options.error and type(options.error) ~= "string" then
+		return '"error" must be a string or nil', position
+	end
+	if options.current and type(options.current) ~= "string" then
+		return '"current" must be a string or nil', position
+	end
+	if options.order then
+		if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then
+			return '"order" must be a non-zero number or nil', position
+		end
+	end
+	if options.disabled then
+		if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then
+			return '"disabled" must be a function, string, or boolean', position
+		end
+	end
+	if options.cmdHidden then
+		if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then
+			return '"cmdHidden" must be a function, string, or boolean', position
+		end
+	end
+	if options.guiHidden then
+		if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then
+			return '"guiHidden" must be a function, string, or boolean', position
+		end
+	end
+	if options.hidden then
+		if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then
+			return '"hidden" must be a function, string, or boolean', position
+		end
+	end
+	if kind == "text" then
+		if type(options.validate) == "table" then
+			local t = options.validate
+			local iTable = nil
+			for k,v in pairs(t) do
+				if type(k) == "number" then
+					if iTable == nil then
+						iTable = true
+					elseif not iTable then
+						return '"validate" must either have all keys be indexed numbers or strings', position
+					elseif k < 1 or k > #t then
+						return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position
+					end
+				else
+					if iTable == nil then
+						iTable = false
+					elseif iTable then
+						return '"validate" must either have all keys be indexed numbers or strings', position
+					end
+				end
+				if type(v) ~= "string" then
+					return '"validate" values must all be strings', position
+				end
+			end
+			if options.multiToggle and options.multiToggle ~= true then
+				return '"multiToggle" must be a boolean or nil if "validate" is a table', position
+			end
+		elseif options.validate == "keybinding" then
+			-- no other checks
+		else
+			if type(options.usage) ~= "string" then
+				return '"usage" must be a string', position
+			elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then
+				return '"validate" must be a string, function, or table', position
+			end
+		end
+		if options.multiToggle and type(options.validate) ~= "table" then
+			return '"validate" must be a table if "multiToggle" is true', position
+		end
+	elseif kind == "range" then
+		if options.min or options.max then
+			if type(options.min) ~= "number" then
+				return '"min" must be a number', position
+			elseif type(options.max) ~= "number" then
+				return '"max" must be a number', position
+			elseif options.min >= options.max then
+				return '"min" must be less than "max"', position
+			end
+		end
+		if options.step then
+			if type(options.step) ~= "number" then
+				return '"step" must be a number', position
+			elseif options.step < 0 then
+				return '"step" must be nonnegative', position
+			end
+		end
+		if options.bigStep then
+			if type(options.bigStep) ~= "number" then
+				return '"bigStep" must be a number', position
+			elseif options.bigStep < 0 then
+				return '"bigStep" must be nonnegative', position
+			end
+		end
+		if options.isPercent and options.isPercent ~= true then
+			return '"isPercent" must either be nil, true, or false', position
+		end
+	elseif kind == "toggle" then
+		if options.map then
+			if type(options.map) ~= "table" then
+				return '"map" must be a table', position
+			elseif type(options.map[true]) ~= "string" then
+				return '"map[true]" must be a string', position
+			elseif type(options.map[false]) ~= "string" then
+				return '"map[false]" must be a string', position
+			end
+		end
+	elseif kind == "color" then
+		if options.hasAlpha and options.hasAlpha ~= true then
+			return '"hasAlpha" must be nil, true, or false', position
+		end
+	elseif kind == "group" then
+		if options.pass and options.pass ~= true then
+			return '"pass" must be nil, true, or false', position
+		end
+		if type(options.args) ~= "table" then
+			return '"args" must be a table', position
+		end
+		for k,v in pairs(options.args) do
+			if type(k) ~= "number" then
+				if type(k) ~= "string" then
+					return '"args" keys must be strings or numbers', position
+				elseif k:len() == 0 then
+					return '"args" keys must not be 0-length strings.', position
+				end
+			end
+			if type(v) ~= "table" then
+				return '"args" values must be tables', position and position .. "." .. k or k
+			end
+			local newposition
+			if position then
+				newposition = position .. ".args." .. k
+			else
+				newposition = "args." .. k
+			end
+			local err, pos = validateOptions(v, newposition, baseOptions, options.pass)
+			if err then
+				return err, pos
+			end
+		end
+	elseif kind == "execute" then
+		if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then
+			return '"confirm" must be a string, boolean, or nil', position
+		end
+	end
+	if options.icon and type(options.icon) ~= "string" then
+		return'"icon" must be a string', position
+	end
+	if options.iconWidth or options.iconHeight then
+		if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then
+			return '"iconHeight" and "iconWidth" must be numbers', position
+		end
+	end
+	if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then
+		if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then
+			return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position
+		end
+	end
+end
+
+local validatedOptions
+
+local values
+local mysort_args
+local mysort
+local othersort
+local othersort_validate
+
+local baseFunc, currentLevel
+
+local function confirmPopup(message, func, ...)
+	if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then
+		StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {}
+	end
+	local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"]
+	for k in pairs(t) do
+		t[k] = nil
+	end
+	t.text = message
+	t.button1 = ACCEPT or "Accept"
+	t.button2 = CANCEL or "Cancel"
+	t.OnAccept = function()
+		func(unpack(t))
+	end
+	for i = 1, select('#', ...) do
+		t[i] = select(i, ...)
+	end
+	t.timeout = 0
+	t.whileDead = 1
+	t.hideOnEscape = 1
+
+	Dewdrop:Close()
+	StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG")
+end
+
+
+local function getMethod(settingname, handler, v, methodName, ...)	-- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222"
+	assert(v and type(v)=="table")
+	assert(methodName and type(methodName)=="string")
+
+	local method = v[methodName]
+	if type(method)=="function" then
+		return method, ...
+	elseif type(method)=="string" then
+		if not handler then
+			Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method)
+		elseif not handler[method] then
+			Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method)
+		end
+		return handler[method], handler, ...
+	end
+
+	Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName)
+end
+
+local function callMethod(settingname, handler, v, methodName, ...)
+	assert(v and type(v)=="table")
+	assert(methodName and type(methodName)=="string")
+
+	local method = v[methodName]
+	if type(method)=="function" then
+		local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...)
+		if not success then
+			geterrorhandler()(ret)
+			return nil
+		end
+		return ret,ret2,ret3,ret4
+
+	elseif type(method)=="string" then
+
+		local neg = method:match("^~(.-)$")
+		if neg then
+			method = neg
+		end
+		if not handler then
+			Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method)
+		elseif not handler[method] then
+			Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method)
+		end
+		local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...)
+		if not success then
+			geterrorhandler()(ret)
+			return nil
+		end
+		if neg then
+			return not ret
+		end
+		return ret,ret2,ret3,ret4
+	elseif method == false then
+		return nil
+	end
+
+	Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)")
+end
+
+local function skip1Nil(...)
+	if select(1,...)==nil then
+		return select(2,...)
+	end
+	return ...
+end
+
+function Dewdrop:FeedAceOptionsTable(options, difference)
+	self:argCheck(options, 2, "table")
+	self:argCheck(difference, 3, "nil", "number")
+	if not currentLevel then
+		self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration")
+	end
+	if not difference then
+		difference = 0
+	end
+	if not validatedOptions then
+		validatedOptions = {}
+	end
+	if not validatedOptions[options] then
+		local err, position = validateOptions(options)
+
+		if err then
+			if position then
+				Dewdrop:error(position .. ": " .. err)
+			else
+				Dewdrop:error(err)
+			end
+		end
+
+		validatedOptions[options] = true
+	end
+	local level = levels[currentLevel]
+	if not level then
+		self:error("Improper level given")
+	end
+	if not values then
+		values = {}
+	else
+		for k,v in pairs(values) do
+			values[k] = nil
+		end
+	end
+
+	local current = level
+	while current do		-- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later
+		if current.num == difference + 1 then
+			break
+		end
+		table.insert(values, current.value)
+		current = levels[current.num - 1]
+	end
+
+	local realOptions = options
+	local handler = options.handler
+	local passTable
+	local passValue
+	while #values > 0 do	-- This loop traverses values from the END (trunk nodes first, then onto leaf nodes)
+		if options.pass then
+			if options.get and options.set then
+				passTable = options
+			elseif not passTable then
+				passTable = options
+			end
+		else
+			passTable = nil
+		end
+		local value = table.remove(values)
+		options = options.args and options.args[value]
+		if not options then
+			return
+		end
+		handler = options.handler or handler
+		passValue = passTable and value or nil
+	end
+
+	if options.type == "group" then
+		local hidden = options.hidden
+		if type(hidden) == "function" or type(hidden) == "string" then
+			hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false
+		end
+		if hidden then
+			return
+		end
+		local disabled = options.disabled
+		if type(disabled) == "function" or type(disabled) == "string" then
+			disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false
+		end
+		if disabled then
+			self:AddLine(
+				'text', DISABLED,
+				'disabled', true
+			)
+			return
+		end
+		for k in pairs(options.args) do
+			table.insert(values, k)
+		end
+		if options.pass then
+			if options.get and options.set then
+				passTable = options
+			elseif not passTable then
+				passTable = options
+			end
+		else
+			passTable = nil
+		end
+		if not mysort then
+			mysort = function(a, b)
+				local alpha, bravo = mysort_args[a], mysort_args[b]
+				local alpha_order = alpha.order or 100
+				local bravo_order = bravo.order or 100
+				local alpha_name = alpha.guiName or alpha.name
+				local bravo_name = bravo.guiName or bravo.name
+				if alpha_order == bravo_order then
+					if not alpha_name then
+						return bravo_name
+					elseif not bravo_name then
+						return false
+					else
+						return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper()
+					end
+				else
+					if alpha_order < 0 then
+						if bravo_order > 0 then
+							return false
+						end
+					else
+						if bravo_order < 0 then
+							return true
+						end
+					end
+					return alpha_order < bravo_order
+				end
+			end
+		end
+		mysort_args = options.args
+		table.sort(values, mysort)
+		mysort_args = nil
+		local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0
+		local last_order = 1
+		for _,k in ipairs(values) do
+			local v = options.args[k]
+			local handler = v.handler or handler
+			if hasBoth and last_order > 0 and (v.order or 100) < 0 then
+				hasBoth = false
+				self:AddLine()
+			end
+			local hidden, disabled = v.guiHidden or v.hidden, v.disabled
+
+			if type(hidden) == "function" or type(hidden) == "string" then
+				hidden = callMethod(k, handler, v, "hidden", v.passValue) or false
+			end
+			if not hidden then
+				if type(disabled) == "function" or type(disabled) == "string" then
+					disabled = callMethod(k, handler, v, "disabled", v.passValue) or false
+				end
+				local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name)
+				local desc = v.guiDesc or v.desc
+				local iconHeight = v.iconHeight or 16
+				local iconWidth = v.iconWidth or 16
+				local iconCoordLeft = v.iconCoordLeft
+				local iconCoordRight = v.iconCoordRight
+				local iconCoordBottom = v.iconCoordBottom
+				local iconCoordTop = v.iconCoordTop
+				local tooltipTitle, tooltipText
+				tooltipTitle = name
+				if name ~= desc then
+					tooltipText = desc
+				end
+				if type(v.usage) == "string" and v.usage:trim():len() > 0 then
+					if tooltipText then
+						tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage)
+					else
+						tooltipText = USAGE_TOOLTIP:format(v.usage)
+					end
+				end
+				local v_p = passTable
+				if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then
+					v_p = v
+				end
+				local passValue = v.passValue or (v_p~=v and k) or nil
+				if v.type == "toggle" then
+					local checked = callMethod(name, handler, v_p, "get", passValue) or false
+					local checked_arg = checked
+					if type(v_p.get)=="string" and v_p.get:match("^~") then
+						checked_arg = not checked
+					end
+					local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set",   skip1Nil(passValue, not checked_arg))
+					if v.guiNameIsMap then
+						checked = checked and true or false
+						name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
+						tooltipTitle = name
+						checked = true--nil
+					end
+					self:AddLine(
+						'text', name,
+						'checked', checked,
+						'isRadio', v.isRadio,
+						'func', func,
+						'arg1', arg1,
+						'arg2', arg2,
+						'arg3', arg3,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText
+					)
+				elseif v.type == "execute" then
+					local func, arg1, arg2, arg3, arg4
+					local confirm = v.confirm
+					if confirm == true then
+						confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle)
+						func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue)
+					elseif type(confirm) == "string" then
+						func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue)
+					else
+						func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue)
+					end
+					self:AddLine(
+						'text', name,
+						'checked', checked,
+						'func', func,
+						'arg1', arg1,
+						'arg2', arg2,
+						'arg3', arg3,
+						'arg4', arg4,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText,
+						'icon', v.icon,
+						'iconHeight', iconHeight,
+						'iconWidth', iconWidth,
+						'iconCoordLeft', iconCoordLeft,
+						'iconCoordRight', iconCoordRight,
+						'iconCoordTop', iconCoordTop,
+						'iconCoordBottom', iconCoordBottom
+					)
+				elseif v.type == "range" then
+					local sliderValue
+					sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0
+					local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set",    passValue)
+					if tooltipText then
+						tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP)
+					else
+						tooltipText = RANGE_TOOLTIP
+					end
+					self:AddLine(
+						'text', name,
+						'hasArrow', true,
+						'hasSlider', true,
+						'sliderMin', v.min or 0,
+						'sliderMax', v.max or 1,
+						'sliderStep', v.step or 0,
+						'sliderBigStep', v.bigStep or nil,
+						'sliderIsPercent', v.isPercent or false,
+						'sliderValue', sliderValue,
+						'sliderFunc', sliderFunc,
+						'sliderArg1', sliderArg1,
+						'sliderArg2', sliderArg2,
+						'fromAceOptions', true,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText,
+						'icon', v.icon,
+						'iconHeight', iconHeight,
+						'iconWidth', iconWidth,
+						'iconCoordLeft', iconCoordLeft,
+						'iconCoordRight', iconCoordRight,
+						'iconCoordTop', iconCoordTop,
+						'iconCoordBottom', iconCoordBottom
+					)
+				elseif v.type == "color" then
+					local r,g,b,a = callMethod(name, handler, v_p, "get", passValue)
+					if not r then
+						r,g,b,a = 0,0,0,0
+					end
+					local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set",    passValue)
+					self:AddLine(
+						'text', name,
+						'hasArrow', true,
+						'hasColorSwatch', true,
+						'r', r,
+						'g', g,
+						'b', b,
+						'opacity', v.hasAlpha and a or nil,
+						'hasOpacity', v.hasAlpha,
+						'colorFunc', colorFunc,
+						'colorArg1', colorArg1,
+						'colorArg2', colorArg2,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText
+					)
+				elseif v.type == "text" then
+						if type(v.validate) == "table" then
+						local func,arg1,arg2
+						if v.onClick then
+							func,arg1,arg2 = getMethod(name, handler, v, "onClick",    passValue)
+						end
+						local checked
+						if v.isChecked then
+							checked = callMethod(name, handler, v, "isChecked",    passValue) or false
+						end
+						self:AddLine(
+							'text', name,
+							'hasArrow', true,
+							'value', k,
+							'func', func,
+							'arg1', arg1,
+							'arg2', arg2,
+							'mouseoverUnderline', func and true or nil,
+							'disabled', disabled,
+							'checked', checked,
+							'tooltipTitle', tooltipTitle,
+							'tooltipText', tooltipText,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom
+						)
+					else
+						local editBoxText
+						editBoxText = callMethod(name, handler, v_p, "get", passValue) or ""
+						local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set",    passValue)
+
+						local editBoxValidateFunc, editBoxValidateArg1
+
+						if v.validate and v.validate ~= "keybinding" then
+							if v.validate == "keybinding" then
+								if tooltipText then
+									tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC)
+								else
+									tooltipText = RESET_KEYBINDING_DESC
+								end
+							else
+								editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue!
+							end
+						end
+
+						self:AddLine(
+							'text', name,
+							'hasArrow', true,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom,
+							'hasEditBox', true,
+							'editBoxText', editBoxText,
+							'editBoxFunc', editBoxFunc,
+							'editBoxArg1', editBoxArg1,
+							'editBoxArg2', editBoxArg2,
+							'editBoxValidateFunc', editBoxValidateFunc,
+							'editBoxValidateArg1', editBoxValidateArg1,
+							'editBoxIsKeybinding', v.validate == "keybinding",
+							'editBoxKeybindingOnly', v.keybindingOnly,
+							'editBoxKeybindingExcept', v.keybindingExcept,
+							'disabled', disabled,
+							'tooltipTitle', tooltipTitle,
+							'tooltipText', tooltipText
+						)
+					end
+				elseif v.type == "group" then
+					local func,arg1,arg2
+					if v.onClick then
+						func,arg1,arg2 = getMethod(name, handler, v, "onClick",    passValue)
+					end
+					local checked
+					if v.isChecked then
+						checked = callMethod(name, handler, v, "isChecked",    passValue) or false
+					end
+					self:AddLine(
+						'text', name,
+						'hasArrow', true,
+						'value', k,
+						'func', func,
+						'arg1', arg1,
+						'arg2', arg2,
+						'mouseoverUnderline', func and true or nil,
+						'disabled', disabled,
+						'checked', checked,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText,
+						'icon', v.icon,
+						'iconHeight', iconHeight,
+						'iconWidth', iconWidth,
+						'iconCoordLeft', iconCoordLeft,
+						'iconCoordRight', iconCoordRight,
+						'iconCoordTop', iconCoordTop,
+						'iconCoordBottom', iconCoordBottom
+					)
+				elseif v.type == "header" then
+					if name == "" or not name then
+						self:AddLine(
+							'isTitle', true,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom
+						)
+					else
+						self:AddLine(
+							'text', name,
+							'isTitle', true,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom
+						)
+					end
+				end
+			end
+			last_order = v.order or 100
+		end
+	elseif options.type == "text" and type(options.validate) == "table" then
+		local current
+		local options_p = passTable
+		if not options_p or (options.get and options.set) then
+			options_p = options
+			passTable = nil
+			passValue = nil
+		end
+		local multiToggle = options.multiToggle
+		local passValue = options.passValue or passValue
+		if not multiToggle then
+			current = callMethod(k, handler, options_p, "get", passValue)
+		end
+		local indexed = true
+		for k,v in pairs(options.validate) do
+			if type(k) ~= "number" then
+				indexed = false
+			end
+			table.insert(values, k)
+		end
+		if not indexed then
+			if not othersort then
+				othersort = function(alpha, bravo)
+					return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper()
+				end
+			end
+			othersort_validate = options.validate
+			table.sort(values, othersort)
+			othersort_validate = nil
+		end
+		for _,k in ipairs(values) do
+			local v = options.validate[k]
+			if type(k) == "number" then
+				k = v
+			end
+			local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set",    skip1Nil(passValue, k))
+			local checked
+			if multiToggle then
+				checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false
+				if arg2 == nil then
+					arg2 = not checked
+				elseif arg3 == nil then
+					arg3 = not checked
+				else
+					arg4 = not checked
+				end
+			else
+				checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower()))
+				if checked then
+					func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil
+				end
+			end
+			local tooltipTitle
+			local tooltipText
+			if options.validateDesc then
+				tooltipTitle = v
+				tooltipText = options.validateDesc[k]
+			else
+				tooltipTitle = options.guiName or options.name
+				tooltipText = v
+			end
+			self:AddLine(
+				'text', v,
+				'func', func,
+				'arg1', arg1,
+				'arg2', arg2,
+				'arg3', arg3,
+				'arg4', arg4,
+				'isRadio', not multiToggle,
+				'checked',  checked,
+				'tooltipTitle', tooltipTitle,
+				'tooltipText', tooltipText
+			)
+		end
+		for k in pairs(values) do
+			values[k] = nil
+		end
+	else
+		return false
+	end
+	return true
+end
+
+function Dewdrop:FeedTable(s, difference)
+	self:argCheck(s, 2, "table")
+	self:argCheck(difference, 3, "nil", "number")
+	if not currentLevel then
+		self:error("Cannot call `FeedTable' outside of a Dewdrop declaration")
+	end
+	if not difference then
+		difference = 0
+	end
+	local level = levels[currentLevel]
+	if not level then
+		self:error("Improper level given")
+	end
+	if not values then
+		values = {}
+	else
+		for k,v in pairs(values) do
+			values[k] = nil
+		end
+	end
+	local t = s.subMenu and s or {subMenu = s}
+	local current = level
+	while current do
+		if current.num == difference + 1 then
+			break
+		end
+		table.insert(values, current.value)
+		current = levels[current.num - 1]
+	end
+
+	while #values > 0 do
+		local value = table.remove(values)
+		t = t.subMenu and t.subMenu[value]
+		if not t then
+			return
+		end
+	end
+
+	if t.subMenu or current.num == 1 then
+		for k in pairs(t.subMenu) do
+			table.insert(values, k)
+		end
+		table.sort(values)
+		for _,k in ipairs(values) do
+			local argTable = {"value", k}
+			for key, val in pairs(t.subMenu[k]) do
+				table.insert(argTable, key)
+				table.insert(argTable, val)
+			end
+			self:AddLine(unpack(argTable))
+		end
+		for k in pairs(values) do
+			values[k] = nil
+		end
+		return false
+	end
+	return true
+end
+
+function Refresh(self, level)
+	if type(level) == "number" then
+		level = levels[level]
+	end
+	if not level then
+		return
+	end
+	if baseFunc then
+		Clear(self, level)
+		currentLevel = level.num
+		if type(baseFunc) == "table" then
+			if currentLevel == 1 then
+				local handler = baseFunc.handler
+				if handler then
+					local name = tostring(handler)
+					if not name:find('^table:') and not handler.hideMenuTitle then
+						name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
+						self:AddLine(
+							'text', name,
+							'isTitle', true
+						)
+					end
+				end
+--			elseif level.parentText then
+--				self:AddLine(
+--					'text', level.parentText,
+--					'tooltipTitle', level.parentTooltipTitle,
+--					'tooltipText', level.parentTooltipText,
+--					'tooltipFunc', level.parentTooltipFunc,
+--					'isTitle', true
+--				)
+			end
+			self:FeedAceOptionsTable(baseFunc)
+			if currentLevel == 1 then
+				self:AddLine(
+					'text', CLOSE,
+					'tooltipTitle', CLOSE,
+					'tooltipText', CLOSE_DESC,
+					'closeWhenClicked', true
+				)
+			end
+		else
+--			if level.parentText then
+--				self:AddLine(
+--					'text', level.parentText,
+--					'tooltipTitle', level.parentTooltipTitle,
+--					'tooltipText', level.parentTooltipText,
+--					'tooltipFunc', level.parentTooltipFunc,
+--					'isTitle', true
+--				)
+--			end
+			baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value)
+		end
+		currentLevel = nil
+		CheckSize(self, level)
+	end
+end
+
+function Dewdrop:Refresh(level)
+	self:argCheck(level, 2, "number", "nil")
+	if not level then
+		for k,v in pairs(levels) do
+			Refresh(self, v)
+		end
+	else
+		Refresh(self, levels[level])
+	end
+end
+
+function OpenSlider(self, parent)
+	if not sliderFrame then
+		sliderFrame = CreateFrame("Frame", nil, nil)
+		sliderFrame:SetWidth(100)
+		sliderFrame:SetHeight(170)
+		sliderFrame:SetScale(UIParent:GetScale())
+		sliderFrame:SetBackdrop(tmp(
+			'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
+			'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
+			'tile', true,
+			'insets', tmp2(
+				'left', 5,
+				'right', 5,
+				'top', 5,
+				'bottom', 5
+			),
+			'tileSize', 16,
+			'edgeSize', 16
+		))
+		sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+		if sliderFrame.SetTopLevel then
+			sliderFrame:SetTopLevel(true)
+		end
+		sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
+		sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
+		sliderFrame:EnableMouse(true)
+		sliderFrame:EnableMouseWheel(true)
+		sliderFrame:Hide()
+		sliderFrame:SetPoint("CENTER", UIParent, "CENTER")
+		local slider = CreateFrame("Slider", nil, sliderFrame)
+		sliderFrame.slider = slider
+		slider:SetOrientation("VERTICAL")
+		slider:SetMinMaxValues(0, 1)
+		slider:SetValueStep(0.000000001)
+		slider:SetValue(0.5)
+		slider:SetWidth(16)
+		slider:SetHeight(128)
+		slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0)
+		slider:SetBackdrop(tmp(
+			'bgFile', "Interface\\Buttons\\UI-SliderBar-Background",
+			'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border",
+			'tile', true,
+			'edgeSize', 8,
+			'tileSize', 8,
+			'insets', tmp2(
+				'left', 3,
+				'right', 3,
+				'top', 3,
+				'bottom', 3
+			)
+		))
+		local texture = slider:CreateTexture()
+		slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
+		local text = slider:CreateFontString(nil, "ARTWORK")
+		sliderFrame.topText = text
+		text:SetFontObject(GameFontGreenSmall)
+		text:SetText("100%")
+		text:SetPoint("BOTTOM", slider, "TOP")
+		local text = slider:CreateFontString(nil, "ARTWORK")
+		sliderFrame.bottomText = text
+		text:SetFontObject(GameFontGreenSmall)
+		text:SetText("0%")
+		text:SetPoint("TOP", slider, "BOTTOM")
+		local editBox = CreateFrame("EditBox", nil, sliderFrame)
+		sliderFrame.currentText = editBox
+		editBox:SetFontObject(ChatFontNormal)
+		editBox:SetHeight(13)
+		editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0)
+		editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0)
+		editBox:SetText("50%")
+		editBox:SetJustifyH("CENTER")
+
+		local width = editBox:GetWidth()/2 + 10
+		local left = editBox:CreateTexture(nil, "BACKGROUND")
+		left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
+		left:SetTexCoord(0, width / 256, 0, 1)
+		left:SetWidth(width)
+		left:SetHeight(32)
+		left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
+		local right = editBox:CreateTexture(nil, "BACKGROUND")
+		right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
+		right:SetTexCoord(1 - width / 256, 1, 0, 1)
+		right:SetWidth(width)
+		right:SetHeight(32)
+		right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
+
+		local changed = false
+		local inside = false
+		slider:SetScript("OnValueChanged", function()
+			if sliderFrame.changing then
+				return
+			end
+			changed = true
+			local done = false
+			if sliderFrame.parent and sliderFrame.parent.sliderFunc then
+				local min = sliderFrame.parent.sliderMin or 0
+				local max = sliderFrame.parent.sliderMax or 1
+				local step
+				if sliderFrame.fineStep then
+					step = sliderFrame.parent.sliderStep or (max - min) / 100
+				else
+					step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100
+				end
+				local value = (1 - slider:GetValue()) * (max - min) + min
+				if step > 0 then
+					value = math.floor((value - min) / step + 0.5) * step + min
+					if value > max then
+						value = max
+					elseif value < min then
+						value = min
+					end
+				end
+				if value == sliderFrame.lastValue then
+					return
+				end
+				sliderFrame.lastValue = value
+				local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value))
+				if sliderFrame.parent.fromAceOptions then
+					text = nil
+				elseif type(text) == "string" or type(text) == "number" then
+					sliderFrame.currentText:SetText(text)
+					done = true
+				end
+			end
+			if not done then
+				local min = sliderFrame.parent.sliderMin or 0
+				local max = sliderFrame.parent.sliderMax or 1
+				local step
+				if sliderFrame.fineStep then
+					step = sliderFrame.parent.sliderStep or (max - min) / 100
+				else
+					step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100
+				end
+				local value = (1 - slider:GetValue()) * (max - min) + min
+				if step > 0 then
+					value = math.floor((value - min) / step + 0.5) * step + min
+					if value > max then
+						value = max
+					elseif value < min then
+						value = min
+					end
+				end
+				if sliderFrame.parent.sliderIsPercent then
+					sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100))
+				else
+					if step < 0.1 then
+						sliderFrame.currentText:SetText(string.format("%.2f", value))
+					elseif step < 1 then
+						sliderFrame.currentText:SetText(string.format("%.1f", value))
+					else
+						sliderFrame.currentText:SetText(string.format("%.0f", value))
+					end
+				end
+			end
+		end)
+		local function onEnter()
+			StopCounting(self, sliderFrame.level)
+			showGameTooltip(sliderFrame.parent)
+		end
+		local function onLeave()
+			GameTooltip:Hide()
+		end
+		sliderFrame:SetScript("OnEnter", onEnter)
+		sliderFrame:SetScript("OnLeave", function()
+			GameTooltip:Hide()
+			if changed then
+				local parent = sliderFrame.parent
+				local sliderFunc = parent.sliderFunc
+				for i = 1, sliderFrame.level - 1 do
+					Refresh(self, levels[i])
+				end
+				local newParent
+				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
+					if button.sliderFunc == sliderFunc then
+						newParent = button
+						break
+					end
+				end
+				if newParent then
+					OpenSlider(self, newParent)
+				else
+					sliderFrame:Hide()
+				end
+			end
+		end)
+		editBox:SetScript("OnEnter", onEnter)
+		editBox:SetScript("OnLeave", onLeave)
+		slider:SetScript("OnMouseDown", function()
+			sliderFrame.mouseDown = true
+			GameTooltip:Hide()
+		end)
+		slider:SetScript("OnMouseUp", function()
+			sliderFrame.mouseDown = false
+			if changed--[[ and not inside]] then
+				local parent = sliderFrame.parent
+				local sliderFunc = parent.sliderFunc
+				for i = 1, sliderFrame.level - 1 do
+					Refresh(self, levels[i])
+				end
+				local newParent
+				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
+					if button.sliderFunc == sliderFunc then
+						newParent = button
+						break
+					end
+				end
+				if newParent then
+					OpenSlider(self, newParent)
+				else
+					sliderFrame:Hide()
+				end
+			end
+			if inside then
+				showGameTooltip(sliderFrame.parent)
+			end
+		end)
+		slider:SetScript("OnEnter", function()
+			inside = true
+			StopCounting(self, sliderFrame.level)
+			showGameTooltip(sliderFrame.parent)
+		end)
+		slider:SetScript("OnLeave", function()
+			inside = false
+			GameTooltip:Hide()
+			if changed and not sliderFrame.mouseDown then
+				local parent = sliderFrame.parent
+				local sliderFunc = parent.sliderFunc
+				for i = 1, sliderFrame.level - 1 do
+					Refresh(self, levels[i])
+				end
+				local newParent
+				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
+					if button.sliderFunc == sliderFunc then
+						newParent = button
+						break
+					end
+				end
+				if newParent then
+					OpenSlider(self, newParent)
+				else
+					sliderFrame:Hide()
+				end
+
+				changed = false
+			end
+		end)
+		sliderFrame:SetScript("OnMouseWheel", function(t, a1)
+			local arg1 = a1 or arg1
+			local up = arg1 > 0
+
+			local min = sliderFrame.parent.sliderMin or 0
+			local max = sliderFrame.parent.sliderMax or 1
+			local step = sliderFrame.parent.sliderStep or (max - min) / 100
+			if step <= 0 then
+				step = (max - min) / 100
+			end
+
+			local value = (1 - slider:GetValue()) * (max - min) + min
+			if up then
+				value = value + step
+			else
+				value = value - step
+			end
+			if value > max then
+				value = max
+			elseif value < min then
+				value = min
+			end
+			sliderFrame.fineStep = true
+			if max<=min then
+				slider:SetValue(0)
+			else
+				slider:SetValue(1 - (value - min) / (max - min))
+			end
+			sliderFrame.fineStep = nil
+		end)
+		slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel"))
+		editBox:SetScript("OnEnterPressed", function(t, a1)
+			local value = editBox:GetNumber()
+
+			if sliderFrame.parent.sliderIsPercent then
+				value = value / 100
+			end
+
+			local min = sliderFrame.parent.sliderMin or 0
+			local max = sliderFrame.parent.sliderMax or 1
+
+			if value > max then
+				value = max
+			elseif value < min then
+				value = min
+			end
+			sliderFrame.fineStep = true
+			if max <= min then
+				slider:SetValue(0)
+			else
+				slider:SetValue(1 - (value - min) / (max - min))
+			end
+			sliderFrame.fineStep = nil
+
+			StartCounting(self, sliderFrame.level)
+		end)
+		editBox:SetScript("OnEscapePressed", function()
+			self:Close(sliderFrame.level)
+			StartCounting(self, sliderFrame.level)
+		end)
+		editBox:SetAutoFocus(false)
+	end
+	sliderFrame.parent = parent
+	sliderFrame.level = parent.level.num + 1
+	sliderFrame.parentValue = parent.level.value
+	sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
+	sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
+	sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
+	sliderFrame.currentText:ClearFocus()
+	sliderFrame.changing = true
+	if not parent.sliderMin or not parent.sliderMax then
+		return
+	end
+
+	if parent.arrow then
+--		parent.arrow:SetVertexColor(0.2, 0.6, 0)
+--		parent.arrow:SetHeight(24)
+--		parent.arrow:SetWidth(24)
+		parent.selected = true
+		parent.highlight:Show()
+	end
+
+	sliderFrame:SetClampedToScreen(false)
+	if not parent.sliderValue then
+		parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2
+	end
+	if parent.sliderMax <= parent.sliderMin then
+		sliderFrame.slider:SetValue(0)
+	else
+		sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin))
+	end
+	sliderFrame.changing = false
+	sliderFrame.bottomText:SetText(parent.sliderMinText or "0")
+	sliderFrame.topText:SetText(parent.sliderMaxText or "1")
+	local text
+	if parent.sliderFunc and not parent.fromAceOptions then
+		text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue))
+	end
+	if type(text) == "number" or type(text) == "string" then
+		sliderFrame.currentText:SetText(text)
+	elseif parent.sliderIsPercent then
+		sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100))
+	else
+		if parent.sliderStep < 0.1 then
+			sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue))
+		elseif parent.sliderStep < 1 then
+			sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue))
+		else
+			sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue))
+		end
+	end
+
+
+	sliderFrame.lastValue = parent.sliderValue
+
+	local level = parent.level
+	sliderFrame:Show()
+	sliderFrame:ClearAllPoints()
+	if level.lastDirection == "RIGHT" then
+		if level.lastVDirection == "DOWN" then
+			sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+		else
+			sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+		end
+	else
+		if level.lastVDirection == "DOWN" then
+			sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+		else
+			sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+		end
+	end
+	local dirty
+	if level.lastDirection == "RIGHT" then
+		if sliderFrame:GetRight() > GetScreenWidth() then
+			level.lastDirection = "LEFT"
+			dirty = true
+		end
+	elseif sliderFrame:GetLeft() < 0 then
+		level.lastDirection = "RIGHT"
+		dirty = true
+	end
+	if level.lastVDirection == "DOWN" then
+		if sliderFrame:GetBottom() < 0 then
+			level.lastVDirection = "UP"
+			dirty = true
+		end
+	elseif sliderFrame:GetTop() > GetScreenWidth() then
+		level.lastVDirection = "DOWN"
+		dirty = true
+	end
+	if dirty then
+		sliderFrame:ClearAllPoints()
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom()
+	sliderFrame:ClearAllPoints()
+	sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	if mod(level.num, 5) == 0 then
+		local left, bottom = level:GetLeft(), level:GetBottom()
+		level:ClearAllPoints()
+		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	end
+	sliderFrame:SetClampedToScreen(true)
+end
+
+function OpenEditBox(self, parent)
+	if not editBoxFrame then
+		editBoxFrame = CreateFrame("Frame", nil, nil)
+		editBoxFrame:SetWidth(200)
+		editBoxFrame:SetHeight(40)
+		editBoxFrame:SetScale(UIParent:GetScale())
+		editBoxFrame:SetBackdrop(tmp(
+			'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
+			'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
+			'tile', true,
+			'insets', tmp2(
+				'left', 5,
+				'right', 5,
+				'top', 5,
+				'bottom', 5
+			),
+			'tileSize', 16,
+			'edgeSize', 16
+		))
+		editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+		if editBoxFrame.SetTopLevel then
+			editBoxFrame:SetTopLevel(true)
+		end
+		editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
+		editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
+		editBoxFrame:EnableMouse(true)
+		editBoxFrame:EnableMouseWheel(true)
+		editBoxFrame:Hide()
+		editBoxFrame:SetPoint("CENTER", UIParent, "CENTER")
+
+		local editBox = CreateFrame("EditBox", nil, editBoxFrame)
+		editBoxFrame.editBox = editBox
+		editBox:SetFontObject(ChatFontNormal)
+		editBox:SetWidth(160)
+		editBox:SetHeight(13)
+		editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0)
+
+		local left = editBox:CreateTexture(nil, "BACKGROUND")
+		left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
+		left:SetTexCoord(0, 100 / 256, 0, 1)
+		left:SetWidth(100)
+		left:SetHeight(32)
+		left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
+		local right = editBox:CreateTexture(nil, "BACKGROUND")
+		right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
+		right:SetTexCoord(156/256, 1, 0, 1)
+		right:SetWidth(100)
+		right:SetHeight(32)
+		right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
+
+		editBox:SetScript("OnEnterPressed", function()
+			if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then
+				local t = editBox.realText or editBox:GetText() or ""
+				local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t))
+				if not result then
+					UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0)
+					return
+				end
+			end
+			if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then
+				local t
+				if editBox.realText ~= "NONE" then
+					t = editBox.realText or editBox:GetText() or ""
+				end
+				editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t))
+			end
+			self:Close(editBoxFrame.level)
+			for i = 1, editBoxFrame.level - 1 do
+				Refresh(self, levels[i])
+			end
+			StartCounting(self, editBoxFrame.level-1)
+		end)
+		editBox:SetScript("OnEscapePressed", function()
+			self:Close(editBoxFrame.level)
+			StartCounting(self, editBoxFrame.level-1)
+		end)
+		editBox:SetScript("OnReceiveDrag", function(this)
+			if GetCursorInfo then
+				local type, alpha, bravo = GetCursorInfo()
+				local text
+				if type == "spell" then
+					text = GetSpellName(alpha, bravo)
+				elseif type == "item" then
+					text = bravo
+				end
+				if not text then
+					return
+				end
+				ClearCursor()
+				editBox:SetText(text)
+			end
+		end)
+		local changing = false
+		local skipNext = false
+
+		function editBox:SpecialSetText(text)
+			local oldText = editBox:GetText() or ""
+			if not text then
+				text = ""
+			end
+			if text ~= oldText then
+				changing = true
+				self:SetText(tostring(text))
+				changing = false
+				skipNext = true
+			end
+		end
+
+		editBox:SetScript("OnTextChanged", function()
+			if skipNext then
+				skipNext = false
+			elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then
+				local t
+				if editBox.realText ~= "NONE" then
+					t = editBox.realText or editBox:GetText() or ""
+				end
+				local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t))
+				if text then
+					editBox:SpecialSetText(text)
+				end
+			end
+		end)
+		editBoxFrame:SetScript("OnEnter", function()
+			StopCounting(self, editBoxFrame.level)
+			showGameTooltip(editBoxFrame.parent)
+		end)
+		editBoxFrame:SetScript("OnLeave", function()
+			GameTooltip:Hide()
+		end)
+		editBox:SetScript("OnEnter", function()
+			StopCounting(self, editBoxFrame.level)
+			showGameTooltip(editBoxFrame.parent)
+		end)
+		editBox:SetScript("OnLeave", function()
+			GameTooltip:Hide()
+		end)
+		editBoxFrame:SetScript("OnKeyDown", function(this, a1)
+			if not editBox.keybinding then
+				return
+			end
+			local arg1 = a1 or arg1
+			local screenshotKey = GetBindingKey("SCREENSHOT")
+			if screenshotKey and arg1 == screenshotKey then
+				Screenshot()
+				return
+			end
+
+			if arg1 == "LeftButton" then
+				arg1 = "BUTTON1"
+			elseif arg1 == "RightButton" then
+				arg1 = "BUTTON2"
+			elseif arg1 == "MiddleButton" then
+				arg1 = "BUTTON3"
+			elseif arg1 == "Button4" then
+				arg1 = "BUTTON4"
+			elseif arg1 == "Button5" then
+				arg1 = "BUTTON5"
+			end
+			if arg1 == "UNKNOWN" then
+				return
+			elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then
+				return
+			elseif arg1 == "ENTER" then
+				if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then
+					return editBox:GetScript("OnEscapePressed")()
+				elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then
+					return editBox:GetScript("OnEscapePressed")()
+				else
+					return editBox:GetScript("OnEnterPressed")()
+				end
+			elseif arg1 == "ESCAPE" then
+				if editBox.realText == "NONE" then
+					return editBox:GetScript("OnEscapePressed")()
+				else
+					editBox:SpecialSetText(NONE or "NONE")
+					editBox.realText = "NONE"
+					return
+				end
+			elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then
+				return
+			elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then
+				return
+			end
+			local s = GetBindingText(arg1, "KEY_")
+			if s == "BUTTON1" then
+				s = KEY_BUTTON1
+			elseif s == "BUTTON2" then
+				s = KEY_BUTTON2
+			end
+			local real = arg1
+			if IsShiftKeyDown() then
+				s = "Shift-" .. s
+				real = "SHIFT-" .. real
+			end
+			if IsControlKeyDown() then
+				s = "Ctrl-" .. s
+				real = "CTRL-" .. real
+			end
+			if IsAltKeyDown() then
+				s = "Alt-" .. s
+				real = "ALT-" .. real
+			end
+			if editBox:GetText() ~= s then
+				editBox:SpecialSetText("-")
+				editBox:SpecialSetText(s)
+				editBox.realText = real
+				return editBox:GetScript("OnTextChanged")()
+			end
+		end)
+		editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown"))
+		editBox:SetScript("OnMouseDown", function(this, ...)
+			if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then
+				return editBox:GetScript("OnReceiveDrag")(this, ...)
+			end
+			return editBoxFrame:GetScript("OnKeyDown")(this, ...)
+		end)
+		editBoxFrame:SetScript("OnMouseWheel", function(t, a1)
+			local arg1 = a1 or arg1
+			local up = arg1 > 0
+			arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN"
+			return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1)
+		end)
+		editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel"))
+	end
+	editBoxFrame.parent = parent
+	editBoxFrame.level = parent.level.num + 1
+	editBoxFrame.parentValue = parent.level.value
+	editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
+	editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1)
+	editBoxFrame.editBox.realText = nil
+	editBoxFrame:SetClampedToScreen(false)
+
+	editBoxFrame.editBox:SpecialSetText("")
+	if parent.editBoxIsKeybinding then
+		local s = parent.editBoxText
+		if s == "" then
+			s =  "NONE"
+		end
+		editBoxFrame.editBox.realText = s
+		if s and s ~= "NONE" then
+			local alpha,bravo = s:match("^(.+)%-(.+)$")
+			if not bravo then
+				alpha = nil
+				bravo = s
+			end
+			bravo = GetBindingText(bravo, "KEY_")
+			if alpha then
+				editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo)
+			else
+				editBoxFrame.editBox:SpecialSetText(bravo)
+			end
+		else
+			editBoxFrame.editBox:SpecialSetText(NONE or "NONE")
+		end
+	else
+		editBoxFrame.editBox:SpecialSetText(parent.editBoxText)
+	end
+
+	editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding
+	editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly
+	editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept
+	editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding)
+	editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding)
+
+	if parent.arrow then
+--		parent.arrow:SetVertexColor(0.2, 0.6, 0)
+--		parent.arrow:SetHeight(24)
+--		parent.arrow:SetWidth(24)
+		parent.selected = true
+		parent.highlight:Show()
+	end
+
+	local level = parent.level
+	editBoxFrame:Show()
+	editBoxFrame:ClearAllPoints()
+	if level.lastDirection == "RIGHT" then
+		if level.lastVDirection == "DOWN" then
+			editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+		else
+			editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+		end
+	else
+		if level.lastVDirection == "DOWN" then
+			editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+		else
+			editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+		end
+	end
+	local dirty
+	if level.lastDirection == "RIGHT" then
+		if editBoxFrame:GetRight() > GetScreenWidth() then
+			level.lastDirection = "LEFT"
+			dirty = true
+		end
+	elseif editBoxFrame:GetLeft() < 0 then
+		level.lastDirection = "RIGHT"
+		dirty = true
+	end
+	if level.lastVDirection == "DOWN" then
+		if editBoxFrame:GetBottom() < 0 then
+			level.lastVDirection = "UP"
+			dirty = true
+		end
+	elseif editBoxFrame:GetTop() > GetScreenWidth() then
+		level.lastVDirection = "DOWN"
+		dirty = true
+	end
+	if dirty then
+		editBoxFrame:ClearAllPoints()
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom()
+	editBoxFrame:ClearAllPoints()
+	editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	if mod(level.num, 5) == 0 then
+		local left, bottom = level:GetLeft(), level:GetBottom()
+		level:ClearAllPoints()
+		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	end
+	editBoxFrame:SetClampedToScreen(true)
+end
+
+function Dewdrop:EncodeKeybinding(text)
+	if text == nil or text == "NONE" then
+		return nil
+	end
+	text = tostring(text):upper()
+	local shift, ctrl, alt
+	local modifier
+	while true do
+		if text == "-" then
+			break
+		end
+		modifier, text = strsplit('-', text, 2)
+		if text then
+			if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
+				return false
+			end
+			if modifier == "SHIFT" then
+				if shift then
+					return false
+				end
+				shift = true
+			end
+			if modifier == "CTRL" then
+				if ctrl then
+					return false
+				end
+				ctrl = true
+			end
+			if modifier == "ALT" then
+				if alt then
+					return false
+				end
+				alt = true
+			end
+		else
+			text = modifier
+			break
+		end
+	end
+	if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then
+		return false
+	end
+	local s = GetBindingText(text, "KEY_")
+	if s == "BUTTON1" then
+		s = KEY_BUTTON1
+	elseif s == "BUTTON2" then
+		s = KEY_BUTTON2
+	end
+	if shift then
+		s = "Shift-" .. s
+	end
+	if ctrl then
+		s = "Ctrl-" .. s
+	end
+	if alt then
+		s = "Alt-" .. s
+	end
+	return s
+end
+
+function Dewdrop:IsOpen(parent)
+	self:argCheck(parent, 2, "table", "string", "nil")
+	return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent())
+end
+
+function Dewdrop:GetOpenedParent()
+	return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent())
+end
+
+function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY)
+	self:Close(level)
+	if DewdropLib then
+		local d = DewdropLib:GetInstance('1.0')
+		local ret, val = pcall(d, IsOpen, d)
+		if ret and val then
+			DewdropLib:GetInstance('1.0'):Close()
+		end
+	end
+	if type(parent) == "table" then
+		parent:GetCenter()
+	end
+	local frame = AcquireLevel(self, level)
+	if level == 1 then
+		frame.lastDirection = "RIGHT"
+		frame.lastVDirection = "DOWN"
+	else
+		frame.lastDirection = levels[level - 1].lastDirection
+		frame.lastVDirection = levels[level - 1].lastVDirection
+	end
+	frame:SetFrameStrata("FULLSCREEN_DIALOG")
+	frame:ClearAllPoints()
+	frame.parent = parent
+	frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0)
+	frame:Show()
+	if level == 1 then
+		baseFunc = func
+	end
+	levels[level].value = value
+--	levels[level].parentText = parent.text and parent.text:GetText() or nil
+--	levels[level].parentTooltipTitle = parent.tooltipTitle
+--	levels[level].parentTooltipText = parent.tooltipText
+--	levels[level].parentTooltipFunc = parent.tooltipFunc
+	if type(parent) == "table" and parent.arrow then
+--		parent.arrow:SetVertexColor(0.2, 0.6, 0)
+--		parent.arrow:SetHeight(24)
+--		parent.arrow:SetWidth(24)
+		parent.selected = true
+		parent.highlight:Show()
+	end
+	relativePoint = relativePoint or point
+	Refresh(self, levels[level])
+	if point or (cursorX and cursorY) then
+		frame:ClearAllPoints()
+		if cursorX and cursorY then
+			local curX, curY = GetScaledCursorPosition()
+			if curY < GetScreenHeight() / 2 then
+				point, relativePoint = "BOTTOM", "BOTTOM"
+			else
+				point, relativePoint = "TOP", "TOP"
+			end
+			if curX < GetScreenWidth() / 2 then
+				point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT"
+			else
+				point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT"
+			end
+		end
+		frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint)
+		if cursorX and cursorY then
+			local left = frame:GetLeft()
+			local width = frame:GetWidth()
+			local bottom = frame:GetBottom()
+			local height = frame:GetHeight()
+			local curX, curY = GetScaledCursorPosition()
+			frame:ClearAllPoints()
+			relativePoint = relativePoint or point
+			if point == "BOTTOM" or point == "TOP" then
+				if curX < GetScreenWidth() / 2 then
+					point = point .. "LEFT"
+				else
+					point = point .. "RIGHT"
+				end
+			elseif point == "CENTER" then
+				if curX < GetScreenWidth() / 2 then
+					point = "LEFT"
+				else
+					point = "RIGHT"
+				end
+			end
+			local xOffset, yOffset = 0, 0
+			if curY > GetScreenHeight() / 2 then
+				yOffset = -height
+			end
+			if curX > GetScreenWidth() / 2 then
+				xOffset = -width
+			end
+			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset)
+			if level == 1 then
+				frame.lastDirection = "RIGHT"
+			end
+		elseif cursorX then
+			local left = frame:GetLeft()
+			local width = frame:GetWidth()
+			local curX, curY = GetScaledCursorPosition()
+			frame:ClearAllPoints()
+			relativePoint = relativePoint or point
+			if point == "BOTTOM" or point == "TOP" then
+				if curX < GetScreenWidth() / 2 then
+					point = point .. "LEFT"
+				else
+					point = point .. "RIGHT"
+				end
+			elseif point == "CENTER" then
+				if curX < GetScreenWidth() / 2 then
+					point = "LEFT"
+				else
+					point = "RIGHT"
+				end
+			end
+			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0)
+			if level == 1 then
+				frame.lastDirection = "RIGHT"
+			end
+		elseif cursorY then
+			local bottom = frame:GetBottom()
+			local height = frame:GetHeight()
+			local curX, curY = GetScaledCursorPosition()
+			frame:ClearAllPoints()
+			relativePoint = relativePoint or point
+			if point == "LEFT" or point == "RIGHT" then
+				if curX < GetScreenHeight() / 2 then
+					point = point .. "BOTTOM"
+				else
+					point = point .. "TOP"
+				end
+			elseif point == "CENTER" then
+				if curX < GetScreenHeight() / 2 then
+					point = "BOTTOM"
+				else
+					point = "TOP"
+				end
+			end
+			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2)
+			if level == 1 then
+				frame.lastDirection = "DOWN"
+			end
+		end
+		if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then
+			if frame:GetBottom() < 0 then
+				local point, parent, relativePoint, x, y = frame:GetPoint(1)
+				local change = GetScreenHeight() - frame:GetTop()
+				local otherChange = -frame:GetBottom()
+				if otherChange < change then
+					change = otherChange
+				end
+				frame:SetPoint(point, parent, relativePoint, x, y + change)
+			elseif frame:GetTop() > GetScreenHeight() then
+				local point, parent, relativePoint, x, y = frame:GetPoint(1)
+				local change = GetScreenHeight() - frame:GetTop()
+				local otherChange = -frame:GetBottom()
+				if otherChange < change then
+					change = otherChange
+				end
+				frame:SetPoint(point, parent, relativePoint, x, y + change)
+			end
+		end
+	end
+	CheckDualMonitor(self, frame)
+	frame:SetClampedToScreen(true)
+	frame:SetClampedToScreen(false)
+	StartCounting(self, level)
+end
+
+function Dewdrop:IsRegistered(parent)
+	self:argCheck(parent, 2, "table", "string")
+	return not not self.registry[parent]
+end
+
+function Dewdrop:Register(parent, ...)
+	self:argCheck(parent, 2, "table", "string")
+	if self.registry[parent] then
+		self:Unregister(parent)
+	end
+	local info = new(...)
+	if type(info.children) == "table" then
+		local err, position = validateOptions(info.children)
+
+		if err then
+			if position then
+				Dewdrop:error(position .. ": " .. err)
+			else
+				Dewdrop:error(err)
+			end
+		end
+	end
+	self.registry[parent] = info
+	if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then
+		if parent:HasScript("OnMouseUp") then
+			local script = parent:GetScript("OnMouseUp")
+			parent:SetScript("OnMouseUp", function(this, ...)
+				if script then
+					script(this, ...)
+				end
+				if arg1 == "RightButton" and self.registry[parent] then
+					if self:IsOpen(parent) then
+						self:Close()
+					else
+						self:Open(parent)
+					end
+				end
+			end)
+		end
+		if parent:HasScript("OnMouseDown") then
+			local script = parent:GetScript("OnMouseDown")
+			parent:SetScript("OnMouseDown", function(this, ...)
+				if script then
+					script(this, ...)
+				end
+				if self.registry[parent] then
+					self:Close()
+				end
+			end)
+		end
+	end
+	self.onceRegistered[parent] = true
+end
+
+function Dewdrop:Unregister(parent)
+	self:argCheck(parent, 2, "table", "string")
+	self.registry[parent] = nil
+end
+
+function Dewdrop:Open(parent, ...)
+	self:argCheck(parent, 2, "table", "string")
+	local info
+	local k1 = ...
+	if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then
+		info = tmp(select(2, ...))
+		for k,v in pairs(self.registry[k1]) do
+			if info[k] == nil then
+				info[k] = v
+			end
+		end
+	else
+		info = tmp(...)
+		if self.registry[parent] then
+			for k,v in pairs(self.registry[parent]) do
+				if info[k] == nil then
+					info[k] = v
+				end
+			end
+		end
+	end
+	local point = info.point
+	local relativePoint = info.relativePoint
+	local cursorX = info.cursorX
+	local cursorY = info.cursorY
+	if type(point) == "function" then
+		local b
+		point, b = point(parent)
+		if b then
+			relativePoint = b
+		end
+	end
+	if type(relativePoint) == "function" then
+		relativePoint = relativePoint(parent)
+	end
+	Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY)
+end
+
+function Clear(self, level)
+	if level then
+		if level.buttons then
+			for i = #level.buttons, 1, -1 do
+				ReleaseButton(self, level, i)
+			end
+		end
+	end
+end
+
+function Dewdrop:Close(level)
+	if DropDownList1:IsShown() then
+		DropDownList1:Hide()
+	end
+	if DewdropLib then
+		local d = DewdropLib:GetInstance('1.0')
+		local ret, val = pcall(d, IsOpen, d)
+		if ret and val then
+			DewdropLib:GetInstance('1.0'):Close()
+		end
+	end
+	self:argCheck(level, 2, "number", "nil")
+	if not level then
+		level = 1
+	end
+	if level == 1 and levels[level] then
+		levels[level].parented = false
+	end
+	if level > 1 and levels[level-1].buttons then
+		local buttons = levels[level-1].buttons
+		for _,button in ipairs(buttons) do
+--			button.arrow:SetWidth(16)
+--			button.arrow:SetHeight(16)
+			button.selected = nil
+			button.highlight:Hide()
+--			button.arrow:SetVertexColor(1, 1, 1)
+		end
+	end
+	if sliderFrame and sliderFrame.level >= level then
+		sliderFrame:Hide()
+	end
+	if editBoxFrame and editBoxFrame.level >= level then
+		editBoxFrame:Hide()
+	end
+	for i = level, #levels do
+		Clear(self, levels[level])
+		levels[i]:Hide()
+		levels[i]:ClearAllPoints()
+		levels[i]:SetPoint("CENTER", UIParent, "CENTER")
+		levels[i].value = nil
+	end
+end
+
+function Dewdrop:AddSeparator(level)
+	level = levels[level or currentLevel]
+	if not level or not level.buttons then return; end
+
+	local prevbutton = level.buttons[#level.buttons]
+	if not prevbutton then return; end
+
+	if prevbutton.disabled and prevbutton.text:GetText() == "" then
+		return
+	end
+	self:AddLine("text", "", "disabled", true)
+end
+
+function Dewdrop:AddLine(...)
+	local info = tmp(...)
+	local level = info.level or currentLevel
+	info.level = nil
+	local button = AcquireButton(self, level)
+	if not next(info) then
+		info.disabled = true
+	end
+	button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure)
+	button.isTitle = info.isTitle
+	button.notClickable = info.notClickable
+	if button.isTitle then
+		button.text:SetFontObject(GameFontNormalSmall)
+	elseif button.notClickable then
+		button.text:SetFontObject(GameFontHighlightSmall)
+	elseif button.disabled then
+		button.text:SetFontObject(GameFontDisableSmall)
+	else
+		button.text:SetFontObject(GameFontHighlightSmall)
+	end
+	if info.disabled then
+		button.arrow:SetDesaturated(true)
+		button.check:SetDesaturated(true)
+	else
+		button.arrow:SetDesaturated(false)
+		button.check:SetDesaturated(false)
+	end
+	if info.textR and info.textG and info.textB then
+		button.textR = info.textR
+		button.textG = info.textG
+		button.textB = info.textB
+		button.text:SetTextColor(button.textR, button.textG, button.textB)
+	else
+		button.text:SetTextColor(button.text:GetFontObject():GetTextColor())
+	end
+	button.notCheckable = info.notCheckable
+	button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0)
+	button.checked = not info.notCheckable and info.checked
+	button.mouseoverUnderline = info.mouseoverUnderline
+	button.isRadio = not info.notCheckable and info.isRadio
+	if info.isRadio then
+		button.check:Show()
+		button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
+		if button.checked then
+			button.check:SetTexCoord(0.25, 0.5, 0, 1)
+			button.check:SetVertexColor(1, 1, 1, 1)
+		else
+			button.check:SetTexCoord(0, 0.25, 0, 1)
+			button.check:SetVertexColor(1, 1, 1, 0.5)
+		end
+		button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
+		button.check:SetWidth(16)
+		button.check:SetHeight(16)
+	elseif info.icon then
+		button.check:Show()
+		button.check:SetTexture(info.icon)
+		if info.iconWidth and info.iconHeight then
+			button.check:SetWidth(info.iconWidth)
+			button.check:SetHeight(info.iconHeight)
+		else
+			button.check:SetWidth(16)
+			button.check:SetHeight(16)
+		end
+		if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then
+			button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom)
+		elseif info.icon:find("^Interface\\Icons\\") then
+			button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
+		else
+			button.check:SetTexCoord(0, 1, 0, 1)
+		end
+		button.check:SetVertexColor(1, 1, 1, 1)
+	else
+		if button.checked then
+			if info.checkIcon then
+				button.check:SetWidth(16)
+				button.check:SetHeight(16)
+				button.check:SetTexture(info.checkIcon)
+				if info.checkIcon:find("^Interface\\Icons\\") then
+					button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
+				else
+					button.check:SetTexCoord(0, 1, 0, 1)
+				end
+			else
+				button.check:SetWidth(24)
+				button.check:SetHeight(24)
+				button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+				button.check:SetTexCoord(0, 1, 0, 1)
+			end
+			button.check:SetVertexColor(1, 1, 1, 1)
+		else
+			button.check:SetVertexColor(1, 1, 1, 0)
+		end
+	end
+	if not button.disabled then
+		button.func = info.func
+		button.secure = info.secure
+	end
+	button.hasColorSwatch = info.hasColorSwatch
+	if button.hasColorSwatch then
+		button.colorSwatch:Show()
+		button.colorSwatch.texture:Show()
+		button.r = info.r or 1
+		button.g = info.g or 1
+		button.b = info.b or 1
+		button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b)
+		button.checked = false
+		button.func = nil
+		button.colorFunc = info.colorFunc
+		local i = 1
+		while true do
+			local k = "colorArg" .. i
+			local x = info[k]
+			if x == nil then
+				break
+			end
+			button[k] = x
+			i = i + 1
+		end
+		button.hasOpacity = info.hasOpacity
+		button.opacity = info.opacity or 1
+	else
+		button.colorSwatch:Hide()
+		button.colorSwatch.texture:Hide()
+	end
+	button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow
+	if button.hasArrow then
+		button.arrow:SetAlpha(1)
+		if info.hasSlider then
+			button.hasSlider = true
+			button.sliderMin = info.sliderMin or 0
+			button.sliderMax = info.sliderMax or 1
+			button.sliderStep = info.sliderStep or 0
+			button.sliderBigStep = info.sliderBigStep or button.sliderStep
+			if button.sliderBigStep < button.sliderStep then
+				button.sliderBigStep = button.sliderStep
+			end
+			button.sliderIsPercent = info.sliderIsPercent and true or false
+			button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin
+			button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax
+			button.sliderFunc = info.sliderFunc
+			button.sliderValue = info.sliderValue
+			button.fromAceOptions = info.fromAceOptions
+			local i = 1
+			while true do
+				local k = "sliderArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+		elseif info.hasEditBox then
+			button.hasEditBox = true
+			button.editBoxText = info.editBoxText or ""
+			button.editBoxFunc = info.editBoxFunc
+			local i = 1
+			while true do
+				local k = "editBoxArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+			button.editBoxChangeFunc = info.editBoxChangeFunc
+			local i = 1
+			while true do
+				local k = "editBoxChangeArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+			button.editBoxValidateFunc = info.editBoxValidateFunc
+			local i = 1
+			while true do
+				local k = "editBoxValidateArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+			button.editBoxIsKeybinding = info.editBoxIsKeybinding
+			button.editBoxKeybindingOnly = info.editBoxKeybindingOnly
+			button.editBoxKeybindingExcept = info.editBoxKeybindingExcept
+		else
+			button.value = info.value
+			local l = levels[level+1]
+			if l and info.value == l.value then
+--				button.arrow:SetWidth(24)
+--				button.arrow:SetHeight(24)
+				button.selected = true
+				button.highlight:Show()
+			end
+		end
+	else
+		button.arrow:SetAlpha(0)
+	end
+	local i = 1
+	while true do
+		local k = "arg" .. i
+		local x = info[k]
+		if x == nil then
+			break
+		end
+		button[k] = x
+		i = i + 1
+	end
+	button.closeWhenClicked = info.closeWhenClicked
+	button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10
+	local font,_ = button.text:GetFont()
+	button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight)
+	button:SetHeight(button.textHeight + 6)
+	button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT")
+	button.text:SetJustifyH(info.justifyH or "LEFT")
+	button.text:SetText(info.text)
+	button.tooltipTitle = info.tooltipTitle
+	button.tooltipText = info.tooltipText
+	button.tooltipFunc = info.tooltipFunc
+	local i = 1
+	while true do
+		local k = "tooltipArg" .. i
+		local x = info[k]
+		if x == nil then
+			break
+		end
+		button[k] = x
+		i = i + 1
+	end
+	if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then
+		button.tooltipTitle = info.text
+	end
+	if type(button.func) == "string" then
+		if type(button.arg1) ~= "table" then
+			self:error("Cannot call method %q on a non-table", button.func)
+		end
+		if type(button.arg1[button.func]) ~= "function" then
+			self:error("Method %q nonexistant.", button.func)
+		end
+	end
+end
+
+function Dewdrop:InjectAceOptionsTable(handler, options)
+	self:argCheck(handler, 2, "table")
+	self:argCheck(options, 3, "table")
+	if tostring(options.type):lower() ~= "group" then
+		self:error('Cannot inject into options table argument #3 if its type is not "group"')
+	end
+	if options.handler ~= nil and options.handler ~= handler then
+		self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2")
+	end
+	options.handler = handler
+	local class = handler.class
+	if not AceLibrary:HasInstance("AceOO-2.0") or not class then
+		if Rock then
+			-- possible Rock object
+			for mixin in Rock:IterateObjectMixins(handler) do
+				if type(mixin.GetAceOptionsDataTable) == "function" then
+					local t = mixin:GetAceOptionsDataTable(handler)
+					for k,v in pairs(t) do
+						if type(options.args) ~= "table" then
+							options.args = {}
+						end
+						if options.args[k] == nil then
+							options.args[k] = v
+						end
+					end
+				end
+			end
+		end
+	else
+		-- Ace2 object
+		while class and class ~= AceLibrary("AceOO-2.0").Class do
+			if type(class.GetAceOptionsDataTable) == "function" then
+				local t = class:GetAceOptionsDataTable(handler)
+				for k,v in pairs(t) do
+					if type(options.args) ~= "table" then
+						options.args = {}
+					end
+					if options.args[k] == nil then
+						options.args[k] = v
+					end
+				end
+			end
+			local mixins = class.mixins
+			if mixins then
+				for mixin in pairs(mixins) do
+					if type(mixin.GetAceOptionsDataTable) == "function" then
+						local t = mixin:GetAceOptionsDataTable(handler)
+						for k,v in pairs(t) do
+							if type(options.args) ~= "table" then
+								options.args = {}
+							end
+							if options.args[k] == nil then
+								options.args[k] = v
+							end
+						end
+					end
+				end
+			end
+			class = class.super
+		end
+	end
+	return options
+end
+
+function Dewdrop:OnTooltipHide()
+	if lastSetFont then
+		if lastSetFont == normalFont then
+			lastSetFont = nil
+			return
+		end
+		fillRegionTmp(GameTooltip:GetRegions())
+		for i,v in ipairs(regionTmp) do
+			if v.GetFont then
+				local font,size,outline = v:GetFont()
+				if font == lastSetFont then
+					v:SetFont(normalFont, size, outline)
+				end
+			end
+			regionTmp[i] = nil
+		end
+		lastSetFont = nil
+	end
+end
+
+local function activate(self, oldLib, oldDeactivate)
+	Dewdrop = self
+	if oldLib and oldLib.registry then
+		self.registry = oldLib.registry
+		self.onceRegistered = oldLib.onceRegistered
+	else
+		self.registry = {}
+		self.onceRegistered = {}
+
+		local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown")
+		local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp")
+		local oldX, oldY, clickTime
+		WorldFrame:SetScript("OnMouseDown", function(this, ...)
+			oldX,oldY = GetCursorPosition()
+			clickTime = GetTime()
+			if WorldFrame_OnMouseDown then
+				WorldFrame_OnMouseDown(this, ...)
+			end
+		end)
+
+		WorldFrame:SetScript("OnMouseUp", function(this, ...)
+			local x,y = GetCursorPosition()
+			if not oldX or not oldY or not x or not y or not clickTime then
+				self:Close()
+				if WorldFrame_OnMouseUp then
+					WorldFrame_OnMouseUp(this, ...)
+				end
+				return
+			end
+			local d = math.abs(x - oldX) + math.abs(y - oldY)
+			if d <= 5 and GetTime() - clickTime < 0.5 then
+				self:Close()
+			end
+			if WorldFrame_OnMouseUp then
+				WorldFrame_OnMouseUp(this, ...)
+			end
+		end)
+
+		hooksecurefunc(DropDownList1, "Show", function()
+			if levels[1] and levels[1]:IsVisible() then
+				self:Close()
+			end
+		end)
+
+		hooksecurefunc("HideDropDownMenu", function()
+			if levels[1] and levels[1]:IsVisible() then
+				self:Close()
+			end
+		end)
+
+		hooksecurefunc("CloseDropDownMenus", function()
+			if levels[1] and levels[1]:IsVisible() then
+				local stack = debugstack()
+				if not stack:find("`TargetFrame_OnHide'") then
+					self:Close()
+				end
+			end
+		end)
+	end
+	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
+	self.frame:UnregisterAllEvents()
+	self.frame:RegisterEvent("PLAYER_REGEN_ENABLED")
+	self.frame:RegisterEvent("PLAYER_REGEN_DISABLED")
+	self.frame:Hide()
+	self.frame:SetScript("OnEvent", function(this, event)
+		this:Show()
+		if event=="PLAYER_REGEN_ENABLED" then			-- track combat state for secure frame operations
+			self.combat = false
+		elseif event=="PLAYER_REGEN_DISABLED" then
+			self.combat = true
+		end
+	end)
+	self.frame:SetScript("OnUpdate", function(this)
+		this:Hide()
+		self:Refresh(1)
+	end)
+	self.hookedTooltip = true
+	if not oldLib or not oldLib.hookedTooltip then
+		local OnTooltipHide = GameTooltip:GetScript("OnHide")
+		GameTooltip:SetScript("OnHide", function(this, ...)
+			if OnTooltipHide then
+				OnTooltipHide(this, ...)
+			end
+			if type(self.OnTooltipHide) == "function" then
+				self:OnTooltipHide()
+			end
+		end)
+	end
+	levels = {}
+	buttons = {}
+
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+local function external(lib, major, instance)
+	if major == "SharedMedia-1.0" then
+		SharedMedia = instance
+	end
+end
+
+AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/modules/ReAction_Action/ReAction_Action.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/ReAction_Action/ReAction_Action.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -11,34 +11,22 @@
 local ReAction = ReAction
 local L = ReAction.L
 local _G = _G
-local AceOO = AceLibrary("AceOO-2.0")
 local CreateFrame = CreateFrame
 local print = ReAction.print
 
 -- module declaration
 local moduleID = "Action"
-local module = ReAction:NewModule( moduleID,
-  "AceEvent-2.0"
-)
-
---
--- action button class declaration
---
-local BtnClass = AceOO.Class()
-local Button = BtnClass.prototype
-module.BtnClass = BtnClass
-
-
+local module = ReAction:NewModule( moduleID )
 
 -- module methods
 function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
+  self.db = ReAction.db:RegisterNamespace( moduleID,
     { 
-      buttons = { }
+      profile = {
+        buttons = { }
+      }
     }
   )
-
   self.buttons = { }
 end
 
@@ -48,9 +36,6 @@
 function module:OnDisable()
 end
 
-function module:OnProfileEnable()
-end
-
 function module:ApplyToBar(bar)
   self:RefreshBar(bar)
 end
@@ -136,7 +121,7 @@
         name = L["New Action Bar"],
         desc = L["Create a new bar of standard action buttons"],
         func = function()
-                 ReAction:GetModule("Bar"):CreateBar()
+                 ReAction:CreateBar()
                end,
         disabled = InCombatLockdown,
       }
@@ -194,9 +179,11 @@
 
 
 
--- button class methods
-function Button:init( bar, idx, config )
-  BtnClass.super.prototype.init(self)
+
+------ Button class ------
+local Button = { }
+
+local function Constructor( self, bar, idx, config )
   self.bar, self.idx, self.config = bar, idx, config
 
   local barFrame = bar:GetFrame()
@@ -225,8 +212,8 @@
   f:Hide()
   f:SetParent(UIParent)
   f:ClearAllPoints()
-  if self.config.name then
-    _G[self.config.name] = nil
+  if self.name then
+    _G[self.name] = nil
   end
   ActionIDList[self.config.actionID] = nil
   self.frame = nil
@@ -249,3 +236,16 @@
 function Button:GetActionID()
   return self.config.actionID
 end
+
+
+-- export as a class-factory to module
+module.BtnClass = {
+  new = function(self, ...)
+    local x = { }
+    for k,v in pairs(Button) do
+      x[k] = v
+    end
+    Constructor(x, ...)
+    return x
+  end
+}
--- a/modules/ReAction_ConfigUI/ReAction_ConfigUI.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/ReAction_ConfigUI/ReAction_ConfigUI.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -30,13 +30,11 @@
 local Dewdrop = AceLibrary("Dewdrop-2.0")
 local print = ReAction.print
 local InCombatLockdown = InCombatLockdown
-local BarModule = ReAction:GetModule("Bar")
 
 -- module declaration
 local moduleID = "ConfigUI"
 local module = ReAction:NewModule( moduleID,
-  "AceConsole-2.0",  -- temp
-  "AceEvent-2.0"
+  "AceEvent-3.0"
   -- mixins go here
 )
 
@@ -97,17 +95,11 @@
 
 -- module methods
 function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
+  self.db = ReAction.db:RegisterNamespace( moduleID,
     {
-
+      profile = { }
     }
   )
-
-  -- temp: this will be moved to main ReAction.lua later in a more efficient AceConsole-less implementation
-  -- that can load the ConfigUI module on demand
-  -- NOTE: this inserts an 'about' command that we don't want
-  self:RegisterChatCommand( {L["/reaction"], L["/rxn"]}, self.globalOptions, "REACTION" )
 end
 
 function module:OnEnable()
@@ -136,8 +128,8 @@
 end
 
 function module:SetConfigMode( mode )
-  BarModule:CallMethodOnAllBars("ShowControls",mode)
-  ReAction:CallMethodOnAllModules("ApplyConfigMode",mode,BarModule.bars)
+  ReAction:CallMethodOnAllBars("ShowControls",mode)
+  ReAction:CallMethodOnAllModules("ApplyConfigMode",mode,ReAction.bars)
   self.configMode = mode
 end
 
@@ -161,11 +153,17 @@
   module:RefreshConfig()
 end
 
+local function SafeCall(module, method, ...)
+  if module and type(module[method]) == "function" then
+    return module[method](...)
+  end
+end
+
 function module:RefreshOptions()
   local opts = self.configOptions.args
   
-  for _, m in ReAction:IterateModulesWithMethod("GetGlobalOptions") do
-    local o = m:GetGlobalOptions(self)
+  for _, m in ReAction:IterateModules() do
+    local o = SafeCall(m,"GetGlobalOptions",self)
     if o then
       for k, v in pairs(o) do
         opts.global.args[k] = v
@@ -173,8 +171,8 @@
     end
   end
 
-  for _, m in ReAction:IterateModulesWithMethod("GetGlobalBarOptions") do
-    local o = m:GetGlobalBarOptions(self)
+  for _, m in ReAction:IterateModules() do
+    local o = SafeCall(m,"GetGlobalBarOptions",self)
     if o then
       for k, v in pairs(o) do
         opts.bar.args[k] = v
@@ -182,8 +180,8 @@
     end
   end
 
-  for _, m in ReAction:IterateModulesWithMethod("GetModuleOptions") do
-    local o = m:GetModuleOptions(self)
+  for _, m in ReAction:IterateModules() do
+    local o = SafeCall(m,"GetModuleOptions",self)
     if o then
       for k, v in pairs(o) do
         opts.module.args[k] = v
@@ -192,7 +190,7 @@
   end
 
   local barOpts = opts.bar.args
-  for name, bar in pairs(BarModule.bars) do
+  for name, bar in pairs(ReAction.bars) do
     if bar then
       if barOpts[name] == nil then
         barOpts[name] = {
@@ -200,14 +198,28 @@
           name = name,
           desc = name,
           handler = bar,
-          args = { }
+          args = { 
+            delete = {
+              type = "execute",
+              name = L["Delete Bar"],
+              desc = L["Remove the bar from the current profile"],
+              func = function() ReAction:EraseBar(bar); self:RefreshConfig() end
+            },
+            rename = {
+              type = "text",
+              name = L["Rename Bar"],
+              desc = L["Set a name for the bar"],
+              get  = "GetName",
+              set  = function(name) ReAction:RenameBar(bar,name); self:RefreshConfig() end
+            }
+          }
         }
       end
       if bar.modConfigOpts == nil then 
         bar.modConfigOpts = { }
       end
-      for _, m in ReAction:IterateModulesWithMethod("GetBarConfigOptions") do
-        local o = m:GetBarConfigOptions(bar,self)
+      for _, m in ReAction:IterateModules() do
+        local o = SafeCall(m,"GetBarConfigOptions",bar,self)
         if o then
           for k, v in pairs(o) do
             barOpts[name].args[k] = v
@@ -218,7 +230,7 @@
   end
   -- remove obsolete bar tables
   for name, opt in pairs(barOpts) do
-    if opt.type == "group" and BarModule.bars[name] == nil then
+    if opt.type == "group" and ReAction.bars[name] == nil then
       barOpts[name] = nil
     end
   end
@@ -262,7 +274,7 @@
 -- Bar config overlay
 --
 -- import some of these for small OnUpdate performance boost
-local Bar           = BarModule.BarClass.prototype
+local Bar           = ReAction.Bar.prototype
 local GetSize       = Bar.GetSize
 local GetButtonSize = Bar.GetButtonSize
 local GetButtonGrid = Bar.GetButtonGrid
@@ -280,7 +292,7 @@
   local point, relativeTo, relativePoint, x, y = f:GetPoint(1)
   relativeTo = relativeTo or f:GetParent()
   local anchorTo
-  for name, b in pairs(BarModule.bars) do
+  for name, b in pairs(ReAction.bars) do
     if b then
       if b:GetFrame() == relativeTo then
         anchorTo = name
@@ -534,8 +546,8 @@
     function()
       -- add bar type and status information to name
       local name = bar.name
-      for _, m in ReAction:IterateModulesWithMethod("GetBarNameModifier") do
-        local suffix = m:GetBarNameModifier(bar)
+      for _, m in ReAction:IterateModules() do
+        local suffix = SafeCall(m,"GetBarNameModifier",bar)
         if suffix then
           name = format("%s %s",name,suffix)
         end
@@ -584,16 +596,26 @@
           func = function() module:OpenConfig(self) end,
           disabled = InCombatLockdown,
           order = 1
-        }
+        },
+        delete = {
+          type = "execute",
+          name = L["Delete Bar"],
+          desc = L["Remove the bar from the current profile"],
+          func = function() ReAction:EraseBar(self) end,
+          order = 2
+        },
       }
     }
   end
   if self.modMenuOpts == nil then
     self.modMenuOpts = { }
   end
-  for _, m in ReAction:IterateModulesWithMethod("GetBarMenuOptions") do
-    for k, v in pairs(m:GetBarMenuOptions(self, module)) do
-      self.menuOpts.args[k] = v
+  for _, m in ReAction:IterateModules() do
+    local opts = SafeCall(m,"GetBarMenuOptions",self,module)
+    if opts then
+      for k, v in pairs(opts) do
+        self.menuOpts.args[k] = v
+      end
     end
   end
   Dewdrop:Open(self.controlFrame, "children", self.menuOpts, "cursorX", true, "cursorY", true)
--- a/modules/ReAction_ConfigUI/ReAction_ConfigUI.xml	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/ReAction_ConfigUI/ReAction_ConfigUI.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -2,7 +2,11 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
 
+  <Script file="lib\AceLibrary\AceLibrary.lua"/>
+  <Script file="lib\AceOO-2.0\AceOO-2.0.lua"/>
   <Script file="lib\Waterfall-1.0\Waterfall-1.0.lua"/>
+  <Script file="lib\Dewdrop-2.0\Dewdrop-2.0.lua"/>
+
   <Script file="ReAction_ConfigUI.lua"/>
 
 </Ui>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,856 @@
+--[[
+Name: AceLibrary
+Revision: $Rev: 49421 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Iriel (iriel@vigilance-committee.org)
+             Tekkub (tekkub@gmail.com)
+             Revision: $Rev: 49421 $
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/index.php/AceLibrary
+SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
+Description: Versioning library to handle other library instances, upgrading,
+             and proper access.
+             It also provides a base for libraries to work off of, providing
+             proper error tools. It is handy because all the errors occur in the
+             file that called it, not in the library file itself.
+Dependencies: None
+License: LGPL v2.1
+]]
+
+local ACELIBRARY_MAJOR = "AceLibrary"
+local ACELIBRARY_MINOR = "$Revision: 49421 $"
+
+local _G = getfenv(0)
+local previous = _G[ACELIBRARY_MAJOR]
+if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
+
+do
+	-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
+	-- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+	local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+	local LibStub = _G[LIBSTUB_MAJOR]
+
+	if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+		LibStub = LibStub or {libs = {}, minors = {} }
+		_G[LIBSTUB_MAJOR] = LibStub
+		LibStub.minor = LIBSTUB_MINOR
+		
+		function LibStub:NewLibrary(major, minor)
+			assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+			minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+			local oldminor = self.minors[major]
+			if oldminor and oldminor >= minor then return nil end
+			self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+			return self.libs[major], oldminor
+		end
+		
+		function LibStub:GetLibrary(major, silent)
+			if not self.libs[major] and not silent then
+				error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+			end
+			return self.libs[major], self.minors[major]
+		end
+		
+		function LibStub:IterateLibraries() return pairs(self.libs) end
+		setmetatable(LibStub, { __call = LibStub.GetLibrary })
+	end
+end
+local LibStub = _G.LibStub
+
+-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
+-- disabled in the addon screen, set this to true.
+local DONT_ENABLE_LIBRARIES = nil
+
+local function safecall(func,...)
+    local success, err = pcall(func,...)
+    if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
+end
+
+local WoW22 = false
+if type(GetBuildInfo) == "function" then
+	local success, buildinfo = pcall(GetBuildInfo)
+	if success and type(buildinfo) == "string" then
+		local num = tonumber(buildinfo:match("^(%d+%.%d+)"))
+		if num and num >= 2.2 then
+			WoW22 = true
+		end
+	end
+end
+
+-- @table AceLibrary
+-- @brief System to handle all versioning of libraries.
+local AceLibrary = {}
+local AceLibrary_mt = {}
+setmetatable(AceLibrary, AceLibrary_mt)
+
+local function error(self, message, ...)
+	if type(self) ~= "table" then
+		return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
+	end
+	
+	local stack = debugstack()
+	if not message then
+		local second = stack:match("\n(.-)\n")
+		message = "error raised! " .. second
+	else
+		local arg = { ... } -- not worried about table creation, as errors don't happen often
+		
+		for i = 1, #arg do
+			arg[i] = tostring(arg[i])
+		end
+		for i = 1, 10 do
+			table.insert(arg, "nil")
+		end
+		message = message:format(unpack(arg))
+	end
+	
+	if getmetatable(self) and getmetatable(self).__tostring then
+		message = ("%s: %s"):format(tostring(self), message)
+	elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
+		message = ("%s: %s"):format(self:GetLibraryVersion(), message)
+	elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
+		message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
+	end
+	
+	local first = stack:gsub("\n.*", "")
+	local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
+	file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
+	
+	
+	local i = 0
+	for s in stack:gmatch("\n([^\n]*)") do
+		i = i + 1
+		if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
+			file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
+			file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
+			break
+		end
+	end
+	local j = 0
+	for s in stack:gmatch("\n([^\n]*)") do
+		j = j + 1
+		if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
+			return _G.error(message, j+1)
+		end
+	end
+	return _G.error(message, 2)
+end
+
+local assert
+if not WoW22 then
+	function assert(self, condition, message, ...)
+		if not condition then
+			if not message then
+				local stack = debugstack()
+				local second = stack:match("\n(.-)\n")
+				message = "assertion failed! " .. second
+			end
+			return error(self, message, ...)
+		end
+		return condition
+	end
+end
+
+local type = type
+local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
+	if type(num) ~= "number" then
+		return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
+	elseif type(kind) ~= "string" then
+		return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
+	end
+	arg = type(arg)
+	if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
+		local stack = debugstack()
+		local func = stack:match("`argCheck'.-([`<].-['>])")
+		if not func then
+			func = stack:match("([`<].-['>])")
+		end
+		if kind5 then
+			return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
+		elseif kind4 then
+			return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
+		elseif kind3 then
+			return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
+		elseif kind2 then
+			return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
+		else
+			return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
+		end
+	end
+end
+
+local pcall
+do
+	local function check(self, ret, ...)
+		if not ret then
+			local s = ...
+			return error(self, (s:gsub(".-%.lua:%d-: ", "")))
+		else
+			return ...
+		end
+	end
+
+	function pcall(self, func, ...)
+		return check(self, _G.pcall(func, ...))
+	end
+end
+
+local recurse = {}
+local function addToPositions(t, major)
+	if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
+		rawset(t, recurse, true)
+		AceLibrary.positions[t] = major
+		for k,v in pairs(t) do
+			if type(v) == "table" and not rawget(v, recurse) then
+				addToPositions(v, major)
+			end
+			if type(k) == "table" and not rawget(k, recurse) then
+				addToPositions(k, major)
+			end
+		end
+		local mt = getmetatable(t)
+		if mt and not rawget(mt, recurse) then
+			addToPositions(mt, major)
+		end
+		rawset(t, recurse, nil)
+	end
+end
+
+local function svnRevisionToNumber(text)
+	local kind = type(text)
+	if kind == "number" or tonumber(text) then
+		return tonumber(text)
+	elseif kind == "string" then
+		if text:find("^%$Revision: (%d+) %$$") then
+			return tonumber((text:match("^%$Revision: (%d+) %$$")))
+		elseif text:find("^%$Rev: (%d+) %$$") then
+			return tonumber((text:match("^%$Rev: (%d+) %$$")))
+		elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
+			return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
+		end
+	end
+	return nil
+end
+
+local crawlReplace
+do
+	local recurse = {}
+	local function func(t, to, from)
+		if recurse[t] then
+			return
+		end
+		recurse[t] = true
+		local mt = getmetatable(t)
+		setmetatable(t, nil)
+		rawset(t, to, rawget(t, from))
+		rawset(t, from, nil)
+		for k,v in pairs(t) do
+			if v == from then
+				t[k] = to
+			elseif type(v) == "table" then
+				if not recurse[v] then
+					func(v, to, from)
+				end
+			end
+			
+			if type(k) == "table" then
+				if not recurse[k] then
+					func(k, to, from)
+				end
+			end
+		end
+		setmetatable(t, mt)
+		if mt then
+			if mt == from then
+				setmetatable(t, to)
+			elseif not recurse[mt] then
+				func(mt, to, from)
+			end
+		end
+	end
+	function crawlReplace(t, to, from)
+		func(t, to, from)
+		for k in pairs(recurse) do
+			recurse[k] = nil
+		end
+	end
+end
+
+-- @function destroyTable
+-- @brief    remove all the contents of a table
+-- @param t  table to destroy
+local function destroyTable(t)
+	setmetatable(t, nil)
+	for k,v in pairs(t) do
+		t[k] = nil 
+	end
+end
+
+local function isFrame(frame)
+	return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
+end
+
+-- @function   copyTable
+-- @brief      Create a shallow copy of a table and return it.
+-- @param from The table to copy from
+-- @return     A shallow copy of the table
+local function copyTable(from, to)
+	if not to then
+		to = {}
+	end
+	for k,v in pairs(from) do
+		to[k] = v
+	end
+	setmetatable(to, getmetatable(from))
+	return to
+end
+
+-- @function         deepTransfer
+-- @brief            Fully transfer all data, keeping proper previous table
+--                   backreferences stable.
+-- @param to         The table with which data is to be injected into
+-- @param from       The table whose data will be injected into the first
+-- @param saveFields If available, a shallow copy of the basic data is saved
+--                   in here.
+-- @param list       The account of table references
+-- @param list2      The current status on which tables have been traversed.
+local deepTransfer
+do
+	-- @function   examine
+	-- @brief      Take account of all the table references to be shared
+	--             between the to and from tables.
+	-- @param to   The table with which data is to be injected into
+	-- @param from The table whose data will be injected into the first
+	-- @param list An account of the table references
+	local function examine(to, from, list, major)
+		list[from] = to
+		for k,v in pairs(from) do
+			if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
+				if from[k] == to[k] then
+					list[from[k]] = to[k]
+				elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
+					list[from[k]] = from[k]
+				elseif not list[from[k]] then
+					examine(to[k], from[k], list, major)
+				end
+			end
+		end
+		return list
+	end
+	
+	function deepTransfer(to, from, saveFields, major, list, list2)
+		setmetatable(to, nil)
+		if not list then
+			list = {}
+			list2 = {}
+			examine(to, from, list, major)
+		end
+		list2[to] = to
+		for k,v in pairs(to) do
+			if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
+				if saveFields then
+					saveFields[k] = v
+				end
+				to[k] = nil
+			elseif v ~= _G then
+				if saveFields then
+					saveFields[k] = copyTable(v)
+				end
+			end
+		end
+		for k in pairs(from) do
+			if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
+				if not list2[to[k]] then
+					deepTransfer(to[k], from[k], nil, major, list, list2)
+				end
+				to[k] = list[to[k]] or list2[to[k]]
+			else
+				rawset(to, k, from[k])
+			end
+		end
+		setmetatable(to, getmetatable(from))
+		local mt = getmetatable(to)
+		if mt then
+			if list[mt] then
+				setmetatable(to, list[mt])
+			elseif mt.__index and list[mt.__index] then
+				mt.__index = list[mt.__index]
+			end
+		end
+		destroyTable(from)
+	end
+end
+
+local function TryToEnable(addon)
+	if DONT_ENABLE_LIBRARIES then return end
+	local isondemand = IsAddOnLoadOnDemand(addon)
+	if isondemand then
+		local _, _, _, enabled = GetAddOnInfo(addon)
+		EnableAddOn(addon)
+		local _, _, _, _, loadable = GetAddOnInfo(addon)
+		if not loadable and not enabled then
+			DisableAddOn(addon)
+		end
+
+		return loadable
+	end
+end
+
+-- @method      TryToLoadStandalone
+-- @brief       Attempt to find and load a standalone version of the requested library
+-- @param major A string representing the major version
+-- @return      If library is found and loaded, true is return. If not loadable, false is returned.
+--              If the library has been requested previously, nil is returned.
+local function TryToLoadStandalone(major)
+	if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
+	if AceLibrary.scannedlibs[major] then return end
+
+	AceLibrary.scannedlibs[major] = true
+
+	local name, _, _, enabled, loadable = GetAddOnInfo(major)
+	
+	loadable = (enabled and loadable) or TryToEnable(name)
+	
+	local loaded = false
+	if loadable then
+		loaded = true
+		LoadAddOn(name)
+	end
+	
+	local field = "X-AceLibrary-" .. major 
+	for i = 1, GetNumAddOns() do
+		if GetAddOnMetadata(i, field) then
+			name, _, _, enabled, loadable = GetAddOnInfo(i)
+			
+			loadable = (enabled and loadable) or TryToEnable(name)
+			if loadable then
+				loaded = true
+				LoadAddOn(name)
+			end
+		end
+	end
+	return loaded
+end
+
+-- @method      IsNewVersion
+-- @brief       Obtain whether the supplied version would be an upgrade to the
+--              current version. This allows for bypass code in library
+--              declaration.
+-- @param major A string representing the major version
+-- @param minor An integer or an svn revision string representing the minor version
+-- @return      whether the supplied version would be newer than what is
+--              currently available.
+function AceLibrary:IsNewVersion(major, minor)
+	argCheck(self, major, 2, "string")
+	TryToLoadStandalone(major)
+
+	if type(minor) == "string" then
+		local m = svnRevisionToNumber(minor)
+		if m then
+			minor = m
+		else
+			_G.error(("Bad argument #3 to  `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+		end
+	end
+	argCheck(self, minor, 3, "number")
+	local lib, oldMinor = LibStub:GetLibrary(major, true)
+	if lib then
+		return oldMinor < minor
+	end
+	local data = self.libs[major]
+	if not data then
+		return true
+	end
+	return data.minor < minor
+end
+
+-- @method      HasInstance
+-- @brief       Returns whether an instance exists. This allows for optional support of a library.
+-- @param major A string representing the major version.
+-- @param minor (optional) An integer or an svn revision string representing the minor version.
+-- @return      Whether an instance exists.
+function AceLibrary:HasInstance(major, minor)
+	argCheck(self, major, 2, "string")
+	if minor ~= false then
+		TryToLoadStandalone(major)
+	end
+	
+	local lib, ver = LibStub:GetLibrary(major, true)
+	if not lib and self.libs[major] then
+		lib, ver = self.libs[major].instance, self.libs[major].minor
+	end
+	if minor then
+		if type(minor) == "string" then
+			local m = svnRevisionToNumber(minor)
+			if m then
+				minor = m
+			else
+				_G.error(("Bad argument #3 to  `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+			end
+		end
+		argCheck(self, minor, 3, "number")
+		if not lib then
+			return false
+		end
+		return ver == minor
+	end
+	return not not lib
+end
+
+-- @method      GetInstance
+-- @brief       Returns the library with the given major/minor version.
+-- @param major A string representing the major version.
+-- @param minor (optional) An integer or an svn revision string representing the minor version.
+-- @return      The library with the given major/minor version.
+function AceLibrary:GetInstance(major, minor)
+	argCheck(self, major, 2, "string")
+	if minor ~= false then
+		TryToLoadStandalone(major)
+	end
+
+	local data, ver = LibStub:GetLibrary(major, true)
+	if not data then
+		if self.libs[major] then
+			data, ver = self.libs[major].instance, self.libs[major].minor
+		else
+			_G.error(("Cannot find a library instance of %s."):format(major), 2)
+			return
+		end
+	end
+	if minor then
+		if type(minor) == "string" then
+			local m = svnRevisionToNumber(minor)
+			if m then
+				minor = m
+			else
+				_G.error(("Bad argument #3 to  `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+			end
+		end
+		argCheck(self, minor, 2, "number")
+		if ver ~= minor then
+			_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
+		end
+	end
+	return data
+end
+
+-- Syntax sugar.  AceLibrary("FooBar-1.0")
+AceLibrary_mt.__call = AceLibrary.GetInstance
+
+local donothing = function() end
+
+local AceEvent
+
+local tmp = {}
+
+-- @method               Register
+-- @brief                Registers a new version of a given library.
+-- @param newInstance    the library to register
+-- @param major          the major version of the library
+-- @param minor          the minor version of the library
+-- @param activateFunc   (optional) A function to be called when the library is
+--                       fully activated. Takes the arguments
+--                       (newInstance [, oldInstance, oldDeactivateFunc]). If
+--                       oldInstance is given, you should probably call
+--                       oldDeactivateFunc(oldInstance).
+-- @param deactivateFunc (optional) A function to be called by a newer library's
+--                       activateFunc.
+-- @param externalFunc   (optional) A function to be called whenever a new
+--                       library is registered.
+function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
+	argCheck(self, newInstance, 2, "table")
+	argCheck(self, major, 3, "string")
+	if major ~= ACELIBRARY_MAJOR then
+		for k,v in pairs(_G) do
+			if v == newInstance then
+				geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
+			end
+		end
+	end
+	if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
+		_G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
+	end
+	if type(minor) == "string" then
+		local m = svnRevisionToNumber(minor)
+		if m then
+			minor = m
+		else
+			_G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
+		end
+	end
+	argCheck(self, minor, 4, "number")
+	if math.floor(minor) ~= minor or minor < 0 then
+		error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
+	end
+	argCheck(self, activateFunc, 5, "function", "nil")
+	argCheck(self, deactivateFunc, 6, "function", "nil")
+	argCheck(self, externalFunc, 7, "function", "nil")
+	if not deactivateFunc then
+		deactivateFunc = donothing
+	end
+	local data = self.libs[major]
+	if not data then
+		-- This is new
+		if LibStub:GetLibrary(major, true) then
+			error(self, "Cannot register library %q. It is already registered with LibStub.", major)
+		end
+		local instance = LibStub:NewLibrary(major, minor)
+		copyTable(newInstance, instance)
+		crawlReplace(instance, instance, newInstance)
+		destroyTable(newInstance)
+		if AceLibrary == newInstance then
+			self = instance
+			AceLibrary = instance
+		end
+		self.libs[major] = {
+			instance = instance,
+			minor = minor,
+			deactivateFunc = deactivateFunc,
+			externalFunc = externalFunc,
+		}
+		rawset(instance, 'GetLibraryVersion', function(self)
+			return major, minor
+		end)
+		if not rawget(instance, 'error') then
+			rawset(instance, 'error', error)
+		end
+		if not WoW22 and not rawget(instance, 'assert') then
+			rawset(instance, 'assert', assert)
+		end
+		if not rawget(instance, 'argCheck') then
+			rawset(instance, 'argCheck', argCheck)
+		end
+		if not rawget(instance, 'pcall') then
+			rawset(instance, 'pcall', pcall)
+		end
+		addToPositions(instance, major)
+		if activateFunc then
+			safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
+			
+--[[			if major ~= ACELIBRARY_MAJOR then
+				for k,v in pairs(_G) do
+					if v == instance then
+						geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
+					end
+				end
+			end]]
+		end
+		
+		if externalFunc then
+			for k, data_instance in LibStub:IterateLibraries() do -- all libraries
+				tmp[k] = data_instance
+			end
+			for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
+				tmp[k] = data.instance
+			end
+			for k, data_instance in pairs(tmp) do
+				if k ~= major then
+					safecall(externalFunc, instance, k, data_instance)
+				end
+				tmp[k] = nil
+			end
+		end
+		
+		for k,data in pairs(self.libs) do -- only Ace libraries
+			if k ~= major and data.externalFunc then
+				safecall(data.externalFunc, data.instance, major, instance)
+			end
+		end
+		if major == "AceEvent-2.0" then
+			AceEvent = instance
+		end
+		if AceEvent then
+			AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
+		end
+		
+		return instance
+	end
+	if minor <= data.minor then
+		-- This one is already obsolete, raise an error.
+		_G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
+		return
+	end
+	local instance = data.instance
+	-- This is an update
+	local oldInstance = {}
+	
+	local libStubInstance = LibStub:GetLibrary(major, true)
+	if not libStubInstance then -- non-LibStub AceLibrary registered the library
+		-- pass
+	elseif libStubInstance ~= instance then	
+		error(self, "Cannot register library %q. It is already registered with LibStub.", major)
+	else
+		LibStub:NewLibrary(major, minor) -- upgrade the minor version
+	end
+	
+	addToPositions(newInstance, major)
+	local isAceLibrary = (AceLibrary == newInstance)
+	local old_error, old_assert, old_argCheck, old_pcall
+	if isAceLibrary then
+		self = instance
+		AceLibrary = instance
+		
+		old_error = instance.error
+		if not WoW22 then
+			old_assert = instance.assert
+		end
+		old_argCheck = instance.argCheck
+		old_pcall = instance.pcall
+		
+		self.error = error
+		if not WoW22 then
+			self.assert = assert
+		end
+		self.argCheck = argCheck
+		self.pcall = pcall
+	end
+	deepTransfer(instance, newInstance, oldInstance, major)
+	crawlReplace(instance, instance, newInstance)
+	local oldDeactivateFunc = data.deactivateFunc
+	data.minor = minor
+	data.deactivateFunc = deactivateFunc
+	data.externalFunc = externalFunc
+	rawset(instance, 'GetLibraryVersion', function()
+		return major, minor
+	end)
+	if not rawget(instance, 'error') then
+		rawset(instance, 'error', error)
+	end
+	if not WoW22 and not rawget(instance, 'assert') then
+		rawset(instance, 'assert', assert)
+	end
+	if not rawget(instance, 'argCheck') then
+		rawset(instance, 'argCheck', argCheck)
+	end
+	if not rawget(instance, 'pcall') then
+		rawset(instance, 'pcall', pcall)
+	end
+	if isAceLibrary then
+		for _,v in pairs(self.libs) do
+			local i = type(v) == "table" and v.instance
+			if type(i) == "table" then
+				if not rawget(i, 'error') or i.error == old_error then
+					rawset(i, 'error', error)
+				end
+				if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then
+					rawset(i, 'assert', assert)
+				end
+				if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
+					rawset(i, 'argCheck', argCheck)
+				end
+				if not rawget(i, 'pcall') or i.pcall == old_pcall then
+					rawset(i, 'pcall', pcall)
+				end
+			end
+		end
+	end
+	if activateFunc then
+		safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)	
+				
+--[[		if major ~= ACELIBRARY_MAJOR then
+			for k,v in pairs(_G) do
+				if v == instance then
+					geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
+				end
+			end
+		end]]
+	else
+		safecall(oldDeactivateFunc, oldInstance)
+	end
+	oldInstance = nil
+	
+	if externalFunc then
+		for k, data_instance in LibStub:IterateLibraries() do -- all libraries
+			tmp[k] = data_instance
+		end
+		for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
+			tmp[k] = data.instance
+		end
+		for k, data_instance in pairs(tmp) do
+			if k ~= major then
+				safecall(externalFunc, instance, k, data_instance)
+			end
+			tmp[k] = nil
+		end
+	end
+	
+	return instance
+end
+
+function AceLibrary:IterateLibraries()
+	local t = {}
+	for major, instance in LibStub:IterateLibraries() do
+		t[major] = instance
+	end
+	for major, data in pairs(self.libs) do
+		t[major] = data.instance
+	end
+	return pairs(t)
+end
+
+local function manuallyFinalize(major, instance)
+	if AceLibrary.libs[major] then
+		-- don't work on Ace libraries
+		return
+	end
+	local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
+	if finalizedExternalLibs[major] then
+		return
+	end
+	finalizedExternalLibs[major] = true
+	
+	for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
+		if k ~= major and data.externalFunc then
+			safecall(data.externalFunc, data.instance, major, instance)
+		end
+	end
+end
+
+-- @function            Activate
+-- @brief               The activateFunc for AceLibrary itself. Called when
+--                      AceLibrary properly registers.
+-- @param self          Reference to AceLibrary
+-- @param oldLib        (optional) Reference to an old version of AceLibrary
+-- @param oldDeactivate (optional) Function to deactivate the old lib
+local function activate(self, oldLib, oldDeactivate)
+	AceLibrary = self
+	if not self.libs then
+		self.libs = oldLib and oldLib.libs or {}
+		self.scannedlibs = oldLib and oldLib.scannedlibs or {}
+	end
+	if not self.positions then
+		self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
+	end
+	self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
+	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
+	self.frame:UnregisterAllEvents()
+	self.frame:RegisterEvent("ADDON_LOADED")
+	self.frame:SetScript("OnEvent", function()
+		for major, instance in LibStub:IterateLibraries() do
+			manuallyFinalize(major, instance)
+		end
+	end)
+	for major, instance in LibStub:IterateLibraries() do
+		manuallyFinalize(major, instance)
+	end
+	
+	-- Expose the library in the global environment
+	_G[ACELIBRARY_MAJOR] = self
+	
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+if not previous then
+	previous = AceLibrary
+end
+if not previous.libs then
+	previous.libs = {}
+end
+AceLibrary.libs = previous.libs
+if not previous.positions then
+	previous.positions = setmetatable({}, { __mode = "k" })
+end
+AceLibrary.positions = previous.positions
+AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,10 @@
+## Interface: 20200
+
+## Title: Lib: AceLibrary
+## Notes: AddOn development framework
+## Author: Ace Development Team
+## X-Website: http://www.wowace.com
+## X-Category: Library
+## X-License: LGPL v2.1 + MIT for AceOO-2.0
+ 
+AceLibrary.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,980 @@
+--[[
+Name: AceOO-2.0
+Revision: $Rev: 38641 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Ace 1.x by Turan (turan@gryphon.com)
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/index.php/AceOO-2.0
+SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0
+Description: Library to provide an object-orientation framework.
+Dependencies: AceLibrary
+License: MIT
+]]
+
+local MAJOR_VERSION = "AceOO-2.0"
+local MINOR_VERSION = "$Revision: 38641 $"
+
+-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+local AceOO = {
+	error = AceLibrary.error,
+	argCheck = AceLibrary.argCheck
+}
+
+-- @function	getuid
+-- @brief		Obtain a unique string identifier for the object in question.
+-- @param t		The object to obtain the uid for.
+-- @return		The uid string.
+local function getuid(t)
+	local mt = getmetatable(t)
+	setmetatable(t, nil)
+	local str = tostring(t)
+	setmetatable(t, mt)
+	local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$")
+	if cap then
+		return ("0"):rep(8 - #cap) .. cap
+	end
+end
+
+local function getlibrary(o)
+	if type(o) == "table" then
+		return o
+	elseif type(o) == "string" then
+		if not AceLibrary:HasInstance(o) then
+			AceOO:error("Library %q does not exist.", o)
+		end
+		return AceLibrary(o)
+	end
+end
+
+local function deeprawget(self, k)
+	while true do
+		local v = rawget(self, k)
+		if v ~= nil then
+			return v
+		end
+		local mt = getmetatable(self)
+		if not mt or type(mt.__index) ~= "table" then
+			return nil
+		end
+		self = mt.__index
+	end
+end
+
+-- @function		Factory
+-- @brief			Construct a factory for the creation of objects.
+-- @param obj		The object whose init method will be called on the new factory
+--					object.
+-- @param newobj	The object whose init method will be called on the new
+--					objects that the Factory creates, to initialize them.
+-- @param (...) Arguments which will be passed to obj.init() in addition
+--					to the Factory object.
+-- @return			The new factory which creates a newobj when its new method is called,
+--					or when it is called directly (__call metamethod).
+local Factory
+do
+	local function getlibraries(...)
+		if select('#', ...) == 0 then
+			return
+		end
+		return getlibrary((select(1, ...))), getlibraries(select(2, ...))
+	end
+	local arg = {}
+	local function new(obj, ...)
+		local t = {}
+		local uid = getuid(t)
+		obj:init(t, getlibraries(...))
+		t.uid = uid
+		return t
+	end
+	
+	local function createnew(self, ...)
+		local o = self.prototype
+		local x = new(o, getlibraries(...))
+		return x
+	end
+
+	function Factory(obj, newobj, ...)
+		local t = new(obj, ...)
+		t.prototype = newobj
+		t.new = createnew
+		getmetatable(t).__call = t.new
+		return t
+	end
+end
+
+
+local function objtostring(self)
+	if self.ToString then
+		return self:ToString()
+	elseif self.GetLibraryVersion then
+		return (self:GetLibraryVersion())
+	elseif self.super then
+		local s = "Sub-" .. tostring(self.super)
+		local first = true
+		if self.interfaces then
+			for interface in pairs(self.interfaces) do
+				if first then
+					s = s .. "(" .. tostring(interface)
+					first = false
+				else
+					s = s .. ", " .. tostring(interface)
+				end
+			end
+		end
+		if self.mixins then
+			for mixin in pairs(self.mixins) do
+				if first then
+					s = s .. tostring(mixin)
+					first = false
+				else
+					s = s .. ", " .. tostring(mixin)
+				end
+			end
+		end
+		if first then
+			if self.uid then
+				return s .. ":" .. self.uid
+			else
+				return s
+			end
+		else
+			return s .. ")"
+		end
+	else
+		return self.uid and 'Subclass:' .. self.uid or 'Subclass'
+	end
+end
+
+-- @table			Object
+-- @brief			Base of all objects, including Class.
+--
+-- @method			init
+-- @brief			Initialize a new object.
+-- @param newobject The object to initialize
+-- @param class		The class to make newobject inherit from
+local Object
+do
+	Object = {}
+	function Object:init(newobject, class)
+		local parent = class or self
+		if not rawget(newobject, 'uid') then
+			newobject.uid = getuid(newobject)
+		end
+		local mt = {
+			__index = parent,
+			__tostring = objtostring,
+		}
+		setmetatable(newobject, mt)
+	end
+	Object.uid = getuid(Object)
+	setmetatable(Object, { __tostring = function() return 'Object' end })
+end
+
+local Interface
+
+local function validateInterface(object, interface)
+	if not object.class and object.prototype then
+		object = object.prototype
+	end
+	for k,v in pairs(interface.interface) do
+		if tostring(type(object[k])) ~= v then
+			return false
+		end
+	end
+	if interface.superinterfaces then
+		for superinterface in pairs(interface.superinterfaces) do
+			if not validateInterface(object, superinterface) then
+				return false
+			end
+		end
+	end
+	if type(object.class) == "table" and rawequal(object.class.prototype, object) then
+		if not object.class.interfaces then
+			rawset(object.class, 'interfaces', {})
+		end
+		object.class.interfaces[interface] = true
+	elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
+		validateInterface(object.class.prototype, interface)
+		-- check if class is proper, thus preventing future checks.
+	end
+	return true
+end
+
+-- @function		inherits
+-- @brief			Return whether an Object or Class inherits from a given
+--					parent.
+-- @param object	Object or Class to check
+-- @param parent	Parent to test inheritance from
+-- @return			whether an Object or Class inherits from a given
+--					parent.
+local function inherits(object, parent)
+	object = getlibrary(object)
+	if type(parent) == "string" then
+		if not AceLibrary:HasInstance(parent) then
+			return false
+		else
+			parent = AceLibrary(parent)
+		end
+	end
+	AceOO:argCheck(parent, 2, "table")
+	if type(object) ~= "table" then
+		return false
+	end
+	local current
+	local class = deeprawget(object, 'class')
+	if class then
+		current = class
+	else
+		current = object
+	end
+	if type(current) ~= "table" then
+		return false
+	end
+	if rawequal(current, parent) then
+		return true
+	end
+	if parent.class then
+		while true do
+			if rawequal(current, Object) then
+				break
+			end
+			if current.mixins then
+				for mixin in pairs(current.mixins) do
+					if rawequal(mixin, parent) then
+						return true
+					end
+				end
+			end
+			if current.interfaces then
+				for interface in pairs(current.interfaces) do
+					if rawequal(interface, parent) then
+						return true
+					end
+				end
+			end
+			current = deeprawget(current, 'super')
+			if type(current) ~= "table" then
+				break
+			end
+		end
+		
+		local isInterface = false
+		local curr = parent.class
+		while true do
+			if rawequal(curr, Object) then
+				break
+			elseif rawequal(curr, Interface) then
+				isInterface = true
+				break
+			end
+			curr = deeprawget(curr, 'super')
+			if type(curr) ~= "table" then
+				break
+			end
+		end
+		return isInterface and validateInterface(object, parent)
+	else
+		while true do
+			if rawequal(current, parent) then
+				return true
+			elseif rawequal(current, Object) then
+				return false
+			end
+			current = deeprawget(current, 'super')
+			if type(current) ~= "table" then
+				return false
+			end
+		end
+	end
+end
+
+-- @table			Class
+-- @brief			An object factory which sets up inheritence and supports
+--					'mixins'.
+--
+-- @metamethod		Class call
+-- @brief			Call ClassFactory:new() to create a new class.
+--
+-- @method			Class new
+-- @brief			Construct a new object.
+-- @param (...) Arguments to pass to the object init function.
+-- @return			The new object.
+--
+-- @method			Class init
+-- @brief			Initialize a new class.
+-- @param parent	Superclass.
+-- @param (...) Mixins.
+--
+-- @method			Class ToString
+-- @return			A string representing the object, in this case 'Class'.
+local initStatus
+local Class
+local Mixin
+local autoEmbed = false
+local function traverseInterfaces(bit, total)
+	if bit.superinterfaces then
+		for interface in pairs(bit.superinterfaces) do
+			if not total[interface] then
+				total[interface] = true
+				traverseInterfaces(interface, total)
+			end
+		end
+	end
+end
+local class_new
+do
+	Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
+	Class.super = Object
+	
+	local function protostring(t)
+		return '<' .. tostring(t.class) .. ' prototype>'
+	end
+	local function classobjectstring(t)
+		if t.ToString then
+			return t:ToString()
+		elseif t.GetLibraryVersion then
+			return (t:GetLibraryVersion())
+		else
+			return '<' .. tostring(t.class) .. ' instance>'
+		end
+	end
+	local function classobjectequal(self, other)
+		if type(self) == "table" and self.Equals then
+			return self:Equals(other)
+		elseif type(other) == "table" and other.Equals then
+			return other:Equals(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) == 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) == 0
+		else
+			return rawequal(self, other)
+		end
+	end
+	local function classobjectlessthan(self, other)
+		if type(self) == "table" and self.IsLessThan then
+			return self:IsLessThan(other)
+		elseif type(other) == "table" and other.IsLessThanOrEqualTo then
+			return not other:IsLessThanOrEqualTo(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) < 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) > 0
+		elseif type(other) == "table" and other.IsLessThan and other.Equals then
+			return other:Equals(self) or other:IsLessThan(self)
+		else
+			AceOO:error("cannot compare two objects")
+		end
+	end
+	local function classobjectlessthanequal(self, other)
+		if type(self) == "table" and self.IsLessThanOrEqualTo then
+			return self:IsLessThanOrEqualTo(other)
+		elseif type(other) == "table" and other.IsLessThan then
+			return not other:IsLessThan(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) <= 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) >= 0
+		elseif type(self) == "table" and self.IsLessThan and self.Equals then
+			return self:Equals(other) or self:IsLessThan(other)
+		else
+			AceOO:error("cannot compare two incompatible objects")
+		end
+	end
+	local function classobjectadd(self, other)
+		if type(self) == "table" and self.Add then
+			return self:Add(other)
+		else
+			AceOO:error("cannot add two incompatible objects")
+		end
+	end
+	local function classobjectsub(self, other)
+		if type(self) == "table" and self.Subtract then
+			return self:Subtract(other)
+		else
+			AceOO:error("cannot subtract two incompatible objects")
+		end
+	end
+	local function classobjectunm(self, other)
+		if type(self) == "table" and self.UnaryNegation then
+			return self:UnaryNegation(other)
+		else
+			AceOO:error("attempt to negate an incompatible object")
+		end
+	end
+	local function classobjectmul(self, other)
+		if type(self) == "table" and self.Multiply then
+			return self:Multiply(other)
+		else
+			AceOO:error("cannot multiply two incompatible objects")
+		end
+	end
+	local function classobjectdiv(self, other)
+		if type(self) == "table" and self.Divide then
+			return self:Divide(other)
+		else
+			AceOO:error("cannot divide two incompatible objects")
+		end
+	end
+	local function classobjectpow(self, other)
+		if type(self) == "table" and self.Exponent then
+			return self:Exponent(other)
+		else
+			AceOO:error("cannot exponentiate two incompatible objects")
+		end
+	end
+	local function classobjectconcat(self, other)
+		if type(self) == "table" and self.Concatenate then
+			return self:Concatenate(other)
+		else
+			AceOO:error("cannot concatenate two incompatible objects")
+		end
+	end
+	function class_new(self, ...)
+		if self.virtual then
+			AceOO:error("Cannot instantiate a virtual class.")
+		end
+		
+		local o = self.prototype
+		local newobj = {}
+		if o.class and o.class.instancemeta then
+			setmetatable(newobj, o.class.instancemeta)
+		else
+			Object:init(newobj, o)
+		end
+		
+		if self.interfaces and not self.interfacesVerified then
+			-- Verify the interfaces
+			
+			for interface in pairs(self.interfaces) do
+				for field,kind in pairs(interface.interface) do
+					if tostring(type(newobj[field])) ~= kind then
+						AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field])))
+					end
+				end
+			end
+			self.interfacesVerified = true
+		end
+		local tmp = initStatus
+		initStatus = newobj
+		newobj:init(...)
+		if initStatus then
+			initStatus = tmp
+			AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
+			return
+		end
+		initStatus = tmp
+		return newobj
+	end
+	local classmeta = {
+		__tostring = objtostring,
+		__call = function(self, ...)
+			return self:new(...)
+		end,
+	}
+	function Class:init(newclass, parent, ...)
+		parent = parent or self
+		
+		local total
+		
+		if parent.class then
+			total = { parent, ... }
+			parent = self
+		else
+			total = { ... }
+		end
+		if not inherits(parent, Class) then
+			AceOO:error("Classes must inherit from a proper class")
+		end
+		if parent.sealed then
+			AceOO:error("Cannot inherit from a sealed class")
+		end
+		for i,v in ipairs(total) do
+			if inherits(v, Mixin) and v.class then
+				if v.__deprecated then
+					AceOO:error(v.__deprecated)
+				end
+				if not newclass.mixins then
+					newclass.mixins = {}
+				end
+				if newclass.mixins[v] then
+					AceOO:error("Cannot explicitly inherit from the same mixin twice")
+				end
+				newclass.mixins[v] = true
+			elseif inherits(v, Interface) and v.class then
+				if not newclass.interfaces then
+					newclass.interfaces = {}
+				end
+				if newclass.interfaces[v] then
+					AceOO:error("Cannot explicitly inherit from the same interface twice")
+				end
+				newclass.interfaces[v] = true
+			else
+				AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
+			end
+		end
+		if parent.interfaces then
+			if not newclass.interfaces then
+				newclass.interfaces = {}
+			end
+			for interface in pairs(parent.interfaces) do
+				newclass.interfaces[interface] = true
+			end
+		end
+		for k in pairs(total) do
+			total[k] = nil
+		end
+		
+		newclass.super = parent
+		
+		newclass.prototype = setmetatable(total, {
+			__index = parent.prototype,
+			__tostring = protostring,
+		})
+		total = nil
+		
+		newclass.instancemeta = {
+			__index = newclass.prototype,
+			__tostring = classobjectstring,
+			__eq = classobjectequal,
+			__lt = classobjectlessthan,
+			__le = classobjectlessthanequal,
+			__add = classobjectadd,
+			__sub = classobjectsub,
+			__unm = classobjectunm,
+			__mul = classobjectmul,
+			__div = classobjectdiv,
+			__pow = classobjectpow,
+			__concat = classobjectconcat,
+		}
+		
+		setmetatable(newclass, classmeta)
+		
+		newclass.new = class_new
+		
+		if newclass.mixins then
+			-- Fold in the mixins
+			local err, msg
+			for mixin in pairs(newclass.mixins) do
+				local ret
+				autoEmbed = true
+				ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
+				autoEmbed = false
+				if not ret then
+					err = true
+					break
+				end
+			end
+	
+			if err then
+				local pt = newclass.prototype
+				for k,v in pairs(pt) do
+					pt[k] = nil
+				end
+	
+				-- method conflict
+				AceOO:error(msg)
+			end
+		end
+		
+		newclass.prototype.class = newclass
+		
+		if newclass.interfaces then
+			for interface in pairs(newclass.interfaces) do
+				traverseInterfaces(interface, newclass.interfaces)
+			end
+		end
+		if newclass.mixins then
+			for mixin in pairs(newclass.mixins) do
+				if mixin.interfaces then
+					if not newclass.interfaces then
+						newclass.interfaces = {}
+					end
+					for interface in pairs(mixin.interfaces) do
+						newclass.interfaces[interface] = true
+					end
+				end
+			end
+		end
+	end
+	function Class:ToString()
+		if type(self.GetLibraryVersion) == "function" then
+			return (self:GetLibraryVersion())
+		else
+			return "Class"
+		end
+	end
+	
+	local tmp
+	function Class.prototype:init()
+		if rawequal(self, initStatus) then
+			initStatus = nil
+		else
+			AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
+		end
+		self.uid = getuid(self)
+		local current = self.class
+		while true do
+			if current == Class then
+				break
+			end
+			if current.mixins then
+				for mixin in pairs(current.mixins) do
+					if type(mixin.OnInstanceInit) == "function" then
+						mixin:OnInstanceInit(self)
+					end
+				end
+			end
+			current = current.super
+		end
+	end
+end
+
+
+-- @object	ClassFactory
+-- @brief	A factory for creating classes.	Rarely used directly.
+local ClassFactory = Factory(Object, Class, Object)
+
+function Class:new(...)
+	local x = ClassFactory:new(...)
+	if AceOO.classes then
+		AceOO.classes[x] = true
+	end
+	return x
+end
+getmetatable(Class).__call = Class.new
+
+-- @class	Mixin
+-- @brief	A class to create mixin objects, which contain methods that get
+-- "mixed in" to class prototypes.
+--
+-- @object	Mixin prototype
+-- @brief	The prototype that mixin objects inherit their methods from.
+--
+-- @method	Mixin prototype embed
+-- @brief	Mix in the methods of our object which are listed in our interface
+--		 to the supplied target table.
+--
+-- @method	Mixin prototype init
+-- @brief	Initialize the mixin object.
+-- @param	newobj	 The new object we're initializing.
+-- @param	interface	The interface we implement (the list of methods our
+--					prototype provides which should be mixed into the target
+--					table by embed).
+do
+	Mixin = Class()
+	function Mixin:ToString()
+		if self.GetLibraryVersion then
+			return (self:GetLibraryVersion())
+		else
+			return 'Mixin'
+		end
+	end
+	local function _Embed(state, field, target)
+		field = next(state.export, field)
+		if field == nil then
+			return
+		end
+
+		if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
+			AceOO:error("Method conflict in attempt to mixin. Field %q", field)
+		end
+
+		target[field] = state[field]
+
+		local ret,msg = pcall(_Embed, state, field, target)
+		if not ret then
+			-- Mix in the next method according to the defined interface.	If that
+			-- fails due to a conflict, re-raise to back out the previous mixed
+			-- methods.
+
+			target[field] = nil
+			AceOO:error(msg)
+		end
+	end
+	function Mixin.prototype:embed(target)
+		if self.__deprecated then
+			AceOO:error(self.__deprecated)
+		end
+		local mt = getmetatable(target)
+		setmetatable(target, nil)
+		local err, msg = pcall(_Embed, self, nil, target)
+		if not err then
+			setmetatable(target, mt)
+			AceOO:error(msg)
+			return
+		end
+		if type(self.embedList) == "table" then
+			self.embedList[target] = true
+		end
+		if type(target.class) ~= "table" then
+			target[self] = true
+		end
+		if not autoEmbed and type(self.OnManualEmbed) == "function" then
+			self:OnManualEmbed(target)
+		end
+		setmetatable(target, mt)
+	end
+	
+	function Mixin.prototype:activate(oldLib, oldDeactivate)
+		if oldLib and oldLib.embedList then
+			for target in pairs(oldLib.embedList) do
+				local mt = getmetatable(target)
+				setmetatable(target, nil)
+				for field in pairs(oldLib.export) do
+					target[field] = nil
+				end
+				setmetatable(target, mt)
+			end
+			self.embedList = oldLib.embedList
+			for target in pairs(self.embedList) do
+				self:embed(target)
+			end
+		else
+			self.embedList = setmetatable({}, {__mode="k"})
+		end
+	end
+	
+	function Mixin.prototype:init(export, ...)
+		AceOO:argCheck(export, 2, "table")
+		for k,v in pairs(export) do
+			if type(k) ~= "number" then
+				AceOO:error("All keys to argument #2 must be numbers.")
+			elseif type(v) ~= "string" then
+				AceOO:error("All values to argument #2 must be strings.")
+			end
+		end
+		local num = #export
+		for i = 1, num do
+			local v = export[i]
+			export[i] = nil
+			export[v] = true
+		end
+		
+		local interfaces
+		if select('#', ...) >= 1 then
+			interfaces = { ... }
+			for i,v in ipairs(interfaces) do
+				v = getlibrary(v)
+				interfaces[i] = v
+				if not v.class or not inherits(v, Interface) then
+					AceOO:error("Mixins can inherit only from interfaces")
+				end
+			end
+			local num = #interfaces
+			for i = 1, num do
+				local v = interfaces[i]
+				interfaces[i] = nil
+				interfaces[v] = true
+			end
+			for interface in pairs(interfaces) do
+				traverseInterfaces(interface, interfaces)
+			end
+			for interface in pairs(interfaces) do
+				for field,kind in pairs(interface.interface) do
+					if kind ~= "nil" then
+						local good = false
+						for bit in pairs(export) do
+							if bit == field then
+								good = true
+								break
+							end
+						end
+						if not good then
+							AceOO:error("Mixin does not fully accommodate field %q", field)
+						end
+					end
+				end
+			end
+		end
+		self.super = Mixin.prototype
+		Mixin.super.prototype.init(self)
+		self.export = export
+		self.interfaces = interfaces
+	end
+end
+
+-- @class Interface
+-- @brief A class to create interfaces, which contain contracts that classes
+--			which inherit from this must comply with.
+--
+-- @object Interface prototype
+-- @brief	The prototype that interface objects must adhere to.
+--
+-- @method Interface prototype init
+-- @brief	Initialize the mixin object.
+-- @param	interface	The interface we contract (the hash of fields forced).
+-- @param	(...)	Superinterfaces
+do
+	Interface = Class()
+	function Interface:ToString()
+		if self.GetLibraryVersion then
+			return (self:GetLibraryVersion())
+		else
+			return 'Instance'
+		end
+	end
+	function Interface.prototype:init(interface, ...)
+		Interface.super.prototype.init(self)
+		AceOO:argCheck(interface, 2, "table")
+		for k,v in pairs(interface) do
+			if type(k) ~= "string" then
+				AceOO:error("All keys to argument #2 must be numbers.")
+			elseif type(v) ~= "string" then
+				AceOO:error("All values to argument #2 must be strings.")
+			elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
+				AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
+			end
+		end
+		if select('#', ...) >= 1 then
+			self.superinterfaces = { ... }
+			for i,v in ipairs(self.superinterfaces) do
+				v = getlibrary(v)
+				self.superinterfaces[i] = v
+				if not inherits(v, Interface) or not v.class then
+					AceOO:error('Cannot provide a non-Interface to inherit from')
+				end
+			end
+			local num = #self.superinterfaces
+			for i = 1, num do
+				local v = self.superinterfaces[i]
+				self.superinterfaces[i] = nil
+				self.superinterfaces[v] = true
+			end
+		end
+		self.interface = interface
+	end
+end
+
+-- @function Classpool
+-- @brief	Obtain a read only class from our pool of classes, indexed by the
+--		 superclass and mixins.
+-- @param	sc		 The superclass of the class we want.
+-- @param	(m1..m20)	Mixins of the class we want's objects.
+-- @return A read only class from the class pool.
+local Classpool
+do
+	local pool = setmetatable({}, {__mode = 'v'})
+	local function newindex(k, v)
+		AceOO:error('Attempt to modify a read-only class.')
+	end
+	local function protonewindex(k, v)
+		AceOO:error('Attempt to modify a read-only class prototype.')
+	end
+	local function ts(bit)
+		if type(bit) ~= "table" then
+			return tostring(bit)
+		elseif getmetatable(bit) and bit.__tostring then
+			return tostring(bit)
+		elseif type(bit.GetLibraryVersion) == "function" then
+			return bit:GetLibraryVersion()
+		else
+			return tostring(bit)
+		end
+	end
+	local t = {}
+	local function getcomplexuid(sc, ...)
+		if sc then
+			if sc.uid then
+				table.insert(t, sc.uid)
+			else
+				AceOO:error("%s is not an appropriate class/mixin", ts(sc))
+			end
+		end
+		for i = 1, select('#', ...) do
+			local m = select(i, ...)
+			if m.uid then
+				table.insert(t, m.uid)
+			else
+				AceOO:error("%s is not an appropriate mixin", ts(m))
+			end
+		end
+		table.sort(t)
+		local uid = table.concat(t, '')
+		local num = #t
+		for i = 1, num do
+			t[i] = nil
+		end
+		return uid
+	end
+	local classmeta
+	local arg = {}
+	function Classpool(superclass, ...)
+		local l = getlibrary
+		superclass = getlibrary(superclass)
+		arg = { ... }
+		for i, v in ipairs(arg) do
+			arg[i] = getlibrary(v)
+		end
+		if superclass then
+			if superclass.class then -- mixin
+				table.insert(arg, 1, superclass)
+				superclass = Class
+			end
+		else
+			superclass = Class
+		end
+		local key = getcomplexuid(superclass, unpack(arg))
+		if not pool[key] then
+			local class = Class(superclass, unpack(arg))
+			if not classmeta then
+				classmeta = {}
+				local mt = getmetatable(class)
+				for k,v in pairs(mt) do
+					classmeta[k] = v
+				end
+				classmeta.__newindex = newindex
+			end
+			-- Prevent the user from adding methods to this class.
+			-- NOTE: I'm not preventing modifications of existing class members,
+			-- but it's likely that only a truly malicious user will be doing so.
+			class.sealed = true
+			setmetatable(class, classmeta)
+			getmetatable(class.prototype).__newindex = protonewindex
+			pool[key] = class
+		end
+		return pool[key]
+	end
+end
+
+AceOO.Factory = Factory
+AceOO.Object = Object
+AceOO.Class = Class
+AceOO.Mixin = Mixin
+AceOO.Interface = Interface
+AceOO.Classpool = Classpool
+AceOO.inherits = inherits
+
+-- Library handling bits
+
+local function activate(self, oldLib, oldDeactivate)
+	AceOO = self
+	Factory = self.Factory
+	Object = self.Object
+	Class = self.Class
+	ClassFactory.prototype = Class
+	Mixin = self.Mixin
+	Interface = self.Interface
+	Classpool = self.Classpool
+	
+	if oldLib then
+		self.classes = oldLib.classes
+	end
+	if not self.classes then
+		self.classes = setmetatable({}, {__mode="k"})
+	else
+		for class in pairs(self.classes) do
+			class.new = class_new
+		end
+	end
+	
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
+AceOO = AceLibrary(MAJOR_VERSION)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,12 @@
+## Interface: 20200
+
+## Title: Lib: AceOO-2.0
+## Notes: AddOn development framework
+## Author: Ace Development Team
+## LoadOnDemand: 1
+## X-Website: http://www.wowace.com
+## X-Category: Library
+## X-License: LGPL v2.1 + MIT for AceOO-2.0
+## Dependencies: AceLibrary
+ 
+AceOO-2.0.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_ConfigUI/lib/Dewdrop-2.0/Dewdrop-2.0.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,3487 @@
+--[[
+Name: Dewdrop-2.0
+Revision: $Rev: 48630 $
+Author(s): ckknight (ckknight@gmail.com)
+Website: http://ckknight.wowinterface.com/
+Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0
+SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0
+Description: A library to provide a clean dropdown menu interface.
+Dependencies: AceLibrary
+License: LGPL v2.1
+]]
+
+local MAJOR_VERSION = "Dewdrop-2.0"
+local MINOR_VERSION = "$Revision: 48630 $"
+
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+local Dewdrop = {}
+
+local SharedMedia
+
+local CLOSE = "Close"
+local CLOSE_DESC = "Close the menu."
+local VALIDATION_ERROR = "Validation error."
+local USAGE_TOOLTIP = "Usage: %s."
+local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one."
+local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding."
+local KEY_BUTTON1 = "Left Mouse"
+local KEY_BUTTON2 = "Right Mouse"
+local DISABLED = "Disabled"
+local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?"
+
+if GetLocale() == "deDE" then
+	CLOSE = "Schlie\195\159en"
+	CLOSE_DESC = "Men\195\188 schlie\195\159en."
+	VALIDATION_ERROR = "Validierungsfehler."
+	USAGE_TOOLTIP = "Benutzung: %s."
+	RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen."
+	RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen."
+	KEY_BUTTON1 = "Linke Maustaste"
+	KEY_BUTTON2 = "Rechte Maustaste"
+	DISABLED = "Deaktiviert"
+	DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?"
+elseif GetLocale() == "koKR" then
+	CLOSE = "닫기"
+	CLOSE_DESC = "메뉴를 닫습니다."
+	VALIDATION_ERROR = "오류 확인."
+	USAGE_TOOLTIP = "사용법: %s."
+	RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다."
+	RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요."
+	KEY_BUTTON1 = "왼쪽 마우스"
+	KEY_BUTTON2 = "오른쪽 마우스"
+	DISABLED = "비활성화됨"
+	DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?"
+elseif GetLocale() == "frFR" then
+	CLOSE = "Fermer"
+	CLOSE_DESC = "Ferme le menu."
+	VALIDATION_ERROR = "Erreur de validation."
+	USAGE_TOOLTIP = "Utilisation : %s."
+	RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement."
+	RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci."
+	KEY_BUTTON1 = "Clic gauche"
+	KEY_BUTTON2 = "Clic droit"
+	DISABLED = "D\195\169sactiv\195\169"
+	DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?"
+elseif GetLocale() == "esES" then
+	CLOSE = "Cerrar"
+	CLOSE_DESC = "Cierra el menú."
+	VALIDATION_ERROR = "Error de validación."
+	USAGE_TOOLTIP = "Uso: %s."
+	RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador."
+	RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla."
+	KEY_BUTTON1 = "Clic Izquierdo"
+	KEY_BUTTON2 = "Clic Derecho"
+	DISABLED = "Desactivado"
+	DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?"
+elseif GetLocale() == "zhTW" then
+	CLOSE = "關閉"
+	CLOSE_DESC = "關閉選單。"
+	VALIDATION_ERROR = "驗證錯誤。"
+	USAGE_TOOLTIP = "用法: %s。"
+	RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。"
+	RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。"
+	KEY_BUTTON1 = "滑鼠左鍵"
+	KEY_BUTTON2 = "滑鼠右鍵"
+	DISABLED = "停用"
+	DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?"
+elseif GetLocale() == "zhCN" then
+	CLOSE = "关闭"
+	CLOSE_DESC = "关闭菜单"
+	VALIDATION_ERROR = "验证错误."
+	USAGE_TOOLTIP = "用法: %s."
+	RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页."
+	RESET_KEYBINDING_DESC = "按ESC键清除按键绑定"
+	KEY_BUTTON1 = "鼠标左键"
+	KEY_BUTTON2 = "鼠标右键"
+	DISABLED = "禁用"
+	DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?"
+end
+
+Dewdrop.KEY_BUTTON1 = KEY_BUTTON1
+Dewdrop.KEY_BUTTON2 = KEY_BUTTON2
+
+local function new(...)
+	local t = {}
+	for i = 1, select('#', ...), 2 do
+		local k = select(i, ...)
+		if k then
+			t[k] = select(i+1, ...)
+		else
+			break
+		end
+	end
+	return t
+end
+
+local tmp
+do
+	local t = {}
+	function tmp(...)
+		for k in pairs(t) do
+			t[k] = nil
+		end
+		for i = 1, select('#', ...), 2 do
+			local k = select(i, ...)
+			if k then
+				t[k] = select(i+1, ...)
+			else
+				break
+			end
+		end
+		return t
+	end
+end
+local tmp2
+do
+	local t = {}
+	function tmp2(...)
+		for k in pairs(t) do
+			t[k] = nil
+		end
+		for i = 1, select('#', ...), 2 do
+			local k = select(i, ...)
+			if k then
+				t[k] = select(i+1, ...)
+			else
+				break
+			end
+		end
+		return t
+	end
+end
+local levels
+local buttons
+
+
+-- Secure frame handling:
+-- Rather than using secure buttons in the menu (has problems), we have one
+-- master secureframe that we pop onto menu items on mouseover. This requires
+-- some dark magic with OnLeave etc, but it's not too bad.
+
+local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate")
+secureFrame:Hide()
+
+local function secureFrame_Show(self)
+  local owner = self.owner
+
+  if self.secure then	-- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..)
+	  for k,v in pairs(self.secure) do
+	    self:SetAttribute(k, nil)
+	  end
+  end
+  self.secure = owner.secure;	-- Grab hold of new secure data
+
+  local scale = owner:GetEffectiveScale()
+
+  self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale)
+  self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale)
+  self:EnableMouse(true)
+  for k,v in pairs(self.secure) do
+    self:SetAttribute(k, v)
+  end
+
+	secureFrame:SetFrameStrata(owner:GetFrameStrata())
+	secureFrame:SetFrameLevel(owner:GetFrameLevel()+1)
+
+  self:Show()
+end
+
+local function secureFrame_Hide(self)
+  self:Hide()
+  if self.secure then
+	  for k,v in pairs(self.secure) do
+	    self:SetAttribute(k, nil)
+	  end
+	end
+  self.secure = nil
+end
+
+secureFrame:SetScript("OnEvent",
+	function()
+		if event=="PLAYER_REGEN_ENABLED" then
+			this.combat = false
+			if not this:IsShown() and this.owner then
+				secureFrame_Show(this)
+			end
+		elseif event=="PLAYER_REGEN_DISABLED" then
+			this.combat = true
+			if this:IsShown() then
+				secureFrame_Hide(this)
+			end
+		end
+	end
+)
+secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
+secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
+
+secureFrame:SetScript("OnLeave",
+	function()
+		local owner=this.owner
+		this:Deactivate()
+		owner:GetScript("OnLeave")()
+	end
+)
+
+secureFrame:HookScript("OnClick",
+	function()
+		local realthis = this
+		this = this.owner
+		this:GetScript("OnClick")()
+	end
+)
+
+function secureFrame:IsOwnedBy(frame)
+	return self.owner == frame
+end
+
+function secureFrame:Activate(owner)
+	if self.owner then		-- "Shouldn't" happen but apparently it does and I cba to troubleshoot...
+		if not self.combat then
+			secureFrame_Hide(self)
+		end
+	end
+	self.owner = owner
+	if not self.combat then
+		secureFrame_Show(self)
+	end
+end
+
+function secureFrame:Deactivate()
+	if not self.combat then
+		secureFrame_Hide(self)
+	end
+	self.owner = nil
+end
+
+-- END secure frame utilities
+
+
+-- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies
+local underlineFrame = CreateFrame("Frame", nil)
+underlineFrame.tx = underlineFrame:CreateTexture()
+underlineFrame.tx:SetTexture(1,1,0.5,0.75)
+underlineFrame:SetScript("OnHide", function(this) this:Hide(); end)
+underlineFrame:SetScript("OnShow", function(this) 	-- change sizing on the fly to catch runtime uiscale changes
+    underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale())
+    underlineFrame.tx:SetPoint("RIGHT", 1,0)
+    underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale());
+end)
+underlineFrame:SetHeight(1)
+
+-- END underline on mouseover
+
+
+local function GetScaledCursorPosition()
+	local x, y = GetCursorPosition()
+	local scale = UIParent:GetEffectiveScale()
+	return x / scale, y / scale
+end
+
+local function StartCounting(self, level)
+	for i = level, 1, -1 do
+		if levels[i] then
+			levels[i].count = 3
+		end
+	end
+end
+
+local function StopCounting(self, level)
+	for i = level, 1, -1 do
+		if levels[i] then
+			levels[i].count = nil
+		end
+	end
+end
+
+local function OnUpdate(self, elapsed)
+	for _,level in ipairs(levels) do
+		local count = level.count
+		if count then
+			count = count - elapsed
+			if count < 0 then
+				level.count = nil
+				self:Close(level.num)
+			else
+				level.count = count
+			end
+		end
+	end
+end
+
+local function CheckDualMonitor(self, frame)
+	local ratio = GetScreenWidth() / GetScreenHeight()
+	if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then
+		local offsetx
+		if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then
+			offsetx = GetScreenWidth() / 2 - frame:GetRight()
+		else
+			offsetx = GetScreenWidth() / 2 - frame:GetLeft()
+		end
+		local point, parent, relativePoint, x, y = frame:GetPoint(1)
+		frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0)
+	end
+end
+
+local function CheckSize(self, level)
+	if not level.buttons then
+		return
+	end
+	local height = 20
+	for _, button in ipairs(level.buttons) do
+		height = height + button:GetHeight()
+	end
+	level:SetHeight(height)
+	local width = 160
+	for _, button in ipairs(level.buttons) do
+		local extra = 1
+		if button.hasArrow or button.hasColorSwatch then
+			extra = extra + 16
+		end
+		if not button.notCheckable then
+			extra = extra + 24
+		end
+		button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight)
+		if button.text:GetWidth() + extra > width then
+			width = button.text:GetWidth() + extra
+		end
+	end
+	level:SetWidth(width + 20)
+	if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then
+		level:ClearAllPoints()
+		local parent = level.parent or level:GetParent()
+		if type(parent) ~= "table" then
+			parent = UIParent
+		end
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	local dirty = false
+	if not level:GetRight() then
+		self:Close()
+		return
+	end
+	if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then
+		level.lastDirection = "LEFT"
+		dirty = true
+	elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then
+		level.lastDirection = "RIGHT"
+		dirty = true
+	end
+	if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then
+		level.lastVDirection = "DOWN"
+		dirty = true
+	elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then
+		level.lastVDirection = "UP"
+		dirty = true
+	end
+	if dirty then
+		level:ClearAllPoints()
+		local parent = level.parent or level:GetParent()
+		if type(parent) ~= "table" then
+			parent = UIParent
+		end
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	if level:GetTop() > GetScreenHeight() then
+		local top = level:GetTop()
+		local point, parent, relativePoint, x, y = level:GetPoint(1)
+		level:ClearAllPoints()
+		level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top)
+	elseif level:GetBottom() < 0 then
+		local bottom = level:GetBottom()
+		local point, parent, relativePoint, x, y = level:GetPoint(1)
+		level:ClearAllPoints()
+		level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom)
+	end
+	CheckDualMonitor(self, level)
+	if mod(level.num, 5) == 0 then
+		local left, bottom = level:GetLeft(), level:GetBottom()
+		level:ClearAllPoints()
+		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	end
+end
+
+local Open
+local OpenSlider
+local OpenEditBox
+local Refresh
+local Clear
+local function ReleaseButton(self, level, index)
+	if not level.buttons then
+		return
+	end
+	if not level.buttons[index] then
+		return
+	end
+	local button = level.buttons[index]
+	button:Hide()
+	if button.highlight then
+		button.highlight:Hide()
+	end
+--	button.arrow:SetVertexColor(1, 1, 1)
+--	button.arrow:SetHeight(16)
+--	button.arrow:SetWidth(16)
+	table.remove(level.buttons, index)
+	table.insert(buttons, button)
+	for k in pairs(button) do
+		if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then
+			button[k] = nil
+		end
+	end
+	return true
+end
+
+local function Scroll(self, level, down)
+	if down then
+		if level:GetBottom() < 0 then
+			local point, parent, relativePoint, x, y = level:GetPoint(1)
+			level:SetPoint(point, parent, relativePoint, x, y + 50)
+			if level:GetBottom() > 0 then
+				level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom())
+			end
+		end
+	else
+		if level:GetTop() > GetScreenHeight() then
+			local point, parent, relativePoint, x, y = level:GetPoint(1)
+			level:SetPoint(point, parent, relativePoint, x, y - 50)
+			if level:GetTop() < GetScreenHeight() then
+				level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop())
+			end
+		end
+	end
+end
+
+local function getArgs(t, str, num, ...)
+	local x = t[str .. num]
+	if x == nil then
+		return ...
+	else
+		return x, getArgs(t, str, num + 1, ...)
+	end
+end
+
+local sliderFrame
+local editBoxFrame
+
+local normalFont
+local lastSetFont
+local justSetFont = false
+local regionTmp = {}
+local function fillRegionTmp(...)
+	for i = 1, select('#', ...) do
+		regionTmp[i] = select(i, ...)
+	end
+end
+
+local function showGameTooltip(this)
+	if this.tooltipTitle or this.tooltipText then
+		GameTooltip_SetDefaultAnchor(GameTooltip, this)
+		local disabled = not this.isTitle and this.disabled
+		local font
+		if this.tooltipTitle then
+			if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then
+				font = SharedMedia:Fetch("font", this.tooltipTitle)
+			end
+			if disabled then
+				GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1)
+			else
+				GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1)
+			end
+			if this.tooltipText then
+				if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then
+					font = SharedMedia:Fetch("font", this.tooltipText)
+				end
+				if disabled then
+					GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1)
+				else
+					GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
+				end
+			end
+		else
+			if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then
+				font = SharedMedia:Fetch("font", this.tooltipText)
+			end
+			if disabled then
+				GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1)
+			else
+				GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1)
+			end
+		end
+		if font then
+			fillRegionTmp(GameTooltip:GetRegions())
+			lastSetFont = font
+			justSetFont = true
+			for i,v in ipairs(regionTmp) do
+				if v.SetFont then
+					local norm,size,outline = v:GetFont()
+					v:SetFont(font, size, outline)
+					if not normalFont then
+						normalFont = norm
+					end
+				end
+				regionTmp[i] = nil
+			end
+		elseif not normalFont then
+			fillRegionTmp(GameTooltip:GetRegions())
+			for i,v in ipairs(regionTmp) do
+				if v.GetFont and not normalFont then
+					normalFont = v:GetFont()
+				end
+				regionTmp[i] = nil
+			end
+		end
+		GameTooltip:Show()
+	end
+	if this.tooltipFunc then
+		GameTooltip:SetOwner(this, "ANCHOR_NONE")
+		GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0)
+		this.tooltipFunc(getArgs(this, 'tooltipArg', 1))
+		GameTooltip:Show()
+	end
+end
+
+local tmpt = setmetatable({}, {mode='v'})
+local numButtons = 0
+local function AcquireButton(self, level)
+	if not levels[level] then
+		return
+	end
+	level = levels[level]
+	if not level.buttons then
+		level.buttons = {}
+	end
+	local button
+	if #buttons == 0 then
+		numButtons = numButtons + 1
+		button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil)
+		button:SetFrameStrata("FULLSCREEN_DIALOG")
+		button:SetHeight(16)
+		local highlight = button:CreateTexture(nil, "BACKGROUND")
+		highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
+		button.highlight = highlight
+		highlight:SetBlendMode("ADD")
+		highlight:SetAllPoints(button)
+		highlight:Hide()
+		local check = button:CreateTexture(nil, "ARTWORK")
+		button.check = check
+		check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+		check:SetPoint("CENTER", button, "LEFT", 12, 0)
+		check:SetWidth(24)
+		check:SetHeight(24)
+		local radioHighlight = button:CreateTexture(nil, "ARTWORK")
+		button.radioHighlight = radioHighlight
+		radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
+		radioHighlight:SetAllPoints(check)
+		radioHighlight:SetBlendMode("ADD")
+		radioHighlight:SetTexCoord(0.5, 0.75, 0, 1)
+		radioHighlight:Hide()
+		button:SetScript("OnEnter", function()
+			if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then
+				for i = 1, this.level.num do
+					Refresh(self, levels[i])
+				end
+				return
+			end
+			self:Close(this.level.num + 1)
+			if not this.disabled then
+				if this.secure then
+					secureFrame:Activate(this)
+				elseif this.hasSlider then
+					OpenSlider(self, this)
+				elseif this.hasEditBox then
+					OpenEditBox(self, this)
+				elseif this.hasArrow then
+					Open(self, this, nil, this.level.num + 1, this.value)
+				end
+			end
+			if not this.level then -- button reclaimed
+				return
+			end
+			StopCounting(self, this.level.num + 1)
+			if not this.disabled then
+				highlight:Show()
+				if this.isRadio then
+					button.radioHighlight:Show()
+				end
+				if this.mouseoverUnderline then
+					underlineFrame:SetParent(this)
+					underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0)
+					underlineFrame:SetWidth(this.text:GetWidth())
+					underlineFrame:Show()
+				end
+			end
+			showGameTooltip(this)
+		end)
+		button:SetScript("OnHide", function()
+			if this.secure and secureFrame:IsOwnedBy(this) then
+				secureFrame:Deactivate()
+			end
+		end)
+		button:SetScript("OnLeave", function()
+			if this.secure and secureFrame:IsShown() then
+				return;	-- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it
+			end
+			underlineFrame:Hide()
+			if not this.selected then
+				highlight:Hide()
+			end
+			button.radioHighlight:Hide()
+			if this.level then
+				StartCounting(self, this.level.num)
+			end
+			GameTooltip:Hide()
+		end)
+		local first = true
+		button:SetScript("OnClick", function()
+			if not this.disabled then
+				if this.hasColorSwatch then
+					local func = button.colorFunc
+					local hasOpacity = this.hasOpacity
+					local this = this
+					for k in pairs(tmpt) do
+						tmpt[k] = nil
+					end
+					for i = 1, 1000 do
+						local x = this['colorArg'..i]
+						if x == nil then
+							break
+						else
+							tmpt[i] = x
+						end
+					end
+					ColorPickerFrame.func = function()
+						if func then
+							local r,g,b = ColorPickerFrame:GetColorRGB()
+							local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil
+							local n = #tmpt
+							tmpt[n+1] = r
+							tmpt[n+2] = g
+							tmpt[n+3] = b
+							tmpt[n+4] = a
+							func(unpack(tmpt))
+							tmpt[n+1] = nil
+							tmpt[n+2] = nil
+							tmpt[n+3] = nil
+							tmpt[n+4] = nil
+						end
+					end
+					ColorPickerFrame.hasOpacity = this.hasOpacity
+					ColorPickerFrame.opacityFunc = ColorPickerFrame.func
+					ColorPickerFrame.opacity = 1 - this.opacity
+					ColorPickerFrame:SetColorRGB(this.r, this.g, this.b)
+					local r, g, b, a = this.r, this.g, this.b, this.opacity
+					ColorPickerFrame.cancelFunc = function()
+						if func then
+							local n = #tmpt
+							tmpt[n+1] = r
+							tmpt[n+2] = g
+							tmpt[n+3] = b
+							tmpt[n+4] = a
+							func(unpack(tmpt))
+							for i = 1, n+4 do
+								tmpt[i] = nil
+							end
+						end
+					end
+					self:Close(1)
+					ShowUIPanel(ColorPickerFrame)
+				elseif this.func then
+					local level = this.level
+					if type(this.func) == "string" then
+						if type(this.arg1[this.func]) ~= "function" then
+							self:error("Cannot call method %q", this.func)
+						end
+						this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2))
+					else
+						this.func(getArgs(this, 'arg', 1))
+					end
+					if this.closeWhenClicked then
+						self:Close()
+					elseif level:IsShown() then
+						for i = 1, level.num do
+							Refresh(self, levels[i])
+						end
+						local value = levels[level.num].value
+						for i = level.num-1, 1, -1 do
+							local level = levels[i]
+							local good = false
+							for _,button in ipairs(level.buttons) do
+								if button.value == value then
+									good = true
+									break
+								end
+							end
+							if not good then
+								Dewdrop:Close(i+1)
+							end
+							value = levels[i].value
+						end
+					end
+				elseif this.closeWhenClicked then
+					self:Close()
+				end
+			end
+		end)
+		local text = button:CreateFontString(nil, "ARTWORK")
+		button.text = text
+		text:SetFontObject(GameFontHighlightSmall)
+		button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT)
+		button:SetScript("OnMouseDown", function()
+			if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
+				text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1)
+			end
+		end)
+		button:SetScript("OnMouseUp", function()
+			if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
+				text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0)
+			end
+		end)
+		local arrow = button:CreateTexture(nil, "ARTWORK")
+		button.arrow = arrow
+		arrow:SetPoint("LEFT", button, "RIGHT", -16, 0)
+		arrow:SetWidth(16)
+		arrow:SetHeight(16)
+		arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
+		local colorSwatch = button:CreateTexture(nil, "ARTWORK")
+		button.colorSwatch = colorSwatch
+		colorSwatch:SetWidth(20)
+		colorSwatch:SetHeight(20)
+		colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
+		local texture = button:CreateTexture(nil, "OVERLAY")
+		colorSwatch.texture = texture
+		texture:SetTexture("Interface\\Buttons\\WHITE8X8")
+		texture:SetWidth(11.5)
+		texture:SetHeight(11.5)
+		texture:Show()
+		texture:SetPoint("CENTER", colorSwatch, "CENTER")
+		colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0)
+	else
+		button = table.remove(buttons)
+	end
+	button:ClearAllPoints()
+	button:SetParent(level)
+	button:SetFrameStrata(level:GetFrameStrata())
+	button:SetFrameLevel(level:GetFrameLevel() + 1)
+	button:SetPoint("LEFT", level, "LEFT", 10, 0)
+	button:SetPoint("RIGHT", level, "RIGHT", -10, 0)
+	if #level.buttons == 0 then
+		button:SetPoint("TOP", level, "TOP", 0, -10)
+	else
+		button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0)
+	end
+	button.text:SetPoint("LEFT", button, "LEFT", 24, 0)
+	button:Show()
+	button.level = level
+	table.insert(level.buttons, button)
+	if not level.parented then
+		level.parented = true
+		level:ClearAllPoints()
+		if level.num == 1 then
+			if level.parent ~= UIParent and type(level.parent) == "table" then
+				level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT")
+			else
+				level:SetPoint("CENTER", UIParent, "CENTER")
+			end
+		else
+			if level.lastDirection == "RIGHT" then
+				if level.lastVDirection == "DOWN" then
+					level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10)
+				else
+					level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10)
+				end
+			else
+				if level.lastVDirection == "DOWN" then
+					level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10)
+				else
+					level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10)
+				end
+			end
+		end
+		level:SetFrameStrata("FULLSCREEN_DIALOG")
+	end
+	button:SetAlpha(1)
+	return button
+end
+
+local numLevels = 0
+local function AcquireLevel(self, level)
+	if not levels[level] then
+		for i = #levels + 1, level, -1 do
+			local i = i
+			numLevels = numLevels + 1
+			local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil)
+			if i == 1 then
+				local old_CloseSpecialWindows = CloseSpecialWindows
+				function CloseSpecialWindows()
+					local found = old_CloseSpecialWindows()
+					if levels[1]:IsShown() then
+						self:Close()
+						return 1
+					end
+					return found
+				end
+			end
+			levels[i] = frame
+			frame.num = i
+			frame:SetParent(UIParent)
+			frame:SetFrameStrata("FULLSCREEN_DIALOG")
+			frame:Hide()
+			frame:SetWidth(180)
+			frame:SetHeight(10)
+			frame:SetFrameLevel(i * 3)
+			frame:SetScript("OnHide", function()
+				self:Close(level + 1)
+			end)
+			if frame.SetTopLevel then
+				frame:SetTopLevel(true)
+			end
+			frame:EnableMouse(true)
+			frame:EnableMouseWheel(true)
+			local backdrop = CreateFrame("Frame", nil, frame)
+			backdrop:SetAllPoints(frame)
+			backdrop:SetBackdrop(tmp(
+				'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
+				'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
+				'tile', true,
+				'insets', tmp2(
+					'left', 5,
+					'right', 5,
+					'top', 5,
+					'bottom', 5
+				),
+				'tileSize', 16,
+				'edgeSize', 16
+			))
+			backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
+			backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
+			frame:SetScript("OnClick", function()
+				self:Close(i)
+			end)
+			frame:SetScript("OnEnter", function()
+				StopCounting(self, i)
+			end)
+			frame:SetScript("OnLeave", function()
+				StartCounting(self, i)
+			end)
+			frame:SetScript("OnMouseWheel", function()
+				Scroll(self, frame, arg1 < 0)
+			end)
+			if i == 1 then
+				frame:SetScript("OnUpdate", function(this, arg1)
+					OnUpdate(self, arg1)
+				end)
+				levels[1].lastDirection = "RIGHT"
+				levels[1].lastVDirection = "DOWN"
+			else
+				levels[i].lastDirection = levels[i - 1].lastDirection
+				levels[i].lastVDirection = levels[i - 1].lastVDirection
+			end
+		end
+	end
+	local fullscreenFrame = GetUIPanel("fullscreen")
+	local l = levels[level]
+	local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel()
+	if fullscreenFrame then
+		l:SetParent(fullscreenFrame)
+	else
+		l:SetParent(UIParent)
+	end
+	l:SetFrameStrata(strata)
+	l:SetFrameLevel(framelevel)
+	l:SetAlpha(1)
+	return l
+end
+
+local function validateOptions(options, position, baseOptions, fromPass)
+	if not baseOptions then
+		baseOptions = options
+	end
+	if type(options) ~= "table" then
+		return "Options must be a table.", position
+	end
+	local kind = options.type
+	if type(kind) ~= "string" then
+		return '"type" must be a string.', position
+	elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then
+		return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position
+	end
+	if options.aliases then
+		if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then
+			return '"alias" must be a table or string', position
+		end
+	end
+	if not fromPass then
+		if kind == "execute" then
+			if type(options.func) ~= "string" and type(options.func) ~= "function" then
+				return '"func" must be a string or function', position
+			end
+		elseif kind == "range" or kind == "text" or kind == "toggle" then
+			if type(options.set) ~= "string" and type(options.set) ~= "function" then
+				return '"set" must be a string or function', position
+			end
+			if kind == "text" and options.get == false then
+			elseif type(options.get) ~= "string" and type(options.get) ~= "function" then
+				return '"get" must be a string or function', position
+			end
+		elseif kind == "group" and options.pass then
+			if options.pass ~= true then
+				return '"pass" must be either nil, true, or false', position
+			end
+			if not options.func then
+				if type(options.set) ~= "string" and type(options.set) ~= "function" then
+					return '"set" must be a string or function', position
+				end
+				if type(options.get) ~= "string" and type(options.get) ~= "function" then
+					return '"get" must be a string or function', position
+				end
+			elseif type(options.func) ~= "string" and type(options.func) ~= "function" then
+				return '"func" must be a string or function', position
+			end
+		end
+	end
+	if options ~= baseOptions then
+		if kind == "header" then
+		elseif type(options.desc) ~= "string" then
+			return '"desc" must be a string', position
+		elseif options.desc:len() == 0 then
+			return '"desc" cannot be a 0-length string', position
+		end
+	end
+	if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then
+		if options.type == "header" and not options.cmdName and not options.name then
+		elseif options.cmdName then
+			if type(options.cmdName) ~= "string" then
+				return '"cmdName" must be a string or nil', position
+			elseif options.cmdName:len() == 0 then
+				return '"cmdName" cannot be a 0-length string', position
+			end
+			if type(options.guiName) ~= "string" then
+				if not options.guiNameIsMap then
+					return '"guiName" must be a string or nil', position
+				end
+			elseif options.guiName:len() == 0 then
+				return '"guiName" cannot be a 0-length string', position
+			end
+		else
+			if type(options.name) ~= "string" then
+				return '"name" must be a string', position
+			elseif options.name:len() == 0 then
+				return '"name" cannot be a 0-length string', position
+			end
+		end
+	end
+	if options.guiNameIsMap then
+		if type(options.guiNameIsMap) ~= "boolean" then
+			return '"guiNameIsMap" must be a boolean or nil', position
+		elseif options.type ~= "toggle" then
+			return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position
+		elseif type(options.map) ~= "table" then
+			return '"map" must be a table', position
+		end
+	end
+	if options.message and type(options.message) ~= "string" then
+		return '"message" must be a string or nil', position
+	end
+	if options.error and type(options.error) ~= "string" then
+		return '"error" must be a string or nil', position
+	end
+	if options.current and type(options.current) ~= "string" then
+		return '"current" must be a string or nil', position
+	end
+	if options.order then
+		if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then
+			return '"order" must be a non-zero number or nil', position
+		end
+	end
+	if options.disabled then
+		if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then
+			return '"disabled" must be a function, string, or boolean', position
+		end
+	end
+	if options.cmdHidden then
+		if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then
+			return '"cmdHidden" must be a function, string, or boolean', position
+		end
+	end
+	if options.guiHidden then
+		if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then
+			return '"guiHidden" must be a function, string, or boolean', position
+		end
+	end
+	if options.hidden then
+		if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then
+			return '"hidden" must be a function, string, or boolean', position
+		end
+	end
+	if kind == "text" then
+		if type(options.validate) == "table" then
+			local t = options.validate
+			local iTable = nil
+			for k,v in pairs(t) do
+				if type(k) == "number" then
+					if iTable == nil then
+						iTable = true
+					elseif not iTable then
+						return '"validate" must either have all keys be indexed numbers or strings', position
+					elseif k < 1 or k > #t then
+						return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position
+					end
+				else
+					if iTable == nil then
+						iTable = false
+					elseif iTable then
+						return '"validate" must either have all keys be indexed numbers or strings', position
+					end
+				end
+				if type(v) ~= "string" then
+					return '"validate" values must all be strings', position
+				end
+			end
+			if options.multiToggle and options.multiToggle ~= true then
+				return '"multiToggle" must be a boolean or nil if "validate" is a table', position
+			end
+		elseif options.validate == "keybinding" then
+			-- no other checks
+		else
+			if type(options.usage) ~= "string" then
+				return '"usage" must be a string', position
+			elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then
+				return '"validate" must be a string, function, or table', position
+			end
+		end
+		if options.multiToggle and type(options.validate) ~= "table" then
+			return '"validate" must be a table if "multiToggle" is true', position
+		end
+	elseif kind == "range" then
+		if options.min or options.max then
+			if type(options.min) ~= "number" then
+				return '"min" must be a number', position
+			elseif type(options.max) ~= "number" then
+				return '"max" must be a number', position
+			elseif options.min >= options.max then
+				return '"min" must be less than "max"', position
+			end
+		end
+		if options.step then
+			if type(options.step) ~= "number" then
+				return '"step" must be a number', position
+			elseif options.step < 0 then
+				return '"step" must be nonnegative', position
+			end
+		end
+		if options.bigStep then
+			if type(options.bigStep) ~= "number" then
+				return '"bigStep" must be a number', position
+			elseif options.bigStep < 0 then
+				return '"bigStep" must be nonnegative', position
+			end
+		end
+		if options.isPercent and options.isPercent ~= true then
+			return '"isPercent" must either be nil, true, or false', position
+		end
+	elseif kind == "toggle" then
+		if options.map then
+			if type(options.map) ~= "table" then
+				return '"map" must be a table', position
+			elseif type(options.map[true]) ~= "string" then
+				return '"map[true]" must be a string', position
+			elseif type(options.map[false]) ~= "string" then
+				return '"map[false]" must be a string', position
+			end
+		end
+	elseif kind == "color" then
+		if options.hasAlpha and options.hasAlpha ~= true then
+			return '"hasAlpha" must be nil, true, or false', position
+		end
+	elseif kind == "group" then
+		if options.pass and options.pass ~= true then
+			return '"pass" must be nil, true, or false', position
+		end
+		if type(options.args) ~= "table" then
+			return '"args" must be a table', position
+		end
+		for k,v in pairs(options.args) do
+			if type(k) ~= "number" then
+				if type(k) ~= "string" then
+					return '"args" keys must be strings or numbers', position
+				elseif k:len() == 0 then
+					return '"args" keys must not be 0-length strings.', position
+				end
+			end
+			if type(v) ~= "table" then
+				return '"args" values must be tables', position and position .. "." .. k or k
+			end
+			local newposition
+			if position then
+				newposition = position .. ".args." .. k
+			else
+				newposition = "args." .. k
+			end
+			local err, pos = validateOptions(v, newposition, baseOptions, options.pass)
+			if err then
+				return err, pos
+			end
+		end
+	elseif kind == "execute" then
+		if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then
+			return '"confirm" must be a string, boolean, or nil', position
+		end
+	end
+	if options.icon and type(options.icon) ~= "string" then
+		return'"icon" must be a string', position
+	end
+	if options.iconWidth or options.iconHeight then
+		if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then
+			return '"iconHeight" and "iconWidth" must be numbers', position
+		end
+	end
+	if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then
+		if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then
+			return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position
+		end
+	end
+end
+
+local validatedOptions
+
+local values
+local mysort_args
+local mysort
+local othersort
+local othersort_validate
+
+local baseFunc, currentLevel
+
+local function confirmPopup(message, func, ...)
+	if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then
+		StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {}
+	end
+	local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"]
+	for k in pairs(t) do
+		t[k] = nil
+	end
+	t.text = message
+	t.button1 = ACCEPT or "Accept"
+	t.button2 = CANCEL or "Cancel"
+	t.OnAccept = function()
+		func(unpack(t))
+	end
+	for i = 1, select('#', ...) do
+		t[i] = select(i, ...)
+	end
+	t.timeout = 0
+	t.whileDead = 1
+	t.hideOnEscape = 1
+
+	Dewdrop:Close()
+	StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG")
+end
+
+
+local function getMethod(settingname, handler, v, methodName, ...)	-- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222"
+	assert(v and type(v)=="table")
+	assert(methodName and type(methodName)=="string")
+
+	local method = v[methodName]
+	if type(method)=="function" then
+		return method, ...
+	elseif type(method)=="string" then
+		if not handler then
+			Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method)
+		elseif not handler[method] then
+			Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method)
+		end
+		return handler[method], handler, ...
+	end
+
+	Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName)
+end
+
+local function callMethod(settingname, handler, v, methodName, ...)
+	assert(v and type(v)=="table")
+	assert(methodName and type(methodName)=="string")
+
+	local method = v[methodName]
+	if type(method)=="function" then
+		local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...)
+		if not success then
+			geterrorhandler()(ret)
+			return nil
+		end
+		return ret,ret2,ret3,ret4
+
+	elseif type(method)=="string" then
+
+		local neg = method:match("^~(.-)$")
+		if neg then
+			method = neg
+		end
+		if not handler then
+			Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method)
+		elseif not handler[method] then
+			Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method)
+		end
+		local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...)
+		if not success then
+			geterrorhandler()(ret)
+			return nil
+		end
+		if neg then
+			return not ret
+		end
+		return ret,ret2,ret3,ret4
+	elseif method == false then
+		return nil
+	end
+
+	Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)")
+end
+
+local function skip1Nil(...)
+	if select(1,...)==nil then
+		return select(2,...)
+	end
+	return ...
+end
+
+function Dewdrop:FeedAceOptionsTable(options, difference)
+	self:argCheck(options, 2, "table")
+	self:argCheck(difference, 3, "nil", "number")
+	if not currentLevel then
+		self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration")
+	end
+	if not difference then
+		difference = 0
+	end
+	if not validatedOptions then
+		validatedOptions = {}
+	end
+	if not validatedOptions[options] then
+		local err, position = validateOptions(options)
+
+		if err then
+			if position then
+				Dewdrop:error(position .. ": " .. err)
+			else
+				Dewdrop:error(err)
+			end
+		end
+
+		validatedOptions[options] = true
+	end
+	local level = levels[currentLevel]
+	if not level then
+		self:error("Improper level given")
+	end
+	if not values then
+		values = {}
+	else
+		for k,v in pairs(values) do
+			values[k] = nil
+		end
+	end
+
+	local current = level
+	while current do		-- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later
+		if current.num == difference + 1 then
+			break
+		end
+		table.insert(values, current.value)
+		current = levels[current.num - 1]
+	end
+
+	local realOptions = options
+	local handler = options.handler
+	local passTable
+	local passValue
+	while #values > 0 do	-- This loop traverses values from the END (trunk nodes first, then onto leaf nodes)
+		if options.pass then
+			if options.get and options.set then
+				passTable = options
+			elseif not passTable then
+				passTable = options
+			end
+		else
+			passTable = nil
+		end
+		local value = table.remove(values)
+		options = options.args and options.args[value]
+		if not options then
+			return
+		end
+		handler = options.handler or handler
+		passValue = passTable and value or nil
+	end
+
+	if options.type == "group" then
+		local hidden = options.hidden
+		if type(hidden) == "function" or type(hidden) == "string" then
+			hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false
+		end
+		if hidden then
+			return
+		end
+		local disabled = options.disabled
+		if type(disabled) == "function" or type(disabled) == "string" then
+			disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false
+		end
+		if disabled then
+			self:AddLine(
+				'text', DISABLED,
+				'disabled', true
+			)
+			return
+		end
+		for k in pairs(options.args) do
+			table.insert(values, k)
+		end
+		if options.pass then
+			if options.get and options.set then
+				passTable = options
+			elseif not passTable then
+				passTable = options
+			end
+		else
+			passTable = nil
+		end
+		if not mysort then
+			mysort = function(a, b)
+				local alpha, bravo = mysort_args[a], mysort_args[b]
+				local alpha_order = alpha.order or 100
+				local bravo_order = bravo.order or 100
+				local alpha_name = alpha.guiName or alpha.name
+				local bravo_name = bravo.guiName or bravo.name
+				if alpha_order == bravo_order then
+					if not alpha_name then
+						return bravo_name
+					elseif not bravo_name then
+						return false
+					else
+						return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper()
+					end
+				else
+					if alpha_order < 0 then
+						if bravo_order > 0 then
+							return false
+						end
+					else
+						if bravo_order < 0 then
+							return true
+						end
+					end
+					return alpha_order < bravo_order
+				end
+			end
+		end
+		mysort_args = options.args
+		table.sort(values, mysort)
+		mysort_args = nil
+		local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0
+		local last_order = 1
+		for _,k in ipairs(values) do
+			local v = options.args[k]
+			local handler = v.handler or handler
+			if hasBoth and last_order > 0 and (v.order or 100) < 0 then
+				hasBoth = false
+				self:AddLine()
+			end
+			local hidden, disabled = v.guiHidden or v.hidden, v.disabled
+
+			if type(hidden) == "function" or type(hidden) == "string" then
+				hidden = callMethod(k, handler, v, "hidden", v.passValue) or false
+			end
+			if not hidden then
+				if type(disabled) == "function" or type(disabled) == "string" then
+					disabled = callMethod(k, handler, v, "disabled", v.passValue) or false
+				end
+				local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name)
+				local desc = v.guiDesc or v.desc
+				local iconHeight = v.iconHeight or 16
+				local iconWidth = v.iconWidth or 16
+				local iconCoordLeft = v.iconCoordLeft
+				local iconCoordRight = v.iconCoordRight
+				local iconCoordBottom = v.iconCoordBottom
+				local iconCoordTop = v.iconCoordTop
+				local tooltipTitle, tooltipText
+				tooltipTitle = name
+				if name ~= desc then
+					tooltipText = desc
+				end
+				if type(v.usage) == "string" and v.usage:trim():len() > 0 then
+					if tooltipText then
+						tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage)
+					else
+						tooltipText = USAGE_TOOLTIP:format(v.usage)
+					end
+				end
+				local v_p = passTable
+				if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then
+					v_p = v
+				end
+				local passValue = v.passValue or (v_p~=v and k) or nil
+				if v.type == "toggle" then
+					local checked = callMethod(name, handler, v_p, "get", passValue) or false
+					local checked_arg = checked
+					if type(v_p.get)=="string" and v_p.get:match("^~") then
+						checked_arg = not checked
+					end
+					local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set",   skip1Nil(passValue, not checked_arg))
+					if v.guiNameIsMap then
+						checked = checked and true or false
+						name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
+						tooltipTitle = name
+						checked = true--nil
+					end
+					self:AddLine(
+						'text', name,
+						'checked', checked,
+						'isRadio', v.isRadio,
+						'func', func,
+						'arg1', arg1,
+						'arg2', arg2,
+						'arg3', arg3,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText
+					)
+				elseif v.type == "execute" then
+					local func, arg1, arg2, arg3, arg4
+					local confirm = v.confirm
+					if confirm == true then
+						confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle)
+						func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue)
+					elseif type(confirm) == "string" then
+						func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue)
+					else
+						func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue)
+					end
+					self:AddLine(
+						'text', name,
+						'checked', checked,
+						'func', func,
+						'arg1', arg1,
+						'arg2', arg2,
+						'arg3', arg3,
+						'arg4', arg4,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText,
+						'icon', v.icon,
+						'iconHeight', iconHeight,
+						'iconWidth', iconWidth,
+						'iconCoordLeft', iconCoordLeft,
+						'iconCoordRight', iconCoordRight,
+						'iconCoordTop', iconCoordTop,
+						'iconCoordBottom', iconCoordBottom
+					)
+				elseif v.type == "range" then
+					local sliderValue
+					sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0
+					local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set",    passValue)
+					if tooltipText then
+						tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP)
+					else
+						tooltipText = RANGE_TOOLTIP
+					end
+					self:AddLine(
+						'text', name,
+						'hasArrow', true,
+						'hasSlider', true,
+						'sliderMin', v.min or 0,
+						'sliderMax', v.max or 1,
+						'sliderStep', v.step or 0,
+						'sliderBigStep', v.bigStep or nil,
+						'sliderIsPercent', v.isPercent or false,
+						'sliderValue', sliderValue,
+						'sliderFunc', sliderFunc,
+						'sliderArg1', sliderArg1,
+						'sliderArg2', sliderArg2,
+						'fromAceOptions', true,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText,
+						'icon', v.icon,
+						'iconHeight', iconHeight,
+						'iconWidth', iconWidth,
+						'iconCoordLeft', iconCoordLeft,
+						'iconCoordRight', iconCoordRight,
+						'iconCoordTop', iconCoordTop,
+						'iconCoordBottom', iconCoordBottom
+					)
+				elseif v.type == "color" then
+					local r,g,b,a = callMethod(name, handler, v_p, "get", passValue)
+					if not r then
+						r,g,b,a = 0,0,0,0
+					end
+					local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set",    passValue)
+					self:AddLine(
+						'text', name,
+						'hasArrow', true,
+						'hasColorSwatch', true,
+						'r', r,
+						'g', g,
+						'b', b,
+						'opacity', v.hasAlpha and a or nil,
+						'hasOpacity', v.hasAlpha,
+						'colorFunc', colorFunc,
+						'colorArg1', colorArg1,
+						'colorArg2', colorArg2,
+						'disabled', disabled,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText
+					)
+				elseif v.type == "text" then
+						if type(v.validate) == "table" then
+						local func,arg1,arg2
+						if v.onClick then
+							func,arg1,arg2 = getMethod(name, handler, v, "onClick",    passValue)
+						end
+						local checked
+						if v.isChecked then
+							checked = callMethod(name, handler, v, "isChecked",    passValue) or false
+						end
+						self:AddLine(
+							'text', name,
+							'hasArrow', true,
+							'value', k,
+							'func', func,
+							'arg1', arg1,
+							'arg2', arg2,
+							'mouseoverUnderline', func and true or nil,
+							'disabled', disabled,
+							'checked', checked,
+							'tooltipTitle', tooltipTitle,
+							'tooltipText', tooltipText,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom
+						)
+					else
+						local editBoxText
+						editBoxText = callMethod(name, handler, v_p, "get", passValue) or ""
+						local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set",    passValue)
+
+						local editBoxValidateFunc, editBoxValidateArg1
+
+						if v.validate and v.validate ~= "keybinding" then
+							if v.validate == "keybinding" then
+								if tooltipText then
+									tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC)
+								else
+									tooltipText = RESET_KEYBINDING_DESC
+								end
+							else
+								editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue!
+							end
+						end
+
+						self:AddLine(
+							'text', name,
+							'hasArrow', true,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom,
+							'hasEditBox', true,
+							'editBoxText', editBoxText,
+							'editBoxFunc', editBoxFunc,
+							'editBoxArg1', editBoxArg1,
+							'editBoxArg2', editBoxArg2,
+							'editBoxValidateFunc', editBoxValidateFunc,
+							'editBoxValidateArg1', editBoxValidateArg1,
+							'editBoxIsKeybinding', v.validate == "keybinding",
+							'editBoxKeybindingOnly', v.keybindingOnly,
+							'editBoxKeybindingExcept', v.keybindingExcept,
+							'disabled', disabled,
+							'tooltipTitle', tooltipTitle,
+							'tooltipText', tooltipText
+						)
+					end
+				elseif v.type == "group" then
+					local func,arg1,arg2
+					if v.onClick then
+						func,arg1,arg2 = getMethod(name, handler, v, "onClick",    passValue)
+					end
+					local checked
+					if v.isChecked then
+						checked = callMethod(name, handler, v, "isChecked",    passValue) or false
+					end
+					self:AddLine(
+						'text', name,
+						'hasArrow', true,
+						'value', k,
+						'func', func,
+						'arg1', arg1,
+						'arg2', arg2,
+						'mouseoverUnderline', func and true or nil,
+						'disabled', disabled,
+						'checked', checked,
+						'tooltipTitle', tooltipTitle,
+						'tooltipText', tooltipText,
+						'icon', v.icon,
+						'iconHeight', iconHeight,
+						'iconWidth', iconWidth,
+						'iconCoordLeft', iconCoordLeft,
+						'iconCoordRight', iconCoordRight,
+						'iconCoordTop', iconCoordTop,
+						'iconCoordBottom', iconCoordBottom
+					)
+				elseif v.type == "header" then
+					if name == "" or not name then
+						self:AddLine(
+							'isTitle', true,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom
+						)
+					else
+						self:AddLine(
+							'text', name,
+							'isTitle', true,
+							'icon', v.icon,
+							'iconHeight', iconHeight,
+							'iconWidth', iconWidth,
+							'iconCoordLeft', iconCoordLeft,
+							'iconCoordRight', iconCoordRight,
+							'iconCoordTop', iconCoordTop,
+							'iconCoordBottom', iconCoordBottom
+						)
+					end
+				end
+			end
+			last_order = v.order or 100
+		end
+	elseif options.type == "text" and type(options.validate) == "table" then
+		local current
+		local options_p = passTable
+		if not options_p or (options.get and options.set) then
+			options_p = options
+			passTable = nil
+			passValue = nil
+		end
+		local multiToggle = options.multiToggle
+		local passValue = options.passValue or passValue
+		if not multiToggle then
+			current = callMethod(k, handler, options_p, "get", passValue)
+		end
+		local indexed = true
+		for k,v in pairs(options.validate) do
+			if type(k) ~= "number" then
+				indexed = false
+			end
+			table.insert(values, k)
+		end
+		if not indexed then
+			if not othersort then
+				othersort = function(alpha, bravo)
+					return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper()
+				end
+			end
+			othersort_validate = options.validate
+			table.sort(values, othersort)
+			othersort_validate = nil
+		end
+		for _,k in ipairs(values) do
+			local v = options.validate[k]
+			if type(k) == "number" then
+				k = v
+			end
+			local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set",    skip1Nil(passValue, k))
+			local checked
+			if multiToggle then
+				checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false
+				if arg2 == nil then
+					arg2 = not checked
+				elseif arg3 == nil then
+					arg3 = not checked
+				else
+					arg4 = not checked
+				end
+			else
+				checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower()))
+				if checked then
+					func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil
+				end
+			end
+			local tooltipTitle
+			local tooltipText
+			if options.validateDesc then
+				tooltipTitle = v
+				tooltipText = options.validateDesc[k]
+			else
+				tooltipTitle = options.guiName or options.name
+				tooltipText = v
+			end
+			self:AddLine(
+				'text', v,
+				'func', func,
+				'arg1', arg1,
+				'arg2', arg2,
+				'arg3', arg3,
+				'arg4', arg4,
+				'isRadio', not multiToggle,
+				'checked',  checked,
+				'tooltipTitle', tooltipTitle,
+				'tooltipText', tooltipText
+			)
+		end
+		for k in pairs(values) do
+			values[k] = nil
+		end
+	else
+		return false
+	end
+	return true
+end
+
+function Dewdrop:FeedTable(s, difference)
+	self:argCheck(s, 2, "table")
+	self:argCheck(difference, 3, "nil", "number")
+	if not currentLevel then
+		self:error("Cannot call `FeedTable' outside of a Dewdrop declaration")
+	end
+	if not difference then
+		difference = 0
+	end
+	local level = levels[currentLevel]
+	if not level then
+		self:error("Improper level given")
+	end
+	if not values then
+		values = {}
+	else
+		for k,v in pairs(values) do
+			values[k] = nil
+		end
+	end
+	local t = s.subMenu and s or {subMenu = s}
+	local current = level
+	while current do
+		if current.num == difference + 1 then
+			break
+		end
+		table.insert(values, current.value)
+		current = levels[current.num - 1]
+	end
+
+	while #values > 0 do
+		local value = table.remove(values)
+		t = t.subMenu and t.subMenu[value]
+		if not t then
+			return
+		end
+	end
+
+	if t.subMenu or current.num == 1 then
+		for k in pairs(t.subMenu) do
+			table.insert(values, k)
+		end
+		table.sort(values)
+		for _,k in ipairs(values) do
+			local argTable = {"value", k}
+			for key, val in pairs(t.subMenu[k]) do
+				table.insert(argTable, key)
+				table.insert(argTable, val)
+			end
+			self:AddLine(unpack(argTable))
+		end
+		for k in pairs(values) do
+			values[k] = nil
+		end
+		return false
+	end
+	return true
+end
+
+function Refresh(self, level)
+	if type(level) == "number" then
+		level = levels[level]
+	end
+	if not level then
+		return
+	end
+	if baseFunc then
+		Clear(self, level)
+		currentLevel = level.num
+		if type(baseFunc) == "table" then
+			if currentLevel == 1 then
+				local handler = baseFunc.handler
+				if handler then
+					local name = tostring(handler)
+					if not name:find('^table:') and not handler.hideMenuTitle then
+						name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
+						self:AddLine(
+							'text', name,
+							'isTitle', true
+						)
+					end
+				end
+--			elseif level.parentText then
+--				self:AddLine(
+--					'text', level.parentText,
+--					'tooltipTitle', level.parentTooltipTitle,
+--					'tooltipText', level.parentTooltipText,
+--					'tooltipFunc', level.parentTooltipFunc,
+--					'isTitle', true
+--				)
+			end
+			self:FeedAceOptionsTable(baseFunc)
+			if currentLevel == 1 then
+				self:AddLine(
+					'text', CLOSE,
+					'tooltipTitle', CLOSE,
+					'tooltipText', CLOSE_DESC,
+					'closeWhenClicked', true
+				)
+			end
+		else
+--			if level.parentText then
+--				self:AddLine(
+--					'text', level.parentText,
+--					'tooltipTitle', level.parentTooltipTitle,
+--					'tooltipText', level.parentTooltipText,
+--					'tooltipFunc', level.parentTooltipFunc,
+--					'isTitle', true
+--				)
+--			end
+			baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value)
+		end
+		currentLevel = nil
+		CheckSize(self, level)
+	end
+end
+
+function Dewdrop:Refresh(level)
+	self:argCheck(level, 2, "number", "nil")
+	if not level then
+		for k,v in pairs(levels) do
+			Refresh(self, v)
+		end
+	else
+		Refresh(self, levels[level])
+	end
+end
+
+function OpenSlider(self, parent)
+	if not sliderFrame then
+		sliderFrame = CreateFrame("Frame", nil, nil)
+		sliderFrame:SetWidth(100)
+		sliderFrame:SetHeight(170)
+		sliderFrame:SetScale(UIParent:GetScale())
+		sliderFrame:SetBackdrop(tmp(
+			'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
+			'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
+			'tile', true,
+			'insets', tmp2(
+				'left', 5,
+				'right', 5,
+				'top', 5,
+				'bottom', 5
+			),
+			'tileSize', 16,
+			'edgeSize', 16
+		))
+		sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+		if sliderFrame.SetTopLevel then
+			sliderFrame:SetTopLevel(true)
+		end
+		sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
+		sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
+		sliderFrame:EnableMouse(true)
+		sliderFrame:EnableMouseWheel(true)
+		sliderFrame:Hide()
+		sliderFrame:SetPoint("CENTER", UIParent, "CENTER")
+		local slider = CreateFrame("Slider", nil, sliderFrame)
+		sliderFrame.slider = slider
+		slider:SetOrientation("VERTICAL")
+		slider:SetMinMaxValues(0, 1)
+		slider:SetValueStep(0.000000001)
+		slider:SetValue(0.5)
+		slider:SetWidth(16)
+		slider:SetHeight(128)
+		slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0)
+		slider:SetBackdrop(tmp(
+			'bgFile', "Interface\\Buttons\\UI-SliderBar-Background",
+			'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border",
+			'tile', true,
+			'edgeSize', 8,
+			'tileSize', 8,
+			'insets', tmp2(
+				'left', 3,
+				'right', 3,
+				'top', 3,
+				'bottom', 3
+			)
+		))
+		local texture = slider:CreateTexture()
+		slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
+		local text = slider:CreateFontString(nil, "ARTWORK")
+		sliderFrame.topText = text
+		text:SetFontObject(GameFontGreenSmall)
+		text:SetText("100%")
+		text:SetPoint("BOTTOM", slider, "TOP")
+		local text = slider:CreateFontString(nil, "ARTWORK")
+		sliderFrame.bottomText = text
+		text:SetFontObject(GameFontGreenSmall)
+		text:SetText("0%")
+		text:SetPoint("TOP", slider, "BOTTOM")
+		local editBox = CreateFrame("EditBox", nil, sliderFrame)
+		sliderFrame.currentText = editBox
+		editBox:SetFontObject(ChatFontNormal)
+		editBox:SetHeight(13)
+		editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0)
+		editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0)
+		editBox:SetText("50%")
+		editBox:SetJustifyH("CENTER")
+
+		local width = editBox:GetWidth()/2 + 10
+		local left = editBox:CreateTexture(nil, "BACKGROUND")
+		left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
+		left:SetTexCoord(0, width / 256, 0, 1)
+		left:SetWidth(width)
+		left:SetHeight(32)
+		left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
+		local right = editBox:CreateTexture(nil, "BACKGROUND")
+		right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
+		right:SetTexCoord(1 - width / 256, 1, 0, 1)
+		right:SetWidth(width)
+		right:SetHeight(32)
+		right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
+
+		local changed = false
+		local inside = false
+		slider:SetScript("OnValueChanged", function()
+			if sliderFrame.changing then
+				return
+			end
+			changed = true
+			local done = false
+			if sliderFrame.parent and sliderFrame.parent.sliderFunc then
+				local min = sliderFrame.parent.sliderMin or 0
+				local max = sliderFrame.parent.sliderMax or 1
+				local step
+				if sliderFrame.fineStep then
+					step = sliderFrame.parent.sliderStep or (max - min) / 100
+				else
+					step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100
+				end
+				local value = (1 - slider:GetValue()) * (max - min) + min
+				if step > 0 then
+					value = math.floor((value - min) / step + 0.5) * step + min
+					if value > max then
+						value = max
+					elseif value < min then
+						value = min
+					end
+				end
+				if value == sliderFrame.lastValue then
+					return
+				end
+				sliderFrame.lastValue = value
+				local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value))
+				if sliderFrame.parent.fromAceOptions then
+					text = nil
+				elseif type(text) == "string" or type(text) == "number" then
+					sliderFrame.currentText:SetText(text)
+					done = true
+				end
+			end
+			if not done then
+				local min = sliderFrame.parent.sliderMin or 0
+				local max = sliderFrame.parent.sliderMax or 1
+				local step
+				if sliderFrame.fineStep then
+					step = sliderFrame.parent.sliderStep or (max - min) / 100
+				else
+					step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100
+				end
+				local value = (1 - slider:GetValue()) * (max - min) + min
+				if step > 0 then
+					value = math.floor((value - min) / step + 0.5) * step + min
+					if value > max then
+						value = max
+					elseif value < min then
+						value = min
+					end
+				end
+				if sliderFrame.parent.sliderIsPercent then
+					sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100))
+				else
+					if step < 0.1 then
+						sliderFrame.currentText:SetText(string.format("%.2f", value))
+					elseif step < 1 then
+						sliderFrame.currentText:SetText(string.format("%.1f", value))
+					else
+						sliderFrame.currentText:SetText(string.format("%.0f", value))
+					end
+				end
+			end
+		end)
+		local function onEnter()
+			StopCounting(self, sliderFrame.level)
+			showGameTooltip(sliderFrame.parent)
+		end
+		local function onLeave()
+			GameTooltip:Hide()
+		end
+		sliderFrame:SetScript("OnEnter", onEnter)
+		sliderFrame:SetScript("OnLeave", function()
+			GameTooltip:Hide()
+			if changed then
+				local parent = sliderFrame.parent
+				local sliderFunc = parent.sliderFunc
+				for i = 1, sliderFrame.level - 1 do
+					Refresh(self, levels[i])
+				end
+				local newParent
+				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
+					if button.sliderFunc == sliderFunc then
+						newParent = button
+						break
+					end
+				end
+				if newParent then
+					OpenSlider(self, newParent)
+				else
+					sliderFrame:Hide()
+				end
+			end
+		end)
+		editBox:SetScript("OnEnter", onEnter)
+		editBox:SetScript("OnLeave", onLeave)
+		slider:SetScript("OnMouseDown", function()
+			sliderFrame.mouseDown = true
+			GameTooltip:Hide()
+		end)
+		slider:SetScript("OnMouseUp", function()
+			sliderFrame.mouseDown = false
+			if changed--[[ and not inside]] then
+				local parent = sliderFrame.parent
+				local sliderFunc = parent.sliderFunc
+				for i = 1, sliderFrame.level - 1 do
+					Refresh(self, levels[i])
+				end
+				local newParent
+				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
+					if button.sliderFunc == sliderFunc then
+						newParent = button
+						break
+					end
+				end
+				if newParent then
+					OpenSlider(self, newParent)
+				else
+					sliderFrame:Hide()
+				end
+			end
+			if inside then
+				showGameTooltip(sliderFrame.parent)
+			end
+		end)
+		slider:SetScript("OnEnter", function()
+			inside = true
+			StopCounting(self, sliderFrame.level)
+			showGameTooltip(sliderFrame.parent)
+		end)
+		slider:SetScript("OnLeave", function()
+			inside = false
+			GameTooltip:Hide()
+			if changed and not sliderFrame.mouseDown then
+				local parent = sliderFrame.parent
+				local sliderFunc = parent.sliderFunc
+				for i = 1, sliderFrame.level - 1 do
+					Refresh(self, levels[i])
+				end
+				local newParent
+				for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
+					if button.sliderFunc == sliderFunc then
+						newParent = button
+						break
+					end
+				end
+				if newParent then
+					OpenSlider(self, newParent)
+				else
+					sliderFrame:Hide()
+				end
+
+				changed = false
+			end
+		end)
+		sliderFrame:SetScript("OnMouseWheel", function(t, a1)
+			local arg1 = a1 or arg1
+			local up = arg1 > 0
+
+			local min = sliderFrame.parent.sliderMin or 0
+			local max = sliderFrame.parent.sliderMax or 1
+			local step = sliderFrame.parent.sliderStep or (max - min) / 100
+			if step <= 0 then
+				step = (max - min) / 100
+			end
+
+			local value = (1 - slider:GetValue()) * (max - min) + min
+			if up then
+				value = value + step
+			else
+				value = value - step
+			end
+			if value > max then
+				value = max
+			elseif value < min then
+				value = min
+			end
+			sliderFrame.fineStep = true
+			if max<=min then
+				slider:SetValue(0)
+			else
+				slider:SetValue(1 - (value - min) / (max - min))
+			end
+			sliderFrame.fineStep = nil
+		end)
+		slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel"))
+		editBox:SetScript("OnEnterPressed", function(t, a1)
+			local value = editBox:GetNumber()
+
+			if sliderFrame.parent.sliderIsPercent then
+				value = value / 100
+			end
+
+			local min = sliderFrame.parent.sliderMin or 0
+			local max = sliderFrame.parent.sliderMax or 1
+
+			if value > max then
+				value = max
+			elseif value < min then
+				value = min
+			end
+			sliderFrame.fineStep = true
+			if max <= min then
+				slider:SetValue(0)
+			else
+				slider:SetValue(1 - (value - min) / (max - min))
+			end
+			sliderFrame.fineStep = nil
+
+			StartCounting(self, sliderFrame.level)
+		end)
+		editBox:SetScript("OnEscapePressed", function()
+			self:Close(sliderFrame.level)
+			StartCounting(self, sliderFrame.level)
+		end)
+		editBox:SetAutoFocus(false)
+	end
+	sliderFrame.parent = parent
+	sliderFrame.level = parent.level.num + 1
+	sliderFrame.parentValue = parent.level.value
+	sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
+	sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
+	sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
+	sliderFrame.currentText:ClearFocus()
+	sliderFrame.changing = true
+	if not parent.sliderMin or not parent.sliderMax then
+		return
+	end
+
+	if parent.arrow then
+--		parent.arrow:SetVertexColor(0.2, 0.6, 0)
+--		parent.arrow:SetHeight(24)
+--		parent.arrow:SetWidth(24)
+		parent.selected = true
+		parent.highlight:Show()
+	end
+
+	sliderFrame:SetClampedToScreen(false)
+	if not parent.sliderValue then
+		parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2
+	end
+	if parent.sliderMax <= parent.sliderMin then
+		sliderFrame.slider:SetValue(0)
+	else
+		sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin))
+	end
+	sliderFrame.changing = false
+	sliderFrame.bottomText:SetText(parent.sliderMinText or "0")
+	sliderFrame.topText:SetText(parent.sliderMaxText or "1")
+	local text
+	if parent.sliderFunc and not parent.fromAceOptions then
+		text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue))
+	end
+	if type(text) == "number" or type(text) == "string" then
+		sliderFrame.currentText:SetText(text)
+	elseif parent.sliderIsPercent then
+		sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100))
+	else
+		if parent.sliderStep < 0.1 then
+			sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue))
+		elseif parent.sliderStep < 1 then
+			sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue))
+		else
+			sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue))
+		end
+	end
+
+
+	sliderFrame.lastValue = parent.sliderValue
+
+	local level = parent.level
+	sliderFrame:Show()
+	sliderFrame:ClearAllPoints()
+	if level.lastDirection == "RIGHT" then
+		if level.lastVDirection == "DOWN" then
+			sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+		else
+			sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+		end
+	else
+		if level.lastVDirection == "DOWN" then
+			sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+		else
+			sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+		end
+	end
+	local dirty
+	if level.lastDirection == "RIGHT" then
+		if sliderFrame:GetRight() > GetScreenWidth() then
+			level.lastDirection = "LEFT"
+			dirty = true
+		end
+	elseif sliderFrame:GetLeft() < 0 then
+		level.lastDirection = "RIGHT"
+		dirty = true
+	end
+	if level.lastVDirection == "DOWN" then
+		if sliderFrame:GetBottom() < 0 then
+			level.lastVDirection = "UP"
+			dirty = true
+		end
+	elseif sliderFrame:GetTop() > GetScreenWidth() then
+		level.lastVDirection = "DOWN"
+		dirty = true
+	end
+	if dirty then
+		sliderFrame:ClearAllPoints()
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom()
+	sliderFrame:ClearAllPoints()
+	sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	if mod(level.num, 5) == 0 then
+		local left, bottom = level:GetLeft(), level:GetBottom()
+		level:ClearAllPoints()
+		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	end
+	sliderFrame:SetClampedToScreen(true)
+end
+
+function OpenEditBox(self, parent)
+	if not editBoxFrame then
+		editBoxFrame = CreateFrame("Frame", nil, nil)
+		editBoxFrame:SetWidth(200)
+		editBoxFrame:SetHeight(40)
+		editBoxFrame:SetScale(UIParent:GetScale())
+		editBoxFrame:SetBackdrop(tmp(
+			'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
+			'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
+			'tile', true,
+			'insets', tmp2(
+				'left', 5,
+				'right', 5,
+				'top', 5,
+				'bottom', 5
+			),
+			'tileSize', 16,
+			'edgeSize', 16
+		))
+		editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+		if editBoxFrame.SetTopLevel then
+			editBoxFrame:SetTopLevel(true)
+		end
+		editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
+		editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
+		editBoxFrame:EnableMouse(true)
+		editBoxFrame:EnableMouseWheel(true)
+		editBoxFrame:Hide()
+		editBoxFrame:SetPoint("CENTER", UIParent, "CENTER")
+
+		local editBox = CreateFrame("EditBox", nil, editBoxFrame)
+		editBoxFrame.editBox = editBox
+		editBox:SetFontObject(ChatFontNormal)
+		editBox:SetWidth(160)
+		editBox:SetHeight(13)
+		editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0)
+
+		local left = editBox:CreateTexture(nil, "BACKGROUND")
+		left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
+		left:SetTexCoord(0, 100 / 256, 0, 1)
+		left:SetWidth(100)
+		left:SetHeight(32)
+		left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
+		local right = editBox:CreateTexture(nil, "BACKGROUND")
+		right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
+		right:SetTexCoord(156/256, 1, 0, 1)
+		right:SetWidth(100)
+		right:SetHeight(32)
+		right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
+
+		editBox:SetScript("OnEnterPressed", function()
+			if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then
+				local t = editBox.realText or editBox:GetText() or ""
+				local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t))
+				if not result then
+					UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0)
+					return
+				end
+			end
+			if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then
+				local t
+				if editBox.realText ~= "NONE" then
+					t = editBox.realText or editBox:GetText() or ""
+				end
+				editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t))
+			end
+			self:Close(editBoxFrame.level)
+			for i = 1, editBoxFrame.level - 1 do
+				Refresh(self, levels[i])
+			end
+			StartCounting(self, editBoxFrame.level-1)
+		end)
+		editBox:SetScript("OnEscapePressed", function()
+			self:Close(editBoxFrame.level)
+			StartCounting(self, editBoxFrame.level-1)
+		end)
+		editBox:SetScript("OnReceiveDrag", function(this)
+			if GetCursorInfo then
+				local type, alpha, bravo = GetCursorInfo()
+				local text
+				if type == "spell" then
+					text = GetSpellName(alpha, bravo)
+				elseif type == "item" then
+					text = bravo
+				end
+				if not text then
+					return
+				end
+				ClearCursor()
+				editBox:SetText(text)
+			end
+		end)
+		local changing = false
+		local skipNext = false
+
+		function editBox:SpecialSetText(text)
+			local oldText = editBox:GetText() or ""
+			if not text then
+				text = ""
+			end
+			if text ~= oldText then
+				changing = true
+				self:SetText(tostring(text))
+				changing = false
+				skipNext = true
+			end
+		end
+
+		editBox:SetScript("OnTextChanged", function()
+			if skipNext then
+				skipNext = false
+			elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then
+				local t
+				if editBox.realText ~= "NONE" then
+					t = editBox.realText or editBox:GetText() or ""
+				end
+				local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t))
+				if text then
+					editBox:SpecialSetText(text)
+				end
+			end
+		end)
+		editBoxFrame:SetScript("OnEnter", function()
+			StopCounting(self, editBoxFrame.level)
+			showGameTooltip(editBoxFrame.parent)
+		end)
+		editBoxFrame:SetScript("OnLeave", function()
+			GameTooltip:Hide()
+		end)
+		editBox:SetScript("OnEnter", function()
+			StopCounting(self, editBoxFrame.level)
+			showGameTooltip(editBoxFrame.parent)
+		end)
+		editBox:SetScript("OnLeave", function()
+			GameTooltip:Hide()
+		end)
+		editBoxFrame:SetScript("OnKeyDown", function(this, a1)
+			if not editBox.keybinding then
+				return
+			end
+			local arg1 = a1 or arg1
+			local screenshotKey = GetBindingKey("SCREENSHOT")
+			if screenshotKey and arg1 == screenshotKey then
+				Screenshot()
+				return
+			end
+
+			if arg1 == "LeftButton" then
+				arg1 = "BUTTON1"
+			elseif arg1 == "RightButton" then
+				arg1 = "BUTTON2"
+			elseif arg1 == "MiddleButton" then
+				arg1 = "BUTTON3"
+			elseif arg1 == "Button4" then
+				arg1 = "BUTTON4"
+			elseif arg1 == "Button5" then
+				arg1 = "BUTTON5"
+			end
+			if arg1 == "UNKNOWN" then
+				return
+			elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then
+				return
+			elseif arg1 == "ENTER" then
+				if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then
+					return editBox:GetScript("OnEscapePressed")()
+				elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then
+					return editBox:GetScript("OnEscapePressed")()
+				else
+					return editBox:GetScript("OnEnterPressed")()
+				end
+			elseif arg1 == "ESCAPE" then
+				if editBox.realText == "NONE" then
+					return editBox:GetScript("OnEscapePressed")()
+				else
+					editBox:SpecialSetText(NONE or "NONE")
+					editBox.realText = "NONE"
+					return
+				end
+			elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then
+				return
+			elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then
+				return
+			end
+			local s = GetBindingText(arg1, "KEY_")
+			if s == "BUTTON1" then
+				s = KEY_BUTTON1
+			elseif s == "BUTTON2" then
+				s = KEY_BUTTON2
+			end
+			local real = arg1
+			if IsShiftKeyDown() then
+				s = "Shift-" .. s
+				real = "SHIFT-" .. real
+			end
+			if IsControlKeyDown() then
+				s = "Ctrl-" .. s
+				real = "CTRL-" .. real
+			end
+			if IsAltKeyDown() then
+				s = "Alt-" .. s
+				real = "ALT-" .. real
+			end
+			if editBox:GetText() ~= s then
+				editBox:SpecialSetText("-")
+				editBox:SpecialSetText(s)
+				editBox.realText = real
+				return editBox:GetScript("OnTextChanged")()
+			end
+		end)
+		editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown"))
+		editBox:SetScript("OnMouseDown", function(this, ...)
+			if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then
+				return editBox:GetScript("OnReceiveDrag")(this, ...)
+			end
+			return editBoxFrame:GetScript("OnKeyDown")(this, ...)
+		end)
+		editBoxFrame:SetScript("OnMouseWheel", function(t, a1)
+			local arg1 = a1 or arg1
+			local up = arg1 > 0
+			arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN"
+			return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1)
+		end)
+		editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel"))
+	end
+	editBoxFrame.parent = parent
+	editBoxFrame.level = parent.level.num + 1
+	editBoxFrame.parentValue = parent.level.value
+	editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
+	editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1)
+	editBoxFrame.editBox.realText = nil
+	editBoxFrame:SetClampedToScreen(false)
+
+	editBoxFrame.editBox:SpecialSetText("")
+	if parent.editBoxIsKeybinding then
+		local s = parent.editBoxText
+		if s == "" then
+			s =  "NONE"
+		end
+		editBoxFrame.editBox.realText = s
+		if s and s ~= "NONE" then
+			local alpha,bravo = s:match("^(.+)%-(.+)$")
+			if not bravo then
+				alpha = nil
+				bravo = s
+			end
+			bravo = GetBindingText(bravo, "KEY_")
+			if alpha then
+				editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo)
+			else
+				editBoxFrame.editBox:SpecialSetText(bravo)
+			end
+		else
+			editBoxFrame.editBox:SpecialSetText(NONE or "NONE")
+		end
+	else
+		editBoxFrame.editBox:SpecialSetText(parent.editBoxText)
+	end
+
+	editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding
+	editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly
+	editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept
+	editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding)
+	editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding)
+
+	if parent.arrow then
+--		parent.arrow:SetVertexColor(0.2, 0.6, 0)
+--		parent.arrow:SetHeight(24)
+--		parent.arrow:SetWidth(24)
+		parent.selected = true
+		parent.highlight:Show()
+	end
+
+	local level = parent.level
+	editBoxFrame:Show()
+	editBoxFrame:ClearAllPoints()
+	if level.lastDirection == "RIGHT" then
+		if level.lastVDirection == "DOWN" then
+			editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+		else
+			editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+		end
+	else
+		if level.lastVDirection == "DOWN" then
+			editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+		else
+			editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+		end
+	end
+	local dirty
+	if level.lastDirection == "RIGHT" then
+		if editBoxFrame:GetRight() > GetScreenWidth() then
+			level.lastDirection = "LEFT"
+			dirty = true
+		end
+	elseif editBoxFrame:GetLeft() < 0 then
+		level.lastDirection = "RIGHT"
+		dirty = true
+	end
+	if level.lastVDirection == "DOWN" then
+		if editBoxFrame:GetBottom() < 0 then
+			level.lastVDirection = "UP"
+			dirty = true
+		end
+	elseif editBoxFrame:GetTop() > GetScreenWidth() then
+		level.lastVDirection = "DOWN"
+		dirty = true
+	end
+	if dirty then
+		editBoxFrame:ClearAllPoints()
+		if level.lastDirection == "RIGHT" then
+			if level.lastVDirection == "DOWN" then
+				editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
+			else
+				editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
+			end
+		else
+			if level.lastVDirection == "DOWN" then
+				editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
+			else
+				editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
+			end
+		end
+	end
+	local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom()
+	editBoxFrame:ClearAllPoints()
+	editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	if mod(level.num, 5) == 0 then
+		local left, bottom = level:GetLeft(), level:GetBottom()
+		level:ClearAllPoints()
+		level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
+	end
+	editBoxFrame:SetClampedToScreen(true)
+end
+
+function Dewdrop:EncodeKeybinding(text)
+	if text == nil or text == "NONE" then
+		return nil
+	end
+	text = tostring(text):upper()
+	local shift, ctrl, alt
+	local modifier
+	while true do
+		if text == "-" then
+			break
+		end
+		modifier, text = strsplit('-', text, 2)
+		if text then
+			if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
+				return false
+			end
+			if modifier == "SHIFT" then
+				if shift then
+					return false
+				end
+				shift = true
+			end
+			if modifier == "CTRL" then
+				if ctrl then
+					return false
+				end
+				ctrl = true
+			end
+			if modifier == "ALT" then
+				if alt then
+					return false
+				end
+				alt = true
+			end
+		else
+			text = modifier
+			break
+		end
+	end
+	if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then
+		return false
+	end
+	local s = GetBindingText(text, "KEY_")
+	if s == "BUTTON1" then
+		s = KEY_BUTTON1
+	elseif s == "BUTTON2" then
+		s = KEY_BUTTON2
+	end
+	if shift then
+		s = "Shift-" .. s
+	end
+	if ctrl then
+		s = "Ctrl-" .. s
+	end
+	if alt then
+		s = "Alt-" .. s
+	end
+	return s
+end
+
+function Dewdrop:IsOpen(parent)
+	self:argCheck(parent, 2, "table", "string", "nil")
+	return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent())
+end
+
+function Dewdrop:GetOpenedParent()
+	return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent())
+end
+
+function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY)
+	self:Close(level)
+	if DewdropLib then
+		local d = DewdropLib:GetInstance('1.0')
+		local ret, val = pcall(d, IsOpen, d)
+		if ret and val then
+			DewdropLib:GetInstance('1.0'):Close()
+		end
+	end
+	if type(parent) == "table" then
+		parent:GetCenter()
+	end
+	local frame = AcquireLevel(self, level)
+	if level == 1 then
+		frame.lastDirection = "RIGHT"
+		frame.lastVDirection = "DOWN"
+	else
+		frame.lastDirection = levels[level - 1].lastDirection
+		frame.lastVDirection = levels[level - 1].lastVDirection
+	end
+	frame:SetFrameStrata("FULLSCREEN_DIALOG")
+	frame:ClearAllPoints()
+	frame.parent = parent
+	frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0)
+	frame:Show()
+	if level == 1 then
+		baseFunc = func
+	end
+	levels[level].value = value
+--	levels[level].parentText = parent.text and parent.text:GetText() or nil
+--	levels[level].parentTooltipTitle = parent.tooltipTitle
+--	levels[level].parentTooltipText = parent.tooltipText
+--	levels[level].parentTooltipFunc = parent.tooltipFunc
+	if type(parent) == "table" and parent.arrow then
+--		parent.arrow:SetVertexColor(0.2, 0.6, 0)
+--		parent.arrow:SetHeight(24)
+--		parent.arrow:SetWidth(24)
+		parent.selected = true
+		parent.highlight:Show()
+	end
+	relativePoint = relativePoint or point
+	Refresh(self, levels[level])
+	if point or (cursorX and cursorY) then
+		frame:ClearAllPoints()
+		if cursorX and cursorY then
+			local curX, curY = GetScaledCursorPosition()
+			if curY < GetScreenHeight() / 2 then
+				point, relativePoint = "BOTTOM", "BOTTOM"
+			else
+				point, relativePoint = "TOP", "TOP"
+			end
+			if curX < GetScreenWidth() / 2 then
+				point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT"
+			else
+				point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT"
+			end
+		end
+		frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint)
+		if cursorX and cursorY then
+			local left = frame:GetLeft()
+			local width = frame:GetWidth()
+			local bottom = frame:GetBottom()
+			local height = frame:GetHeight()
+			local curX, curY = GetScaledCursorPosition()
+			frame:ClearAllPoints()
+			relativePoint = relativePoint or point
+			if point == "BOTTOM" or point == "TOP" then
+				if curX < GetScreenWidth() / 2 then
+					point = point .. "LEFT"
+				else
+					point = point .. "RIGHT"
+				end
+			elseif point == "CENTER" then
+				if curX < GetScreenWidth() / 2 then
+					point = "LEFT"
+				else
+					point = "RIGHT"
+				end
+			end
+			local xOffset, yOffset = 0, 0
+			if curY > GetScreenHeight() / 2 then
+				yOffset = -height
+			end
+			if curX > GetScreenWidth() / 2 then
+				xOffset = -width
+			end
+			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset)
+			if level == 1 then
+				frame.lastDirection = "RIGHT"
+			end
+		elseif cursorX then
+			local left = frame:GetLeft()
+			local width = frame:GetWidth()
+			local curX, curY = GetScaledCursorPosition()
+			frame:ClearAllPoints()
+			relativePoint = relativePoint or point
+			if point == "BOTTOM" or point == "TOP" then
+				if curX < GetScreenWidth() / 2 then
+					point = point .. "LEFT"
+				else
+					point = point .. "RIGHT"
+				end
+			elseif point == "CENTER" then
+				if curX < GetScreenWidth() / 2 then
+					point = "LEFT"
+				else
+					point = "RIGHT"
+				end
+			end
+			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0)
+			if level == 1 then
+				frame.lastDirection = "RIGHT"
+			end
+		elseif cursorY then
+			local bottom = frame:GetBottom()
+			local height = frame:GetHeight()
+			local curX, curY = GetScaledCursorPosition()
+			frame:ClearAllPoints()
+			relativePoint = relativePoint or point
+			if point == "LEFT" or point == "RIGHT" then
+				if curX < GetScreenHeight() / 2 then
+					point = point .. "BOTTOM"
+				else
+					point = point .. "TOP"
+				end
+			elseif point == "CENTER" then
+				if curX < GetScreenHeight() / 2 then
+					point = "BOTTOM"
+				else
+					point = "TOP"
+				end
+			end
+			frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2)
+			if level == 1 then
+				frame.lastDirection = "DOWN"
+			end
+		end
+		if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then
+			if frame:GetBottom() < 0 then
+				local point, parent, relativePoint, x, y = frame:GetPoint(1)
+				local change = GetScreenHeight() - frame:GetTop()
+				local otherChange = -frame:GetBottom()
+				if otherChange < change then
+					change = otherChange
+				end
+				frame:SetPoint(point, parent, relativePoint, x, y + change)
+			elseif frame:GetTop() > GetScreenHeight() then
+				local point, parent, relativePoint, x, y = frame:GetPoint(1)
+				local change = GetScreenHeight() - frame:GetTop()
+				local otherChange = -frame:GetBottom()
+				if otherChange < change then
+					change = otherChange
+				end
+				frame:SetPoint(point, parent, relativePoint, x, y + change)
+			end
+		end
+	end
+	CheckDualMonitor(self, frame)
+	frame:SetClampedToScreen(true)
+	frame:SetClampedToScreen(false)
+	StartCounting(self, level)
+end
+
+function Dewdrop:IsRegistered(parent)
+	self:argCheck(parent, 2, "table", "string")
+	return not not self.registry[parent]
+end
+
+function Dewdrop:Register(parent, ...)
+	self:argCheck(parent, 2, "table", "string")
+	if self.registry[parent] then
+		self:Unregister(parent)
+	end
+	local info = new(...)
+	if type(info.children) == "table" then
+		local err, position = validateOptions(info.children)
+
+		if err then
+			if position then
+				Dewdrop:error(position .. ": " .. err)
+			else
+				Dewdrop:error(err)
+			end
+		end
+	end
+	self.registry[parent] = info
+	if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then
+		if parent:HasScript("OnMouseUp") then
+			local script = parent:GetScript("OnMouseUp")
+			parent:SetScript("OnMouseUp", function(this, ...)
+				if script then
+					script(this, ...)
+				end
+				if arg1 == "RightButton" and self.registry[parent] then
+					if self:IsOpen(parent) then
+						self:Close()
+					else
+						self:Open(parent)
+					end
+				end
+			end)
+		end
+		if parent:HasScript("OnMouseDown") then
+			local script = parent:GetScript("OnMouseDown")
+			parent:SetScript("OnMouseDown", function(this, ...)
+				if script then
+					script(this, ...)
+				end
+				if self.registry[parent] then
+					self:Close()
+				end
+			end)
+		end
+	end
+	self.onceRegistered[parent] = true
+end
+
+function Dewdrop:Unregister(parent)
+	self:argCheck(parent, 2, "table", "string")
+	self.registry[parent] = nil
+end
+
+function Dewdrop:Open(parent, ...)
+	self:argCheck(parent, 2, "table", "string")
+	local info
+	local k1 = ...
+	if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then
+		info = tmp(select(2, ...))
+		for k,v in pairs(self.registry[k1]) do
+			if info[k] == nil then
+				info[k] = v
+			end
+		end
+	else
+		info = tmp(...)
+		if self.registry[parent] then
+			for k,v in pairs(self.registry[parent]) do
+				if info[k] == nil then
+					info[k] = v
+				end
+			end
+		end
+	end
+	local point = info.point
+	local relativePoint = info.relativePoint
+	local cursorX = info.cursorX
+	local cursorY = info.cursorY
+	if type(point) == "function" then
+		local b
+		point, b = point(parent)
+		if b then
+			relativePoint = b
+		end
+	end
+	if type(relativePoint) == "function" then
+		relativePoint = relativePoint(parent)
+	end
+	Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY)
+end
+
+function Clear(self, level)
+	if level then
+		if level.buttons then
+			for i = #level.buttons, 1, -1 do
+				ReleaseButton(self, level, i)
+			end
+		end
+	end
+end
+
+function Dewdrop:Close(level)
+	if DropDownList1:IsShown() then
+		DropDownList1:Hide()
+	end
+	if DewdropLib then
+		local d = DewdropLib:GetInstance('1.0')
+		local ret, val = pcall(d, IsOpen, d)
+		if ret and val then
+			DewdropLib:GetInstance('1.0'):Close()
+		end
+	end
+	self:argCheck(level, 2, "number", "nil")
+	if not level then
+		level = 1
+	end
+	if level == 1 and levels[level] then
+		levels[level].parented = false
+	end
+	if level > 1 and levels[level-1].buttons then
+		local buttons = levels[level-1].buttons
+		for _,button in ipairs(buttons) do
+--			button.arrow:SetWidth(16)
+--			button.arrow:SetHeight(16)
+			button.selected = nil
+			button.highlight:Hide()
+--			button.arrow:SetVertexColor(1, 1, 1)
+		end
+	end
+	if sliderFrame and sliderFrame.level >= level then
+		sliderFrame:Hide()
+	end
+	if editBoxFrame and editBoxFrame.level >= level then
+		editBoxFrame:Hide()
+	end
+	for i = level, #levels do
+		Clear(self, levels[level])
+		levels[i]:Hide()
+		levels[i]:ClearAllPoints()
+		levels[i]:SetPoint("CENTER", UIParent, "CENTER")
+		levels[i].value = nil
+	end
+end
+
+function Dewdrop:AddSeparator(level)
+	level = levels[level or currentLevel]
+	if not level or not level.buttons then return; end
+
+	local prevbutton = level.buttons[#level.buttons]
+	if not prevbutton then return; end
+
+	if prevbutton.disabled and prevbutton.text:GetText() == "" then
+		return
+	end
+	self:AddLine("text", "", "disabled", true)
+end
+
+function Dewdrop:AddLine(...)
+	local info = tmp(...)
+	local level = info.level or currentLevel
+	info.level = nil
+	local button = AcquireButton(self, level)
+	if not next(info) then
+		info.disabled = true
+	end
+	button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure)
+	button.isTitle = info.isTitle
+	button.notClickable = info.notClickable
+	if button.isTitle then
+		button.text:SetFontObject(GameFontNormalSmall)
+	elseif button.notClickable then
+		button.text:SetFontObject(GameFontHighlightSmall)
+	elseif button.disabled then
+		button.text:SetFontObject(GameFontDisableSmall)
+	else
+		button.text:SetFontObject(GameFontHighlightSmall)
+	end
+	if info.disabled then
+		button.arrow:SetDesaturated(true)
+		button.check:SetDesaturated(true)
+	else
+		button.arrow:SetDesaturated(false)
+		button.check:SetDesaturated(false)
+	end
+	if info.textR and info.textG and info.textB then
+		button.textR = info.textR
+		button.textG = info.textG
+		button.textB = info.textB
+		button.text:SetTextColor(button.textR, button.textG, button.textB)
+	else
+		button.text:SetTextColor(button.text:GetFontObject():GetTextColor())
+	end
+	button.notCheckable = info.notCheckable
+	button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0)
+	button.checked = not info.notCheckable and info.checked
+	button.mouseoverUnderline = info.mouseoverUnderline
+	button.isRadio = not info.notCheckable and info.isRadio
+	if info.isRadio then
+		button.check:Show()
+		button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
+		if button.checked then
+			button.check:SetTexCoord(0.25, 0.5, 0, 1)
+			button.check:SetVertexColor(1, 1, 1, 1)
+		else
+			button.check:SetTexCoord(0, 0.25, 0, 1)
+			button.check:SetVertexColor(1, 1, 1, 0.5)
+		end
+		button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
+		button.check:SetWidth(16)
+		button.check:SetHeight(16)
+	elseif info.icon then
+		button.check:Show()
+		button.check:SetTexture(info.icon)
+		if info.iconWidth and info.iconHeight then
+			button.check:SetWidth(info.iconWidth)
+			button.check:SetHeight(info.iconHeight)
+		else
+			button.check:SetWidth(16)
+			button.check:SetHeight(16)
+		end
+		if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then
+			button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom)
+		elseif info.icon:find("^Interface\\Icons\\") then
+			button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
+		else
+			button.check:SetTexCoord(0, 1, 0, 1)
+		end
+		button.check:SetVertexColor(1, 1, 1, 1)
+	else
+		if button.checked then
+			if info.checkIcon then
+				button.check:SetWidth(16)
+				button.check:SetHeight(16)
+				button.check:SetTexture(info.checkIcon)
+				if info.checkIcon:find("^Interface\\Icons\\") then
+					button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
+				else
+					button.check:SetTexCoord(0, 1, 0, 1)
+				end
+			else
+				button.check:SetWidth(24)
+				button.check:SetHeight(24)
+				button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+				button.check:SetTexCoord(0, 1, 0, 1)
+			end
+			button.check:SetVertexColor(1, 1, 1, 1)
+		else
+			button.check:SetVertexColor(1, 1, 1, 0)
+		end
+	end
+	if not button.disabled then
+		button.func = info.func
+		button.secure = info.secure
+	end
+	button.hasColorSwatch = info.hasColorSwatch
+	if button.hasColorSwatch then
+		button.colorSwatch:Show()
+		button.colorSwatch.texture:Show()
+		button.r = info.r or 1
+		button.g = info.g or 1
+		button.b = info.b or 1
+		button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b)
+		button.checked = false
+		button.func = nil
+		button.colorFunc = info.colorFunc
+		local i = 1
+		while true do
+			local k = "colorArg" .. i
+			local x = info[k]
+			if x == nil then
+				break
+			end
+			button[k] = x
+			i = i + 1
+		end
+		button.hasOpacity = info.hasOpacity
+		button.opacity = info.opacity or 1
+	else
+		button.colorSwatch:Hide()
+		button.colorSwatch.texture:Hide()
+	end
+	button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow
+	if button.hasArrow then
+		button.arrow:SetAlpha(1)
+		if info.hasSlider then
+			button.hasSlider = true
+			button.sliderMin = info.sliderMin or 0
+			button.sliderMax = info.sliderMax or 1
+			button.sliderStep = info.sliderStep or 0
+			button.sliderBigStep = info.sliderBigStep or button.sliderStep
+			if button.sliderBigStep < button.sliderStep then
+				button.sliderBigStep = button.sliderStep
+			end
+			button.sliderIsPercent = info.sliderIsPercent and true or false
+			button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin
+			button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax
+			button.sliderFunc = info.sliderFunc
+			button.sliderValue = info.sliderValue
+			button.fromAceOptions = info.fromAceOptions
+			local i = 1
+			while true do
+				local k = "sliderArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+		elseif info.hasEditBox then
+			button.hasEditBox = true
+			button.editBoxText = info.editBoxText or ""
+			button.editBoxFunc = info.editBoxFunc
+			local i = 1
+			while true do
+				local k = "editBoxArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+			button.editBoxChangeFunc = info.editBoxChangeFunc
+			local i = 1
+			while true do
+				local k = "editBoxChangeArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+			button.editBoxValidateFunc = info.editBoxValidateFunc
+			local i = 1
+			while true do
+				local k = "editBoxValidateArg" .. i
+				local x = info[k]
+				if x == nil then
+					break
+				end
+				button[k] = x
+				i = i + 1
+			end
+			button.editBoxIsKeybinding = info.editBoxIsKeybinding
+			button.editBoxKeybindingOnly = info.editBoxKeybindingOnly
+			button.editBoxKeybindingExcept = info.editBoxKeybindingExcept
+		else
+			button.value = info.value
+			local l = levels[level+1]
+			if l and info.value == l.value then
+--				button.arrow:SetWidth(24)
+--				button.arrow:SetHeight(24)
+				button.selected = true
+				button.highlight:Show()
+			end
+		end
+	else
+		button.arrow:SetAlpha(0)
+	end
+	local i = 1
+	while true do
+		local k = "arg" .. i
+		local x = info[k]
+		if x == nil then
+			break
+		end
+		button[k] = x
+		i = i + 1
+	end
+	button.closeWhenClicked = info.closeWhenClicked
+	button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10
+	local font,_ = button.text:GetFont()
+	button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight)
+	button:SetHeight(button.textHeight + 6)
+	button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT")
+	button.text:SetJustifyH(info.justifyH or "LEFT")
+	button.text:SetText(info.text)
+	button.tooltipTitle = info.tooltipTitle
+	button.tooltipText = info.tooltipText
+	button.tooltipFunc = info.tooltipFunc
+	local i = 1
+	while true do
+		local k = "tooltipArg" .. i
+		local x = info[k]
+		if x == nil then
+			break
+		end
+		button[k] = x
+		i = i + 1
+	end
+	if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then
+		button.tooltipTitle = info.text
+	end
+	if type(button.func) == "string" then
+		if type(button.arg1) ~= "table" then
+			self:error("Cannot call method %q on a non-table", button.func)
+		end
+		if type(button.arg1[button.func]) ~= "function" then
+			self:error("Method %q nonexistant.", button.func)
+		end
+	end
+end
+
+function Dewdrop:InjectAceOptionsTable(handler, options)
+	self:argCheck(handler, 2, "table")
+	self:argCheck(options, 3, "table")
+	if tostring(options.type):lower() ~= "group" then
+		self:error('Cannot inject into options table argument #3 if its type is not "group"')
+	end
+	if options.handler ~= nil and options.handler ~= handler then
+		self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2")
+	end
+	options.handler = handler
+	local class = handler.class
+	if not AceLibrary:HasInstance("AceOO-2.0") or not class then
+		if Rock then
+			-- possible Rock object
+			for mixin in Rock:IterateObjectMixins(handler) do
+				if type(mixin.GetAceOptionsDataTable) == "function" then
+					local t = mixin:GetAceOptionsDataTable(handler)
+					for k,v in pairs(t) do
+						if type(options.args) ~= "table" then
+							options.args = {}
+						end
+						if options.args[k] == nil then
+							options.args[k] = v
+						end
+					end
+				end
+			end
+		end
+	else
+		-- Ace2 object
+		while class and class ~= AceLibrary("AceOO-2.0").Class do
+			if type(class.GetAceOptionsDataTable) == "function" then
+				local t = class:GetAceOptionsDataTable(handler)
+				for k,v in pairs(t) do
+					if type(options.args) ~= "table" then
+						options.args = {}
+					end
+					if options.args[k] == nil then
+						options.args[k] = v
+					end
+				end
+			end
+			local mixins = class.mixins
+			if mixins then
+				for mixin in pairs(mixins) do
+					if type(mixin.GetAceOptionsDataTable) == "function" then
+						local t = mixin:GetAceOptionsDataTable(handler)
+						for k,v in pairs(t) do
+							if type(options.args) ~= "table" then
+								options.args = {}
+							end
+							if options.args[k] == nil then
+								options.args[k] = v
+							end
+						end
+					end
+				end
+			end
+			class = class.super
+		end
+	end
+	return options
+end
+
+function Dewdrop:OnTooltipHide()
+	if lastSetFont then
+		if lastSetFont == normalFont then
+			lastSetFont = nil
+			return
+		end
+		fillRegionTmp(GameTooltip:GetRegions())
+		for i,v in ipairs(regionTmp) do
+			if v.GetFont then
+				local font,size,outline = v:GetFont()
+				if font == lastSetFont then
+					v:SetFont(normalFont, size, outline)
+				end
+			end
+			regionTmp[i] = nil
+		end
+		lastSetFont = nil
+	end
+end
+
+local function activate(self, oldLib, oldDeactivate)
+	Dewdrop = self
+	if oldLib and oldLib.registry then
+		self.registry = oldLib.registry
+		self.onceRegistered = oldLib.onceRegistered
+	else
+		self.registry = {}
+		self.onceRegistered = {}
+
+		local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown")
+		local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp")
+		local oldX, oldY, clickTime
+		WorldFrame:SetScript("OnMouseDown", function(this, ...)
+			oldX,oldY = GetCursorPosition()
+			clickTime = GetTime()
+			if WorldFrame_OnMouseDown then
+				WorldFrame_OnMouseDown(this, ...)
+			end
+		end)
+
+		WorldFrame:SetScript("OnMouseUp", function(this, ...)
+			local x,y = GetCursorPosition()
+			if not oldX or not oldY or not x or not y or not clickTime then
+				self:Close()
+				if WorldFrame_OnMouseUp then
+					WorldFrame_OnMouseUp(this, ...)
+				end
+				return
+			end
+			local d = math.abs(x - oldX) + math.abs(y - oldY)
+			if d <= 5 and GetTime() - clickTime < 0.5 then
+				self:Close()
+			end
+			if WorldFrame_OnMouseUp then
+				WorldFrame_OnMouseUp(this, ...)
+			end
+		end)
+
+		hooksecurefunc(DropDownList1, "Show", function()
+			if levels[1] and levels[1]:IsVisible() then
+				self:Close()
+			end
+		end)
+
+		hooksecurefunc("HideDropDownMenu", function()
+			if levels[1] and levels[1]:IsVisible() then
+				self:Close()
+			end
+		end)
+
+		hooksecurefunc("CloseDropDownMenus", function()
+			if levels[1] and levels[1]:IsVisible() then
+				local stack = debugstack()
+				if not stack:find("`TargetFrame_OnHide'") then
+					self:Close()
+				end
+			end
+		end)
+	end
+	self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
+	self.frame:UnregisterAllEvents()
+	self.frame:RegisterEvent("PLAYER_REGEN_ENABLED")
+	self.frame:RegisterEvent("PLAYER_REGEN_DISABLED")
+	self.frame:Hide()
+	self.frame:SetScript("OnEvent", function(this, event)
+		this:Show()
+		if event=="PLAYER_REGEN_ENABLED" then			-- track combat state for secure frame operations
+			self.combat = false
+		elseif event=="PLAYER_REGEN_DISABLED" then
+			self.combat = true
+		end
+	end)
+	self.frame:SetScript("OnUpdate", function(this)
+		this:Hide()
+		self:Refresh(1)
+	end)
+	self.hookedTooltip = true
+	if not oldLib or not oldLib.hookedTooltip then
+		local OnTooltipHide = GameTooltip:GetScript("OnHide")
+		GameTooltip:SetScript("OnHide", function(this, ...)
+			if OnTooltipHide then
+				OnTooltipHide(this, ...)
+			end
+			if type(self.OnTooltipHide) == "function" then
+				self:OnTooltipHide()
+			end
+		end)
+	end
+	levels = {}
+	buttons = {}
+
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+local function external(lib, major, instance)
+	if major == "SharedMedia-1.0" then
+		SharedMedia = instance
+	end
+end
+
+AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/modules/ReAction_HideBlizzard/ReAction_HideBlizzard.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/ReAction_HideBlizzard/ReAction_HideBlizzard.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -18,12 +18,14 @@
 
 -- module methods
 function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
+  self.db = ReAction.db:RegisterNamespace( moduleID,
     { 
-      hide = false
+      profile = {
+        hide = false
+      }
     }
   )
+  self.db.RegisterCallback(self,"OnProfileChanged")
 
   self.hiddenFrame = CreateFrame("Frame")
   self.hiddenFrame:Hide()
@@ -60,15 +62,14 @@
   self:ShowAll(true)
 end
 
-function module:OnProfileEnable()
+function module:OnProfileChanged()
   if self.db.profile.hide then
-    self:HideAll(true)
+    module:HideAll(true)
   else
-    self:ShowAll(true)
+    module:ShowAll(true)
   end
 end
 
-
 local frames = {
   MainMenuBar,
   PetActionButton1,
--- a/modules/ReAction_ModuleTemplate/ReAction_ModuleName.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/ReAction_ModuleTemplate/ReAction_ModuleName.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -16,12 +16,15 @@
 
 -- module methods
 function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
+  self.db = ReAction.db:RegisterNamespace( moduleID
     {
-
+      profile = {
+        -- default profile goes here
+      }
     }
   )
+
+  end
 end
 
 function module:OnEnable()
@@ -32,11 +35,40 @@
 
 end
 
-function module:OnProfileEnable()
+
+---- ReAction module API ----
+
+-- apply module features and settings to a bar object (see Bar.lua for Bar API)
+function module:ApplyToBar(bar)
 
 end
 
-function module:OnProfileDisable()
+-- remove module features and settings from a bar object
+function module:RemoveFromBar(bar)
 
 end
 
+-- refresh module features and settings on a bar object
+function module:RefreshBar(bar)
+
+end
+
+-- notification of config mode (true/false) on the list of bars
+function module:ApplyConfigMode(mode,listOfBars)
+
+end
+
+-- return a name-modifier (suffix) for the bar name display. This can reflect a dynamic state.
+function module:GetBarNameModifier(bar)
+  return nil
+end
+
+-- erase any local configuration entries for the supplied bar name
+function module:EraseBarConfig(barName)
+
+end
+
+-- update any local configuration entries with the new bar name index
+function module:RenameBarConfig(oldName, newName)
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_PetAction/ReAction_PetAction.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,133 @@
+--[[
+  ReAction Pet Action Bar module
+
+--]]
+
+-- local imports
+local ReAction = ReAction
+local L = ReAction.L
+local _G = _G
+
+-- module declaration
+local moduleID = "PetAction"
+local module = ReAction:NewModule( moduleID )
+
+
+-- module methods
+function module:OnInitialize()
+  self.db = ReAction.db:RegisterNamespace( moduleID, 
+    { 
+      profile = {
+        buttons = { }
+      }
+    }
+  )
+
+  self.buttons = { }
+end
+
+function module:OnEnable()
+end
+
+function module:OnDisable()
+end
+
+function module:GetGlobalBarOptions(opts)  
+  if self.globalBarOpts == nil then
+    self.globalBarOpts = {
+      newActionBar = {
+        type = "execute",
+        name = L["New Pet Action Bar"],
+        desc = L["Create a new bar of pet action buttons"],
+        func = function()
+                 ReAction:CreateBar()
+               end,
+        disabled = InCombatLockdown,
+      }
+    }
+  end
+  return self.globalBarOpts
+end
+
+
+-- use-count of action IDs
+local ActionIDList = setmetatable( {}, {
+  __index = function(self, idx)
+    if idx == nil then
+      for i = 1, 10 do
+        if rawget(self,i) == nil then
+          rawset(self,i,1)
+          return i
+        end
+      end
+    else
+      local c = rawget(self,idx) or 0
+      rawset(self,idx,c+1)
+      return idx
+    end
+  end,
+  __newindex = function(self,idx,value)
+    if value == nil then
+      value = rawget(self,idx)
+      if value == 1 then
+        value = nil
+      elseif value then
+        value = value - 1
+      end
+    end
+    rawset(self,idx,value)
+  end
+})
+
+
+-- button class methods
+local Button = { }
+
+local function Constructor( self, bar, idx, config )
+  self.bar, self.idx, self.config = bar, idx, config
+
+  local barFrame = bar:GetFrame()
+
+  self.name = config.name or "ReAction_"..bar:GetName().."_Pet_"..idx
+  config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured
+  
+  local f = CreateFrame("CheckButton", self.name, barFrame, "PetActionButtonTemplate")
+  f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton (question: is this protected? does it cause taint?)
+  self.frame = f
+  barFrame:SetAttribute("addchild",f)
+
+  -- auto show/hide when pet exists
+  -- this gets called once per button, which is inefficient but otherwise harmless
+  barFrame:SetAttribute("unit","pet")
+  RegisterUnitWatch(barFrame)
+
+  self:Refresh(bar,idx)
+end
+
+function Button:Destroy()
+  local f = self.frame
+  f:UnregisterAllEvents()
+  f:Hide()
+  f:SetParent(UIParent)
+  f:ClearAllPoints()
+  if self.name then
+    _G[self.name] = nil
+  end
+  ActionIDList[self.config.actionID] = nil
+  self.frame = nil
+  self.config = nil
+  self.bar = nil
+end
+
+
+-- export as a class-factory to module
+module.BtnClass = {
+  new = function(self, ...)
+    local x = { }
+    for k,v in pairs(Button) do
+      x[k] = v
+    end
+    Constructor(x, ...)
+    return x
+  end
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_PetAction/ReAction_PetAction.toc	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,11 @@
+## Interface: 20300
+## Title: ReAction: Pet Actions
+## Notes: Pet Action Bar support for ReAction
+## DefaultState: enabled
+## LoadOnDemand: 1
+## Author: Flick
+## Version: 1.0
+## X-Category: Action Bars
+## Dependencies: ReAction
+
+ReAction_PetAction.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/ReAction_PetAction/ReAction_PetAction.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -0,0 +1,7 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" 
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+
+<Script file="ReAction_PetAction.lua"/>
+
+</Ui>
\ No newline at end of file
--- a/modules/ReAction_State/ReAction_State.lua	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/ReAction_State/ReAction_State.lua	Mon Mar 17 18:24:53 2008 +0000
@@ -15,10 +15,9 @@
 
 -- module methods
 function module:OnInitialize()
-  self.db = ReAction:AcquireDBNamespace(moduleID)
-  ReAction:RegisterDefaults(moduleID,"profile", 
+  self.db = ReAction:RegisterNamespace( moduleID, 
     {
-
+      profile = { }
     }
   )
 end
@@ -31,14 +30,6 @@
 
 end
 
-function module:OnProfileEnable()
-
-end
-
-function module:OnProfileDisable()
-
-end
-
 --function module:GetGlobalOptions( configModule )
 --  return {}
 --end
--- a/modules/modules.xml	Tue Mar 11 21:39:34 2008 +0000
+++ b/modules/modules.xml	Mon Mar 17 18:24:53 2008 +0000
@@ -7,9 +7,9 @@
 <Include file="ReAction_HideBlizzard\ReAction_HideBlizzard.xml"/>
 <Include file="FuBar_ReActionFu\FuBar_ReActionFu.xml"/>
 
-<!-- in progress -->
+<!-- in progress
 <Include file="ReAction_PetAction\ReAction_PetAction.xml"/>
-
+-->
 
 <!-- not yet implemented
 <Include file="ReAction_State\ReAction_State.xml"/>