changeset 33:c54c481ad0ed

- Moved bar control frame from ConfigUI to Bar - Added LICENSE.txt - added profile management options - other minor cleanup
author Flick <flickerstreak@gmail.com>
date Thu, 03 Apr 2008 20:25:40 +0000
parents 821b2b7edff1
children b5ae1bae02ff
files Bar.lua LICENSE.txt ReAction.lua ReAction.toc lib/AceLibrary/AceLibrary.lua lib/AceLibrary/AceLibrary.toc lib/Dewdrop-2.0/Dewdrop-2.0.lua lib/embeds.xml modules/ReAction_ConfigUI/ReAction_ConfigUI.lua 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_ConfigUI/lib/embeds.xml
diffstat 15 files changed, 4862 insertions(+), 5679 deletions(-) [+]
line wrap: on
line diff
--- a/Bar.lua	Thu Apr 03 16:59:16 2008 +0000
+++ b/Bar.lua	Thu Apr 03 20:25:40 2008 +0000
@@ -2,9 +2,16 @@
 local L = ReAction.L
 local _G = _G
 local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local floor = math.floor
+local min = math.min
+local format = string.format
+local GameTooltip = GameTooltip
+
+
 
 -- update ReAction revision if this file is newer
-local revision = tonumber(("$Revision: 1 $"):match("%d+"))
+local revision = tonumber(("$Revision$"):match("%d+"))
 if revision > ReAction.revision then
   Reaction.revision = revision
 end
@@ -112,6 +119,13 @@
   return self.name
 end
 
+function Bar:SetName(name)
+  self.name = name
+  if self.controlLabelString then
+    self.controlLabelString:SetText(self.name)
+  end
+end
+
 function Bar:PlaceButton(f, idx, baseW, baseH)
   local r, c, s = self:GetButtonGrid()
   local bh, bw = self:GetButtonSize()
@@ -127,6 +141,378 @@
 
 
 
+
+
+
+
+--
+-- Bar config overlay
+--
+local StoreExtents, RecomputeButtonSize, RecomputeButtonSpacing, RecomputeGrid, ClampToButtons, HideGameTooltip, CreateControls
+
+do
+  -- upvalue some of these for small OnUpdate performance boost
+  local GetSize       = Bar.GetSize
+  local GetButtonSize = Bar.GetButtonSize
+  local GetButtonGrid = Bar.GetButtonGrid
+  local SetSize       = Bar.SetSize
+  local SetButtonSize = Bar.SetButtonSize
+  local SetButtonGrid = Bar.SetButtonGrid
+  local ApplyAnchor   = Bar.ApplyAnchor
+
+  StoreExtents = function(bar)
+    local f = bar.frame
+    local point, relativeTo, relativePoint, x, y = f:GetPoint(1)
+    relativeTo = relativeTo or f:GetParent()
+    local anchorTo
+    for name, b in pairs(ReAction.bars) do
+      if b then
+        if b:GetFrame() == relativeTo then
+          anchorTo = name
+          break
+        end
+      end
+    end
+    anchorTo = anchorTo or relativeTo:GetName()
+    local c = bar.config
+    c.anchor = point
+    c.anchorTo = anchorTo
+    c.relativePoint = relativePoint
+    c.x = x
+    c.y = y
+    c.width, c.height = f:GetWidth(), f:GetHeight()
+  end
+
+  RecomputeButtonSize = function(bar)
+    local w, h = GetSize(bar)
+    local bw, bh = GetButtonSize(bar)
+    local r, c, s = GetButtonGrid(bar)
+
+    local scaleW = (floor(w/c) - s) / bw
+    local scaleH = (floor(h/r) - s) / bh
+    local scale = min(scaleW, scaleH)
+
+    SetButtonSize(bar, scale * bw, scale * bh, s)
+  end
+
+  RecomputeButtonSpacing = function(bar)
+    local w, h = GetSize(bar)
+    local bw, bh = GetButtonSize(bar)
+    local r, c, s = GetButtonGrid(bar)
+
+    SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh))
+  end
+
+  RecomputeGrid = function(bar)
+    local w, h = GetSize(bar)
+    local bw, bh = GetButtonSize(bar)
+    local r, c, s = GetButtonGrid(bar)
+
+    SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s)
+  end
+
+  ClampToButtons = function(bar)
+    local bw, bh = GetButtonSize(bar)
+    local r, c, s = GetButtonGrid(bar)
+    SetSize(bar, (bw+s)*c, (bh+s)*r )
+  end
+
+  HideGameTooltip = function()
+    GameTooltip:Hide()
+  end
+
+  CreateControls = function(bar)
+    local f = bar.frame
+
+    f:SetMovable(true)
+    f:SetResizable(true)
+    f:SetClampedToScreen(true)
+
+    -- buttons on the bar should be direct children of the bar frame.
+    -- The control elements need to float on top of this, which we could
+    -- do with SetFrameLevel() or Raise(), but it's more reliable to do it
+    -- via frame nesting, hence good old foo's appearance here.
+    local foo = CreateFrame("Frame",nil,f)
+    foo:SetAllPoints()
+
+    local control = CreateFrame("Button", nil, foo)
+    control:EnableMouse(true)
+    control:SetToplevel(true)
+    control:SetPoint("TOPLEFT", -4, 4)
+    control:SetPoint("BOTTOMRIGHT", 4, -4)
+    control:SetBackdrop({
+      edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+      tile = true,
+      tileSize = 16,
+      edgeSize = 16,
+      insets = { left = 0, right = 0, top = 0, bottom = 0 },
+    })
+
+    -- textures
+    local bgTex = control:CreateTexture(nil,"BACKGROUND")
+    bgTex:SetTexture(0.7,0.7,1.0,0.2)
+    bgTex:SetPoint("TOPLEFT",4,-4)
+    bgTex:SetPoint("BOTTOMRIGHT",-4,4)
+    local hTex = control:CreateTexture(nil,"HIGHLIGHT")
+    hTex:SetTexture(0.7,0.7,1.0,0.2)
+    hTex:SetPoint("TOPLEFT",4,-4)
+    hTex:SetPoint("BOTTOMRIGHT",-4,4)
+    hTex:SetBlendMode("ADD")
+
+    -- label
+    local label = control:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+    label:SetAllPoints()
+    label:SetJustifyH("CENTER")
+    label:SetShadowColor(0,0,0,1)
+    label:SetShadowOffset(2,-2)
+    label:SetTextColor(1,1,1,1)
+    label:SetText(bar:GetName())
+    label:Show()
+    bar.controlLabelString = label  -- so that bar:SetName() can update it
+
+    local StopResize = function()
+      f:StopMovingOrSizing()
+      f.isMoving = false
+      f:SetScript("OnUpdate",nil)
+      StoreExtents(bar)
+      ClampToButtons(bar)
+      ApplyAnchor(bar)
+    end
+
+    -- edge drag handles
+    for _, point in pairs({"LEFT","TOP","RIGHT","BOTTOM"}) do
+      local edge = CreateFrame("Frame",nil,control)
+      edge:EnableMouse(true)
+      edge:SetWidth(8)
+      edge:SetHeight(8)
+      if point == "TOP" or point == "BOTTOM" then
+        edge:SetPoint(point.."LEFT")
+        edge:SetPoint(point.."RIGHT")
+      else
+        edge:SetPoint("TOP"..point)
+        edge:SetPoint("BOTTOM"..point)
+      end
+      local tex = edge:CreateTexture(nil,"HIGHLIGHT")
+      tex:SetTexture(1.0,0.82,0,0.7)
+      tex:SetBlendMode("ADD")
+      tex:SetAllPoints()
+      edge:RegisterForDrag("LeftButton")
+      edge:SetScript("OnMouseDown",
+        function()
+          local bw, bh = GetButtonSize(bar)
+          local r, c, s = GetButtonGrid(bar)
+          f:SetMinResize( bw+s+1, bh+s+1 )
+          f:StartSizing(point)
+          f:SetScript("OnUpdate", 
+            function()
+              RecomputeGrid(bar)
+              bar:RefreshLayout()
+            end
+          )
+        end
+      )
+      edge:SetScript("OnMouseUp", StopResize)
+      edge:SetScript("OnEnter",
+        function()
+          GameTooltip:SetOwner(f, "ANCHOR_"..point)
+          GameTooltip:AddLine(L["Drag to add/remove buttons"])
+          GameTooltip:Show()
+        end
+      )
+      edge:SetScript("OnLeave", HideGameTooltip)
+      edge:Show()
+    end
+
+    -- corner drag handles, again nested in an anonymous frame so that they are on top
+    local foo2 = CreateFrame("Frame",nil,control)
+    foo2:SetAllPoints(true)
+    for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do
+      local corner = CreateFrame("Frame",nil,foo2)
+      corner:EnableMouse(true)
+      corner:SetWidth(12)
+      corner:SetHeight(12)
+      corner:SetPoint(point)
+      local tex = corner:CreateTexture(nil,"HIGHLIGHT")
+      tex:SetTexture(1.0,0.82,0,0.7)
+      tex:SetBlendMode("ADD")
+      tex:SetAllPoints()
+      corner:RegisterForDrag("LeftButton","RightButton")
+      local updateTooltip = function()
+        local size, size2 = bar:GetButtonSize()
+        local rows, cols, spacing = bar:GetButtonGrid()
+        size = (size == size2) and tostring(size) or format("%dx%d",size,size2)
+        GameTooltipTextRight4:SetText(size)
+        GameTooltipTextRight5:SetText(tostring(spacing))
+      end
+      corner:SetScript("OnMouseDown",
+        function(_,btn)
+          local bw, bh = GetButtonSize(bar)
+          local r, c, s = GetButtonGrid(bar)
+          if btn == "LeftButton" then -- button resize
+            f:SetMinResize( (s+12)*c+1, (s+12)*r+1 )
+            f:SetScript("OnUpdate", 
+              function()
+                RecomputeButtonSize(bar)
+                bar:RefreshLayout()
+                updateTooltip()
+              end
+            )
+          elseif btn == "RightButton" then -- spacing resize
+            f:SetMinResize( bw*c, bh*r )
+            f:SetScript("OnUpdate", 
+              function()
+                RecomputeButtonSpacing(bar)
+                bar:RefreshLayout()
+                updateTooltip()
+              end
+            )
+          end
+          f:StartSizing(point)
+        end
+      )
+      corner:SetScript("OnMouseUp",StopResize)
+      corner:SetScript("OnEnter",
+        function()
+          GameTooltip:SetOwner(f, "ANCHOR_"..point)
+          GameTooltip:AddLine(L["Drag to resize buttons"])
+          GameTooltip:AddLine(L["Right-click-drag"])
+          GameTooltip:AddLine(L["to change spacing"])
+          local size, size2 = bar:GetButtonSize()
+          local rows, cols, spacing = bar:GetButtonGrid()
+          size = (size == size2) and tostring(size) or format("%dx%d",size,size2)
+          GameTooltip:AddDoubleLine(L["Size:"], size)
+          GameTooltip:AddDoubleLine(L["Spacing:"], tostring(spacing))
+          GameTooltip:Show()
+        end
+      )
+      corner:SetScript("OnLeave", 
+        function()
+          GameTooltip:Hide()
+          f:SetScript("OnUpdate",nil)
+        end
+      )
+
+    end
+
+    control:RegisterForDrag("LeftButton")
+    control:RegisterForClicks("RightButtonDown")
+    
+    control:SetScript("OnDragStart",
+      function()
+        f:StartMoving()
+        f.isMoving = true
+        -- TODO: snap indicator update install
+      end
+    )
+
+    control:SetScript("OnDragStop",
+      function()
+        f:StopMovingOrSizing()
+        f.isMoving = false
+        f:SetScript("OnUpdate",nil)
+        -- TODO: snap frame here
+        StoreExtents(bar)
+      end
+    )
+
+    control:SetScript("OnEnter",
+      function()
+        -- add bar type and status information to name
+        local name = bar.name
+        for _, m in ReAction:IterateModules() do
+          --[[
+          local suffix = safecall(m,"GetBarNameModifier",bar)
+          if suffix then
+            name = ("%s %s"):format(name,suffix)
+          end
+          --]]
+        end
+        
+        GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
+        GameTooltip:AddLine(name)
+        GameTooltip:AddLine(L["Drag to move"])
+        --GameTooltip:AddLine(L["Shift-drag for sticky mode"])
+        GameTooltip:AddLine(L["Right-click for options"])
+        GameTooltip:Show()
+      end
+    )
+
+    control:SetScript("OnLeave", HideGameTooltip)
+
+    control:SetScript("OnClick",
+      function()
+        bar:ShowMenu()
+      end
+    )
+
+    return control
+  end
+end
+
+
+local OpenMenu, CloseMenu
+do
+  -- Looking for a lightweight AceConfig3-struct-compatible 
+  -- replacement for Dewdrop, encapsulate here
+  -- Considering Blizzard's EasyMenu/UIDropDownMenu, but that's
+  -- a bit tricky to convert from AceConfig3-struct
+  local Dewdrop = AceLibrary("Dewdrop-2.0")
+  OpenMenu = function(frame, opts)
+    Dewdrop:Open(frame, "children", opts, "cursorX", true, "cursorY", true)
+  end
+  CloseMenu = function(frame)
+    if Dewdrop:GetOpenedParent() == frame then
+      Dewdrop:Close()
+    end
+  end
+end
+
+
+function Bar:ShowControls(show)
+  if show then
+    if not self.controlFrame then
+      self.controlFrame = CreateControls(self)
+    end
+    self.controlFrame:Show()
+  elseif self.controlFrame then
+    CloseMenu(self.controlFrame)
+    self.controlFrame:Hide()
+  end
+end
+
+function Bar:ShowMenu()
+  if not self.menuOpts then
+    self.menuOpts = {
+      type = "group",
+      args = {
+        --[[
+        openConfig = {
+          type = "execute",
+          name = L["Configure..."],
+          desc = L["Open the configuration dialogue for this bar"],
+          func = function() CloseMenu(self.controlFrame); 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
+  OpenMenu(self.controlFrame, self.menuOpts)
+end
+
+
+
 ------ Export as a class-factory ------
 ReAction.Bar = {
   prototype = Bar,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE.txt	Thu Apr 03 20:25:40 2008 +0000
@@ -0,0 +1,59 @@
+Copyright (c) 2008 Ryan Findley
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+
+
+This distribution includes source code provided by
+Ace3 Development Team, license of which is reproduced below:
+
+-------------------------------------------
+
+Copyright (c) 2007, Ace3 Development Team 
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+      this list of conditions and the following disclaimer in the documentation 
+      and/or other materials provided with the distribution.
+    * Redistribution of a stand alone version is strictly prohibited without 
+      prior written authorization from the Lead of the Ace3 Development Team. 
+    * Neither the name of the Ace3 Development Team nor the names of its contributors 
+      may be used to endorse or promote products derived from this software without 
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------
\ No newline at end of file
--- a/ReAction.lua	Thu Apr 03 16:59:16 2008 +0000
+++ b/ReAction.lua	Thu Apr 03 20:25:40 2008 +0000
@@ -1,18 +1,14 @@
 -- ReAction.lua
 -- See modules/ReAction_ModuleTemplate for Module API listing
 -- See Bar.lua for Bar object listing
-local MAJOR_VERSION = GetAddOnMetadata("ReAction","Version")
-
------- LIBRARIES ------
-local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
 
 ------ CORE ------
 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
-  "AceConsole-3.0"
+  "AceConsole-3.0",
+  "AceEvent-3.0"
 )
-ReAction.revision = tonumber(("$Revision: 1 $"):match("%d+"))
-ReAction.version = MAJOR_VERSION
-ReAction.L = L
+ReAction.version = GetAddOnMetadata("ReAction","Version")
+ReAction.revision = tonumber(("$Revision$"):match("%d+"))
 
 ------ GLOBALS ------
 _G["ReAction"] = ReAction
@@ -28,6 +24,10 @@
   ReAction.print = function() end
 end
 
+------ LIBRARIES ------
+local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
+ReAction.L = L
+
 ------ PRIVATE ------
 local SelectBar, DestroyBar, InitializeBars, TearDownBars, DeepCopy, SafeCall, CheckMethod, SlashHandler
 do
@@ -112,25 +112,25 @@
   end
 
   local function CallOptsModule(method,...)
-   local m = ReAction:GetModule("ConfigUI",true)
-   if not m then
-     LoadAddOn("ReAction_ConfigUI")
-     m = ReAction:GetModule("ConfigUI")
-   end
-   if m and type(m) == "table" and type(m[method]) == "function" then
-     m[method](m,...)
-   else
-     ReAction:Print("Options module not found")
-   end
+    local m = ReAction:GetModule("ConfigUI",true)
+    if not m then
+      LoadAddOn("ReAction_ConfigUI")
+      m = ReAction:GetModule("ConfigUI")
+    end
+    if m and type(m) == "table" and type(m[method]) == "function" then
+      m[method](m,...)
+    else
+      ReAction:Print("Options module not found")
+    end
   end
 
   SlashHandler = function(option)
     if option == "config" then
       CallOptsModule("OpenConfig",true)
     elseif option == "unlock" then
-      CallOptsModule("SetConfigMode",true)
+      ReAction:SetConfigMode(true)
     elseif option == "lock" then
-      CallOptsModule("SetConfigMode",false)
+      ReAction:SetConfigMode(false)
     else
       ReAction:Print(ReAction.version)
       ReAction:Print("/reaction config")
@@ -156,6 +156,7 @@
   self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
   self:RegisterChatCommand("reaction", SlashHandler)
   self:RegisterChatCommand("rxn", SlashHandler)
+  self:RegisterEvent("PLAYER_REGEN_DISABLED")
 
   self.bars = {}
 end
@@ -169,8 +170,8 @@
 end
 
 function ReAction:OnProfileChanged()
-  self.TearDownBars()
-  self.InitializeBars()
+  TearDownBars()
+  InitializeBars()
 end
 
 function ReAction:OnModuleEnable(module)
@@ -193,6 +194,14 @@
   end
 end
 
+function ReAction:PLAYER_REGEN_DISABLED()
+  if self.configMode == true then
+    UIErrorsFrame:AddMessage(L["ReAction config mode disabled during combat."])
+    self:SetConfigMode(false)
+  end
+end
+
+
 
 ------ API ------
 function ReAction:CallMethodOnAllModules(method, ...)
@@ -229,6 +238,10 @@
   self:CallMethodOnAllModules("ApplyToBar", bar)
   self.bars[name] = bar
   self.callbacks:Fire("OnCreateBar", bar)
+  if self.configMode then
+    bar:ShowControls(true)
+  end
+
   return bar
 end
 
@@ -295,3 +308,9 @@
 function ReAction:RefreshOptions()
   self.callbacks:Fire("OnOptionsRefreshed")
 end
+
+function ReAction:SetConfigMode( mode )
+  self:CallMethodOnAllBars("ShowControls",mode)
+  self:CallMethodOnAllModules("ApplyConfigMode",mode,self.bars)
+  self.configMode = mode
+end
--- a/ReAction.toc	Thu Apr 03 16:59:16 2008 +0000
+++ b/ReAction.toc	Thu Apr 03 20:25:40 2008 +0000
@@ -7,5 +7,6 @@
 ## Version: 1.0
 ## SavedVariables: ReAction_DB
 ## X-Category: Action Bars
+## X-License: MIT
 
 ReAction.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/AceLibrary/AceLibrary.lua	Thu Apr 03 20:25:40 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/lib/AceLibrary/AceLibrary.toc	Thu Apr 03 20:25:40 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/lib/Dewdrop-2.0/Dewdrop-2.0.lua	Thu Apr 03 20:25:40 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/lib/embeds.xml	Thu Apr 03 16:59:16 2008 +0000
+++ b/lib/embeds.xml	Thu Apr 03 20:25:40 2008 +0000
@@ -7,8 +7,11 @@
   <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="AceDBOptions-3.0\AceDBOptions-3.0.xml"/>
   <Include file="AceConsole-3.0\AceConsole-3.0.xml"/>
   <Include file="AceEvent-3.0\AceEvent-3.0.xml"/>
 
+  <!-- for now -->
+  <Script file="AceLibrary\AceLibrary.lua"/>
+  <Script file="Dewdrop-2.0\Dewdrop-2.0.lua"/>
+
 </Ui>
--- a/modules/ReAction_ConfigUI/ReAction_ConfigUI.lua	Thu Apr 03 16:59:16 2008 +0000
+++ b/modules/ReAction_ConfigUI/ReAction_ConfigUI.lua	Thu Apr 03 20:25:40 2008 +0000
@@ -1,38 +1,18 @@
 --[[
   ReAction Configuration UI module
 
-  This modules creates and manages ReAction configuration
-  elements, including:
-
-   - Interface Options panel
-   - bar dragging and resizing control overlays
-   - contextual menus
-
-  Individual modules are responsible for populating these
-  configuration elements via ReAction:RegisterOptions(). The
-  valid values of 'context' are:
-  
-   - 'global'  : added to the Global Settings tab
-   - 'module'  : added to the Module Settings tab
-   - 'bar'     : added to the Bar Settings tab
-   - 'barMenu' : shown on the bar contextual menu
-
+  Hooks into Blizzard Interface Options AddOns panel
 --]]
 
 -- local imports
 local ReAction = ReAction
 local L = ReAction.L
-local _G = _G
-local InCombatLockdown = InCombatLockdown
-
-local Dewdrop = AceLibrary("Dewdrop-2.0")
 
 -- module declaration
 local moduleID = "ConfigUI"
-local module = ReAction:NewModule( moduleID,
-  "AceEvent-3.0"
-)
+local module = ReAction:NewModule( moduleID )
 
+-- options table basic layer
 module.configOptions = {
   type = "group",
   childGroups = "tab",
@@ -94,19 +74,20 @@
       profile = { }
     }
   )
-  self:InitializeOptions()
-  LibStub("AceConfig-3.0"):RegisterOptionsTable("ReAction",self.configOptions)
-  LibStub("AceConfigDialog-3.0"):AddToBlizOptions("ReAction", "ReAction")
-  self:RegisterEvent("PLAYER_REGEN_DISABLED")
-end
 
-function module:InitializeOptions()
   for _, m in pairs(ReAction:GetOptions("global")) do
     for k, v in pairs(m) do
       self.configOptions.args.global.args[k] = v
     end
   end
+
+  self.configOptions.args.profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(ReAction.db)
+  self.configOptions.args.profile.order = -2
+
+  LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("ReAction",self.configOptions)
+  LibStub("AceConfigDialog-3.0"):AddToBlizOptions("ReAction", "ReAction")
   ReAction.RegisterCallback(self,"OnOptionsRegistered")
+  ReAction.RegisterCallback(self,"OnOptionsRefreshed")
 end
 
 function module:OnOptionsRegistered(evt, context, module, opts)
@@ -125,420 +106,13 @@
   end
 end
 
-function module:PLAYER_REGEN_DISABLED()
-  if self.configMode == true then
-    UIErrorsFrame:AddMessage(L["ReAction config mode disabled during combat."])
-    self:SetConfigMode(false)
-  end
-end
-
-function module:SetConfigMode( mode )
-  ReAction:CallMethodOnAllBars("ShowControls",mode)
-  ReAction:CallMethodOnAllModules("ApplyConfigMode",mode,ReAction.bars)
-  self.configMode = mode
-end
-
-function module:ApplyConfigMode( mode, bars )
-  if not(mode) then
-    -- close open dewdrop menu
-    local p = Dewdrop:GetOpenedParent()
-    if p then
-      for _, bar in pairs(bars) do
-        if bar then
-          if p == bar.controlFrame then
-            Dewdrop:Close()
-          end
-        end
-      end
-    end
-  end
-end
-
-local function safecall(module, method, ...)
-  if module and type(module[method]) == "function" then
-    return module[method](method, ...)
-  end
+function module:OnOptionsRefreshed(evt)
+  -- TODO: refresh options frame (just OpenConfig again?)
 end
 
 function module:OpenConfig(bar)
-  Dewdrop:Close()
   InterfaceOptionsFrame_OpenToFrame("ReAction")
-end
-
-function module:ApplyToBar(bar)
-  if self.configMode then
-    bar:ShowControls(self.configMode)
+  if bar then
+    -- TODO: select the correct bar pane
   end
 end
-
-function module:RemoveFromBar(bar)
-  if bar.controlFrame then
-    bar.controlFrame:SetParent(UIParent)
-    bar.controlFrame:ClearAllPoints()
-    bar.controlFrame:Hide()
-    bar.controlFrame = nil
-  end
-end
-
-
-
-
-
---
--- Bar config overlay
---
--- import some of these for small OnUpdate performance boost
-local Bar           = ReAction.Bar.prototype
-local GetSize       = Bar.GetSize
-local GetButtonSize = Bar.GetButtonSize
-local GetButtonGrid = Bar.GetButtonGrid
-local SetSize       = Bar.SetSize
-local SetButtonSize = Bar.SetButtonSize
-local SetButtonGrid = Bar.SetButtonGrid
-local ApplyAnchor   = Bar.ApplyAnchor
-local floor         = math.floor
-local min           = math.min
-local format        = string.format
-local GameTooltip   = GameTooltip
-
-local function StoreExtents(bar)
-  local f = bar.frame
-  local point, relativeTo, relativePoint, x, y = f:GetPoint(1)
-  relativeTo = relativeTo or f:GetParent()
-  local anchorTo
-  for name, b in pairs(ReAction.bars) do
-    if b then
-      if b:GetFrame() == relativeTo then
-        anchorTo = name
-        break
-      end
-    end
-  end
-  anchorTo = anchorTo or relativeTo:GetName()
-  local c = bar.config
-  c.anchor = point
-  c.anchorTo = anchorTo
-  c.relativePoint = relativePoint
-  c.x = x
-  c.y = y
-  c.width, c.height = f:GetWidth(), f:GetHeight()
-end
-
-local function RecomputeButtonSize(bar)
-  local w, h = GetSize(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  local scaleW = (floor(w/c) - s) / bw
-  local scaleH = (floor(h/r) - s) / bh
-  local scale = min(scaleW, scaleH)
-
-  SetButtonSize(bar, scale * bw, scale * bh, s)
-end
-
-local function RecomputeButtonSpacing(bar)
-  local w, h = GetSize(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh))
-end
-
-local function RecomputeGrid(bar)
-  local w, h = GetSize(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s)
-end
-
-local function ClampToButtons(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-  SetSize(bar, (bw+s)*c, (bh+s)*r )
-end
-
-local function HideGameTooltip()
-  GameTooltip:Hide()
-end
-
-local function CreateControls(bar)
-  local f = bar.frame
-
-  f:SetMovable(true)
-  f:SetResizable(true)
-  f:SetClampedToScreen(true)
-
-  -- buttons on the bar should be direct children of the bar frame.
-  -- The control elements need to float on top of this, which we could
-  -- do with SetFrameLevel() or Raise(), but it's more reliable to do it
-  -- via frame nesting, hence good old foo's appearance here.
-  local foo = CreateFrame("Frame",nil,f)
-  foo:SetAllPoints()
-
-  local control = CreateFrame("Button", nil, foo)
-  control:EnableMouse(true)
-  control:SetToplevel(true)
-  control:SetPoint("TOPLEFT", -4, 4)
-  control:SetPoint("BOTTOMRIGHT", 4, -4)
-  control:SetBackdrop({
-    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
-    tile = true,
-    tileSize = 16,
-    edgeSize = 16,
-    insets = { left = 0, right = 0, top = 0, bottom = 0 },
-  })
-
-  -- textures
-  local bgTex = control:CreateTexture(nil,"BACKGROUND")
-  bgTex:SetTexture(0.7,0.7,1.0,0.2)
-  bgTex:SetPoint("TOPLEFT",4,-4)
-  bgTex:SetPoint("BOTTOMRIGHT",-4,4)
-  local hTex = control:CreateTexture(nil,"HIGHLIGHT")
-  hTex:SetTexture(0.7,0.7,1.0,0.2)
-  hTex:SetPoint("TOPLEFT",4,-4)
-  hTex:SetPoint("BOTTOMRIGHT",-4,4)
-  hTex:SetBlendMode("ADD")
-
-  -- label
-  local label = control:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
-  label:SetAllPoints()
-  label:SetJustifyH("CENTER")
-  label:SetShadowColor(0,0,0,1)
-  label:SetShadowOffset(2,-2)
-  label:SetTextColor(1,1,1,1)
-  label:SetText(bar:GetName())
-  label:Show()
-  bar.controlLabelString = label  -- so that bar:SetName() can update it
-
-  local StopResize = function()
-    f:StopMovingOrSizing()
-    f.isMoving = false
-    f:SetScript("OnUpdate",nil)
-    StoreExtents(bar)
-    ClampToButtons(bar)
-    ApplyAnchor(bar)
-  end
-
-  -- edge drag handles
-  for _, point in pairs({"LEFT","TOP","RIGHT","BOTTOM"}) do
-    local edge = CreateFrame("Frame",nil,control)
-    edge:EnableMouse(true)
-    edge:SetWidth(8)
-    edge:SetHeight(8)
-    if point == "TOP" or point == "BOTTOM" then
-      edge:SetPoint(point.."LEFT")
-      edge:SetPoint(point.."RIGHT")
-    else
-      edge:SetPoint("TOP"..point)
-      edge:SetPoint("BOTTOM"..point)
-    end
-    local tex = edge:CreateTexture(nil,"HIGHLIGHT")
-    tex:SetTexture(1.0,0.82,0,0.7)
-    tex:SetBlendMode("ADD")
-    tex:SetAllPoints()
-    edge:RegisterForDrag("LeftButton")
-    edge:SetScript("OnMouseDown",
-      function()
-        local bw, bh = GetButtonSize(bar)
-        local r, c, s = GetButtonGrid(bar)
-        f:SetMinResize( bw+s+1, bh+s+1 )
-        f:StartSizing(point)
-        f:SetScript("OnUpdate", 
-          function()
-            RecomputeGrid(bar)
-            bar:RefreshLayout()
-          end
-        )
-      end
-    )
-    edge:SetScript("OnMouseUp", StopResize)
-    edge:SetScript("OnEnter",
-      function()
-        GameTooltip:SetOwner(f, "ANCHOR_"..point)
-        GameTooltip:AddLine(L["Drag to add/remove buttons"])
-        GameTooltip:Show()
-      end
-    )
-    edge:SetScript("OnLeave", HideGameTooltip)
-    edge:Show()
-  end
-
-  -- corner drag handles, again nested in an anonymous frame so that they are on top
-  local foo2 = CreateFrame("Frame",nil,control)
-  foo2:SetAllPoints(true)
-  for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do
-    local corner = CreateFrame("Frame",nil,foo2)
-    corner:EnableMouse(true)
-    corner:SetWidth(12)
-    corner:SetHeight(12)
-    corner:SetPoint(point)
-    local tex = corner:CreateTexture(nil,"HIGHLIGHT")
-    tex:SetTexture(1.0,0.82,0,0.7)
-    tex:SetBlendMode("ADD")
-    tex:SetAllPoints()
-    corner:RegisterForDrag("LeftButton","RightButton")
-    local updateTooltip = function()
-      local size, size2 = bar:GetButtonSize()
-      local rows, cols, spacing = bar:GetButtonGrid()
-      size = (size == size2) and tostring(size) or format("%dx%d",size,size2)
-      GameTooltipTextRight4:SetText(size)
-      GameTooltipTextRight5:SetText(tostring(spacing))
-    end
-    corner:SetScript("OnMouseDown",
-      function(_,btn)
-        local bw, bh = GetButtonSize(bar)
-        local r, c, s = GetButtonGrid(bar)
-        if btn == "LeftButton" then -- button resize
-          f:SetMinResize( (s+12)*c+1, (s+12)*r+1 )
-          f:SetScript("OnUpdate", 
-            function()
-              RecomputeButtonSize(bar)
-              bar:RefreshLayout()
-              updateTooltip()
-            end
-          )
-        elseif btn == "RightButton" then -- spacing resize
-          f:SetMinResize( bw*c, bh*r )
-          f:SetScript("OnUpdate", 
-            function()
-              RecomputeButtonSpacing(bar)
-              bar:RefreshLayout()
-              updateTooltip()
-            end
-          )
-        end
-        f:StartSizing(point)
-      end
-    )
-    corner:SetScript("OnMouseUp",StopResize)
-    corner:SetScript("OnEnter",
-      function()
-        GameTooltip:SetOwner(f, "ANCHOR_"..point)
-        GameTooltip:AddLine(L["Drag to resize buttons"])
-        GameTooltip:AddLine(L["Right-click-drag"])
-        GameTooltip:AddLine(L["to change spacing"])
-        local size, size2 = bar:GetButtonSize()
-        local rows, cols, spacing = bar:GetButtonGrid()
-        size = (size == size2) and tostring(size) or format("%dx%d",size,size2)
-        GameTooltip:AddDoubleLine(L["Size:"], size)
-        GameTooltip:AddDoubleLine(L["Spacing:"], tostring(spacing))
-        GameTooltip:Show()
-      end
-    )
-    corner:SetScript("OnLeave", 
-      function()
-        GameTooltip:Hide()
-        f:SetScript("OnUpdate",nil)
-      end
-    )
-
-  end
-
-  control:RegisterForDrag("LeftButton")
-  control:RegisterForClicks("RightButtonDown")
-  
-  control:SetScript("OnDragStart",
-    function()
-      f:StartMoving()
-      f.isMoving = true
-      -- TODO: snap indicator update install
-    end
-  )
-
-  control:SetScript("OnDragStop",
-    function()
-      f:StopMovingOrSizing()
-      f.isMoving = false
-      f:SetScript("OnUpdate",nil)
-      -- TODO: snap frame here
-      StoreExtents(bar)
-    end
-  )
-
-  control:SetScript("OnEnter",
-    function()
-      -- add bar type and status information to name
-      local name = bar.name
-      for _, m in ReAction:IterateModules() do
-        local suffix = safecall(m,"GetBarNameModifier",bar)
-        if suffix then
-          name = ("%s %s"):format(name,suffix)
-        end
-      end
-      
-      GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
-      GameTooltip:AddLine(name)
-      GameTooltip:AddLine(L["Drag to move"])
-      --GameTooltip:AddLine(L["Shift-drag for sticky mode"])
-      GameTooltip:AddLine(L["Right-click for options"])
-      GameTooltip:Show()
-    end
-  )
-
-  control:SetScript("OnLeave", HideGameTooltip)
-
-  control:SetScript("OnClick",
-    function()
-      bar:ShowMenu()
-    end
-  )
-
-  return control
-end
-
-function Bar:ShowControls(show)
-  if show then
-    if not self.controlFrame then
-      self.controlFrame = CreateControls(self)
-    end
-    self.controlFrame:Show()
-  elseif self.controlFrame then
-    self.controlFrame:Hide()
-  end
-end
-
-function Bar:ShowMenu()
-  if not self.menuOpts then
-    self.menuOpts = {
-      type = "group",
-      args = {
-        openConfig = {
-          type = "execute",
-          name = L["Configure..."],
-          desc = L["Open the configuration dialogue for this bar"],
-          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: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)
-end
-
-local Bar_SuperSetName = Bar.SetName
-function Bar:SetName(name)
-  Bar_SuperSetName(self,name)  
-  if self.controlLabelString then
-    self.controlLabelString:SetText(self.name)
-  end
-end
--- a/modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.lua	Thu Apr 03 16:59:16 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/modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.toc	Thu Apr 03 16:59:16 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/modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.lua	Thu Apr 03 16:59:16 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/modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.toc	Thu Apr 03 16:59:16 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
--- a/modules/ReAction_ConfigUI/lib/Dewdrop-2.0/Dewdrop-2.0.lua	Thu Apr 03 16:59:16 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)
--- a/modules/ReAction_ConfigUI/lib/embeds.xml	Thu Apr 03 16:59:16 2008 +0000
+++ b/modules/ReAction_ConfigUI/lib/embeds.xml	Thu Apr 03 20:25:40 2008 +0000
@@ -2,13 +2,10 @@
     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="Waterfall-1.0\Waterfall-1.0.lua"/>
-  <Script file="Dewdrop-2.0\Dewdrop-2.0.lua"/>
-
   <Include file="AceGUI-3.0\AceGUI-3.0.xml"/>
-  <Include file="AceConfig-3.0\AceConfig-3.0.xml"/>
+  <Include file="AceConfigRegistry-3.0\AceConfigRegistry-3.0.xml"/>
+  <Include file="AceConfigDialog-3.0\AceConfigDialog-3.0.xml"/>
+  <Include file="AceDBOptions-3.0\AceDBOptions-3.0.xml"/>
 
 </Ui>
  
\ No newline at end of file