if not IsLoggedIn then -- WoW 2.0

--[[
Name: AceEvent-2.0
Revision: $Rev: 36174 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
Description: Mixin to allow for event handling, scheduling, and inter-addon
             communication.
Dependencies: AceLibrary, AceOO-2.0
License: LGPL v2.1
]]

local MAJOR_VERSION = "AceEvent-2.0"
local MINOR_VERSION = "$Revision: 36174 $"

if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end

if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end

local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local Mixin = AceOO.Mixin
local AceEvent = Mixin {
						"RegisterEvent",
						"RegisterAllEvents",
						"UnregisterEvent",
						"UnregisterAllEvents",
						"TriggerEvent",
						"ScheduleEvent",
						"ScheduleRepeatingEvent",
						"CancelScheduledEvent",
						"CancelAllScheduledEvents",
						"IsEventRegistered",
						"IsEventScheduled",
						"RegisterBucketEvent",
						"UnregisterBucketEvent",
						"UnregisterAllBucketEvents",
						"IsBucketEventRegistered",
						"ScheduleLeaveCombatAction",
						"CancelAllCombatSchedules",
					   }

local weakKey = {__mode="k"}

local WoW21 = IsLoggedIn and true

local FAKE_NIL
local RATE

local eventsWhichHappenOnce = {
	PLAYER_LOGIN = true,
	AceEvent_FullyInitialized = true,
	VARIABLES_LOADED = true,
	PLAYER_LOGOUT = true,
}
local next = next
local pairs = pairs
local pcall = pcall
local type = type
local GetTime = GetTime
local gcinfo = gcinfo
local unpack = unpack
local geterrorhandler = geterrorhandler

local new, del
do
	local cache = setmetatable({}, {__mode='k'})
	function new(...)
		local t = next(cache)
		if t then
			cache[t] = nil
			for i = 1, select('#', ...) do
				t[i] = select(i, ...)
			end
			return t
		else
			return { ... }
		end
	end
	function del(t)
		for k in pairs(t) do
			t[k] = nil
		end
		cache[t] = true
		return nil
	end
end

local registeringFromAceEvent
function AceEvent:RegisterEvent(event, method, once)
	AceEvent:argCheck(event, 2, "string")
	if self == AceEvent and not registeringFromAceEvent then
		AceEvent:argCheck(method, 3, "function")
		self = method
	else
		AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
		if type(method) == "boolean" or type(method) == "number" then
			AceEvent:argCheck(once, 4, "nil")
			once, method = method, event
		end
	end
	AceEvent:argCheck(once, 4, "number", "boolean", "nil")
	if eventsWhichHappenOnce[event] then
		once = true
	end
	local throttleRate
	if type(once) == "number" then
		throttleRate, once = once
	end
	if not method then
		method = event
	end
	if type(method) == "string" and type(self[method]) ~= "function" then
		AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
	else
		assert(type(method) == "function" or type(method) == "string")
	end

	local AceEvent_registry = AceEvent.registry
	if not AceEvent_registry[event] then
		AceEvent_registry[event] = new()
		AceEvent.frame:RegisterEvent(event)
	end

	local remember = true
	if AceEvent_registry[event][self] then
		remember = false
	end
	AceEvent_registry[event][self] = method

	local AceEvent_onceRegistry = AceEvent.onceRegistry
	if once then
		if not AceEvent_onceRegistry then
			AceEvent.onceRegistry = {}
			AceEvent_onceRegistry = AceEvent.onceRegistry
		end
		if not AceEvent_onceRegistry[event] then
			AceEvent_onceRegistry[event] = new()
		end
		AceEvent_onceRegistry[event][self] = true
	else
		if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
			AceEvent_onceRegistry[event][self] = nil
			if not next(AceEvent_onceRegistry[event]) then
				AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
			end
		end
	end

	local AceEvent_throttleRegistry = AceEvent.throttleRegistry
	if throttleRate then
		if not AceEvent_throttleRegistry then
			AceEvent.throttleRegistry = {}
			AceEvent_throttleRegistry = AceEvent.throttleRegistry
		end
		if not AceEvent_throttleRegistry[event] then
			AceEvent_throttleRegistry[event] = new()
		end
		if AceEvent_throttleRegistry[event][self] then
			AceEvent_throttleRegistry[event][self] = nil
		end
		AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
		local t = AceEvent_throttleRegistry[event][self]
		t[RATE] = throttleRate
	else
		if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
			if AceEvent_throttleRegistry[event][self] then
				AceEvent_throttleRegistry[event][self] = nil
			end
			if not next(AceEvent_throttleRegistry[event]) then
				AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
			end
		end
	end

	if remember then
		AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
	end
end

local ALL_EVENTS

function AceEvent:RegisterAllEvents(method)
	if self == AceEvent then
		AceEvent:argCheck(method, 1, "function")
		self = method
	else
		AceEvent:argCheck(method, 1, "string", "function")
		if type(method) == "string" and type(self[method]) ~= "function" then
			AceEvent:error("Cannot register all events to method %q, it does not exist", method)
		end
	end

	local AceEvent_registry = AceEvent.registry
	if not AceEvent_registry[ALL_EVENTS] then
		AceEvent_registry[ALL_EVENTS] = new()
		AceEvent.frame:RegisterAllEvents()
	end

	AceEvent_registry[ALL_EVENTS][self] = method
end

local memstack, timestack = {}, {}
local memdiff, timediff

function AceEvent:TriggerEvent(event, ...)
	local tmp = new()
	if type(event) ~= "string" then
		DEFAULT_CHAT_FRAME:AddMessage(debugstack())
	end
	AceEvent:argCheck(event, 2, "string")
	local AceEvent_registry = AceEvent.registry
	if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
		return
	end
	local lastEvent = AceEvent.currentEvent
	AceEvent.currentEvent = event

	local AceEvent_onceRegistry = AceEvent.onceRegistry
	local AceEvent_debugTable = AceEvent.debugTable
	if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
		for obj, method in pairs(AceEvent_onceRegistry[event]) do
			tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
		end
		local obj = next(tmp)
		while obj do
			local mem, time
			if AceEvent_debugTable then
				if not AceEvent_debugTable[event] then
					AceEvent_debugTable[event] = {}
				end
				if not AceEvent_debugTable[event][obj] then
					AceEvent_debugTable[event][obj] = {
						mem = 0,
						time = 0,
						count = 0,
					}
				end
				if memdiff then
					table.insert(memstack, memdiff)
					table.insert(timestack, timediff)
				end
				memdiff, timediff = 0, 0
				mem, time = gcinfo(), GetTime()
			end
			local method = tmp[obj]
			AceEvent.UnregisterEvent(obj, event)
			if type(method) == "string" then
				local obj_method = obj[method]
				if obj_method then
					local success, err = pcall(obj_method, obj, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
			elseif method then -- function
				local success, err = pcall(method, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
			if AceEvent_debugTable then
				local dmem, dtime = memdiff, timediff
				mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
				AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
				AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
				AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

				memdiff, timediff = table.remove(memstack), table.remove(timestack)
				if memdiff then
					memdiff = memdiff + mem + dmem
					timediff = timediff + time + dtime
				end
			end
			tmp[obj] = nil
			obj = next(tmp)
		end
	end

	local AceEvent_throttleRegistry = AceEvent.throttleRegistry
	local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
	if AceEvent_registry[event] then
		for obj, method in pairs(AceEvent_registry[event]) do
			tmp[obj] = method
		end
		local obj = next(tmp)
		while obj do
			local method = tmp[obj]
			local continue = false
			if throttleTable and throttleTable[obj] then
				local a1 = ...
				if a1 == nil then
					a1 = FAKE_NIL
				end
				if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
					throttleTable[obj][a1] = GetTime()
				else
					continue = true
				end
			end
			if not continue then
				local mem, time
				if AceEvent_debugTable then
					if not AceEvent_debugTable[event] then
						AceEvent_debugTable[event] = {}
					end
					if not AceEvent_debugTable[event][obj] then
						AceEvent_debugTable[event][obj] = {
							mem = 0,
							time = 0,
							count = 0,
						}
					end
					if memdiff then
						table.insert(memstack, memdiff)
						table.insert(timestack, timediff)
					end
					memdiff, timediff = 0, 0
					mem, time = gcinfo(), GetTime()
				end
				if type(method) == "string" then
					local obj_method = obj[method]
					if obj_method then
						local success, err = pcall(obj_method, obj, ...)
						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
					end
				elseif method then -- function
					local success, err = pcall(method, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
				if AceEvent_debugTable then
					local dmem, dtime = memdiff, timediff
					mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
					AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
					AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
					AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

					memdiff, timediff = table.remove(memstack), table.remove(timestack)
					if memdiff then
						memdiff = memdiff + mem + dmem
						timediff = timediff + time + dtime
					end
				end
			end
			tmp[obj] = nil
			obj = next(tmp)
		end
	end
	if AceEvent_registry[ALL_EVENTS] then
		for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
			tmp[obj] = method
		end
		local obj = next(tmp)
		while obj do
			local method = tmp[obj]
			local mem, time
			if AceEvent_debugTable then
				if not AceEvent_debugTable[event] then
					AceEvent_debugTable[event] = {}
				end
				if not AceEvent_debugTable[event][obj] then
					AceEvent_debugTable[event][obj] = {}
					AceEvent_debugTable[event][obj].mem = 0
					AceEvent_debugTable[event][obj].time = 0
					AceEvent_debugTable[event][obj].count = 0
				end
				if memdiff then
					table.insert(memstack, memdiff)
					table.insert(timestack, timediff)
				end
				memdiff, timediff = 0, 0
				mem, time = gcinfo(), GetTime()
			end
			if type(method) == "string" then
				local obj_method = obj[method]
				if obj_method then
					local success, err = pcall(obj_method, obj, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
			elseif method then -- function
				local success, err = pcall(method, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
			if AceEvent_debugTable then
				local dmem, dtime = memdiff, timediff
				mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
				AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
				AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
				AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

				memdiff, timediff = table.remove(memstack), table.remove(timestack)
				if memdiff then
					memdiff = memdiff + mem + dmem
					timediff = timediff + time + dtime
				end
			end
			tmp[obj] = nil
			obj = next(tmp)
		end
	end
	tmp = del(tmp)
	AceEvent.currentEvent = lastEvent
end

local delayRegistry
local tmp = {}
local function OnUpdate()
	local t = GetTime()
	for k,v in pairs(delayRegistry) do
		tmp[k] = true
	end
	local AceEvent_debugTable = AceEvent.debugTable
	for k in pairs(tmp) do
		local v = delayRegistry[k]
		if v then
			local v_time = v.time
			if not v_time then
				delayRegistry[k] = nil
			elseif v_time <= t then
				local v_repeatDelay = v.repeatDelay
				if v_repeatDelay then
					-- use the event time, not the current time, else timing inaccuracies add up over time
					v.time = v_time + v_repeatDelay
				end
				local event = v.event
				local mem, time
				if AceEvent_debugTable then
					mem, time = gcinfo(), GetTime()
				end
				if type(event) == "function" then
					local success, err = pcall(event, unpack(v, 1, v.n))
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				else
					AceEvent:TriggerEvent(event, unpack(v, 1, v.n))
				end
				if AceEvent_debugTable then
					mem, time = gcinfo() - mem, GetTime() - time
					v.mem = v.mem + mem
					v.timeSpent = v.timeSpent + time
					v.count = v.count + 1
				end
				if not v_repeatDelay then
					local x = delayRegistry[k]
					if x and x.time == v_time then -- check if it was manually reset
						if type(k) == "string" then
							del(delayRegistry[k])
						end
						delayRegistry[k] = nil
					end
				end
			end
		end
	end
	for k in pairs(tmp) do
		tmp[k] = nil
	end
	if not next(delayRegistry) then
		AceEvent.frame:Hide()
	end
end

local function ScheduleEvent(self, repeating, event, delay, ...)
	local id
	if type(event) == "string" or type(event) == "table" then
		if type(event) == "table" then
			if not delayRegistry or not delayRegistry[event] then
				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
			end
		end
		if type(delay) ~= "number" then
			id, event, delay = event, delay, ...
			AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
			AceEvent:argCheck(delay, 4, "number")
			self:CancelScheduledEvent(id)
		end
	else
		AceEvent:argCheck(event, 2, "string", "function")
		AceEvent:argCheck(delay, 3, "number")
	end

	if not delayRegistry then
		AceEvent.delayRegistry = {}
		delayRegistry = AceEvent.delayRegistry
		AceEvent.frame:SetScript("OnUpdate", OnUpdate)
	end
	local t
	if type(id) == "table" then
		for k in pairs(id) do
			id[k] = nil
		end
		t = id
		for i = 2, select('#', ...) do
			t[i-1] = select(i, ...)
		end
		t.n = select('#', ...) - 1
	elseif id then
		t = new(select(2, ...))
		t.n = select('#', ...) - 1
	else
		t = { n = select('#', ...), ... }
	end
	t.event = event
	t.time = GetTime() + delay
	t.self = self
	t.id = id or t
	t.repeatDelay = repeating and delay
	if AceEvent.debugTable then
		t.mem = 0
		t.count = 0
		t.timeSpent = 0
	end
	delayRegistry[t.id] = t
	AceEvent.frame:Show()
	return t.id
end

function AceEvent:ScheduleEvent(event, delay, ...)
	if type(event) == "string" or type(event) == "table" then
		if type(event) == "table" then
			if not delayRegistry or not delayRegistry[event] then
				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
			end
		end
		if type(delay) ~= "number" then
			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
			AceEvent:argCheck(..., 4, "number")
		end
	else
		AceEvent:argCheck(event, 2, "string", "function")
		AceEvent:argCheck(delay, 3, "number")
	end

	return ScheduleEvent(self, false, event, delay, ...)
end

function AceEvent:ScheduleRepeatingEvent(event, delay, ...)
	if type(event) == "string" or type(event) == "table" then
		if type(event) == "table" then
			if not delayRegistry or not delayRegistry[event] then
				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
			end
		end
		if type(delay) ~= "number" then
			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
			AceEvent:argCheck(..., 4, "number")
		end
	else
		AceEvent:argCheck(event, 2, "string", "function")
		AceEvent:argCheck(delay, 3, "number")
	end

	return ScheduleEvent(self, true, event, delay, ...)
end

function AceEvent:CancelScheduledEvent(t)
	AceEvent:argCheck(t, 2, "string", "table")
	if delayRegistry then
		local v = delayRegistry[t]
		if v then
			if type(t) == "string" then
				del(delayRegistry[t])
			end
			delayRegistry[t] = nil
			if not next(delayRegistry) then
				AceEvent.frame:Hide()
			end
			return true
		end
	end
	return false
end

function AceEvent:IsEventScheduled(t)
	AceEvent:argCheck(t, 2, "string", "table")
	if delayRegistry then
		local v = delayRegistry[t]
		if v then
			return true, v.time - GetTime()
		end
	end
	return false, nil
end

function AceEvent:UnregisterEvent(event)
	AceEvent:argCheck(event, 2, "string")
	local AceEvent_registry = AceEvent.registry
	if AceEvent_registry[event] and AceEvent_registry[event][self] then
		AceEvent_registry[event][self] = nil
		local AceEvent_onceRegistry = AceEvent.onceRegistry
		if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
			AceEvent_onceRegistry[event][self] = nil
			if not next(AceEvent_onceRegistry[event]) then
				AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
			end
		end
		local AceEvent_throttleRegistry = AceEvent.throttleRegistry
		if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
			AceEvent_throttleRegistry[event][self] = nil
			if not next(AceEvent_throttleRegistry[event]) then
				AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
			end
		end
		if not next(AceEvent_registry[event]) then
			AceEvent_registry[event] = del(AceEvent_registry[event])
			if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
				AceEvent.frame:UnregisterEvent(event)
			end
		end
	else
		if self == AceEvent then
			error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2)
		else
			AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
		end
	end
	AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end

function AceEvent:UnregisterAllEvents()
	local AceEvent_registry = AceEvent.registry
	if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
		AceEvent_registry[ALL_EVENTS][self] = nil
		if not next(AceEvent_registry[ALL_EVENTS]) then
			AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS])
			AceEvent.frame:UnregisterAllEvents()
			for k,v in pairs(AceEvent_registry) do
				AceEvent.frame:RegisterEvent(k)
			end
		end
	end
	if AceEvent_registry.AceEvent_EventUnregistered then
		local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered
		local x = data[self]
		data[self] = nil
		if x then
			if not next(data) then
				if not AceEvent_registry[ALL_EVENTS] then
					AceEvent.frame:UnregisterEvent(event)
				end
				AceEvent_registry[event] = del(AceEvent_registry[event])
			end
			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
		end
	end
	for event, data in pairs(AceEvent_registry) do
		local x = data[self]
		data[self] = nil
		if x and event ~= ALL_EVENTS then
			if not next(data) then
				if not AceEvent_registry[ALL_EVENTS] then
					AceEvent.frame:UnregisterEvent(event)
				end
				AceEvent_registry[event] = del(AceEvent_registry[event])
			end
			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
		end
	end
	if AceEvent.onceRegistry then
		for event, data in pairs(AceEvent.onceRegistry) do
			data[self] = nil
		end
	end
end

function AceEvent:CancelAllScheduledEvents()
	if delayRegistry then
		for k,v in pairs(delayRegistry) do
			if v.self == self then
				if type(k) == "string" then
					del(delayRegistry[k])
				end
				delayRegistry[k] = nil
			end
		end
		if not next(delayRegistry) then
			AceEvent.frame:Hide()
		end
	end
end

function AceEvent:IsEventRegistered(event)
	AceEvent:argCheck(event, 2, "string")
	local AceEvent_registry = AceEvent.registry
	if self == AceEvent then
		return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
	end
	if AceEvent_registry[event] and AceEvent_registry[event][self] then
		return true, AceEvent_registry[event][self]
	end
	return false, nil
end

local UnitExists = UnitExists
local bucketfunc
function AceEvent:RegisterBucketEvent(event, delay, method, ...)
	AceEvent:argCheck(event, 2, "string", "table")
	if type(event) == "table" then
		for k,v in pairs(event) do
			if type(k) ~= "number" then
				AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
			elseif type(v) ~= "string" then
				AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
			end
		end
	end
	AceEvent:argCheck(delay, 3, "number")
	if AceEvent == self then
		AceEvent:argCheck(method, 4, "function")
		self = method
	else
		if type(event) == "string" then
			AceEvent:argCheck(method, 4, "string", "function", "nil")
			if not method then
				method = event
			end
		else
			AceEvent:argCheck(method, 4, "string", "function")
		end

		if type(method) == "string" and type(self[method]) ~= "function" then
			AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
		end
	end
	local buckets = AceEvent.buckets
	if not buckets[event] then
		buckets[event] = new()
	end
	if not buckets[event][self] then
		local t = new()
		t.current = new()
		t.self = self
		buckets[event][self] = t
	else
		AceEvent.CancelScheduledEvent(self, buckets[event][self].id)
	end
	local bucket = buckets[event][self]
	bucket.method = method
	
	local n = select('#', ...)
	if n > 0 then
		for i = 1, n do
			bucket[i] = select(i, ...)
		end
	end
	bucket.n = n

	local func = function(arg1)
		bucket.run = true
		if arg1 then
			bucket.current[arg1] = true
		end
	end
	buckets[event][self].func = func
	local isUnitBucket = true
	if type(event) == "string" then
		AceEvent.RegisterEvent(self, event, func)
		if not event:find("^UNIT_") then
			isUnitBucket = false
		end
	else
		for _,v in ipairs(event) do
			AceEvent.RegisterEvent(self, v, func)
			if isUnitBucket and not v:find("^UNIT_") then
				isUnitBucket = false
			end
		end
	end
	bucket.unit = isUnitBucket
	if not bucketfunc then
		bucketfunc = function(bucket)
			local current = bucket.current
			local method = bucket.method
			local self = bucket.self
			if bucket.run then
				if bucket.unit then
					for unit in pairs(current) do
						if not UnitExists(unit) then
							current[unit] = nil
						end
					end
				end
				if type(method) == "string" then
					self[method](self, current, unpack(bucket, 1, bucket.n))
				elseif method then -- function
					method(current, unpack(bucket, 1, bucket.n))
				end
				for k in pairs(current) do
					current[k] = nil
					k = nil
				end
				bucket.run = false
			end
		end
	end
	bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
end

function AceEvent:IsBucketEventRegistered(event)
	AceEvent:argCheck(event, 2, "string", "table")
	return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
end

function AceEvent:UnregisterBucketEvent(event)
	AceEvent:argCheck(event, 2, "string", "table")
	if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
		AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
	end

	local bucket = AceEvent.buckets[event][self]

	if type(event) == "string" then
		AceEvent.UnregisterEvent(self, event)
	else
		for _,v in ipairs(event) do
			AceEvent.UnregisterEvent(self, v)
		end
	end
	AceEvent:CancelScheduledEvent(bucket.id)

	bucket.current = del(bucket.current)
	AceEvent.buckets[event][self] = del(bucket)
	if not next(AceEvent.buckets[event]) then
		AceEvent.buckets[event] = del(AceEvent.buckets[event])
	end
end

function AceEvent:UnregisterAllBucketEvents()
	if not AceEvent.buckets or not next(AceEvent.buckets) then
		return
	end
	for k,v in pairs(AceEvent.buckets) do
		if v == self then
			AceEvent.UnregisterBucketEvent(self, k)
			k = nil
		end
	end
end

local combatSchedules
function AceEvent:CancelAllCombatSchedules()
	local i = 0
	while true do
		i = i + 1
		if not combatSchedules[i] then
			break
		end
		local v = combatSchedules[i]
		if v.self == self then
			v = del(v)
			table.remove(combatSchedules, i)
			i = i - 1
		end
	end
end

local inCombat = false

function AceEvent:PLAYER_REGEN_DISABLED()
	inCombat = true
end

local tmp = {}
function AceEvent:PLAYER_REGEN_ENABLED()
	inCombat = false
	for i, v in ipairs(combatSchedules) do
		tmp[i] = v
		combatSchedules[i] = nil
	end
	for i, v in ipairs(tmp) do
		local func = v.func
		if func then
			local success, err = pcall(func, unpack(v, 1, v.n))
			if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
		else
			local obj = v.obj or v.self
			local method = v.method
			local obj_method = obj[method]
			if obj_method then
				local success, err = pcall(obj_method, obj, unpack(v, 1, v.n))
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
		end
		tmp[i] = del(v)
	end
end

function AceEvent:ScheduleLeaveCombatAction(method, ...)
	local style = type(method)
	if self == AceEvent then
		if style == "table" then
			local func = (...)
			AceEvent:argCheck(func, 3, "string")
			if type(method[func]) ~= "function" then
				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
			end
		else
			AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table")
		end
		self = method
	else
		AceEvent:argCheck(method, 2, "function", "string", "table")
		if style == "string" and type(self[method]) ~= "function" then
			AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method)
		elseif style == "table" then
			local func = (...)
			AceEvent:argCheck(func, 3, "string")
			if type(method[func]) ~= "function" then
				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
			end
		end
	end
	
	if not inCombat then
		local success, err
		if type(method) == "function" then
			success, err = pcall(method, ...)
		elseif type(method) == "table" then
			local func = (...)
			success, err = pcall(method[func], method, select(2, ...))
		else
			success, err = pcall(self[method], self, ...)
		end
		if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
		return
	end
	local t
	local n = select('#', ...)
	if style == "table" then
		t = new(select(2, ...))
		t.obj = method
		t.method = (...)
		t.n = n-1
	else
		t = new(...)
		t.n = n
		if style == "function" then
			t.func = method
		else
			t.method = method
		end
	end
	t.self = self
	table.insert(combatSchedules, t)
end

function AceEvent:OnEmbedDisable(target)
	self.UnregisterAllEvents(target)

	self.CancelAllScheduledEvents(target)

	self.UnregisterAllBucketEvents(target)
	
	self.CancelAllCombatSchedules(target)
end

function AceEvent:EnableDebugging()
	if not self.debugTable then
		self.debugTable = {}

		if delayRegistry then
			for k,v in pairs(self.delayRegistry) do
				if not v.mem then
					v.mem = 0
					v.count = 0
					v.timeSpent = 0
				end
			end
		end
	end
end

function AceEvent:IsFullyInitialized()
	return self.postInit or false
end

if WoW21 then
	function AceEvent:IsPostPlayerLogin()
		return IsLoggedIn() and true or false
	end
else
	function AceEvent:IsPostPlayerLogin()
		return self.playerLogin or false
	end
end

local function activate(self, oldLib, oldDeactivate)
	AceEvent = self
	
	self.onceRegistry = oldLib and oldLib.onceRegistry or {}
	self.throttleRegistry = oldLib and oldLib.throttleRegistry or {}
	self.delayRegistry = oldLib and oldLib.delayRegistry or {}
	self.buckets = oldLib and oldLib.buckets or {}
	self.registry = oldLib and oldLib.registry or {}
	self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame")
	self.debugTable = oldLib and oldLib.debugTable
	if WoW21 then
		self.playerLogin = IsLoggedIn() and true
	else
		self.playerLogin = oldLib and oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
	end
	self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
	self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or {}
	self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or {}
	self.RATE = oldLib and oldLib.RATE or {}
	self.combatSchedules = oldLib and oldLib.combatSchedules or {}
	
	combatSchedules = self.combatSchedules
	ALL_EVENTS = self.ALL_EVENTS
	FAKE_NIL = self.FAKE_NIL
	RATE = self.RATE
	local inPlw = false
	local blacklist = {
		UNIT_INVENTORY_CHANGED = true,
		BAG_UPDATE = true,
		ITEM_LOCK_CHANGED = true,
		ACTIONBAR_SLOT_CHANGED = true,
	}
	self.frame:SetScript("OnEvent", function(_, event, ...)
		if event == "PLAYER_ENTERING_WORLD" then
			inPlw = false
		elseif event == "PLAYER_LEAVING_WORLD" then
			inPlw = true
		end
		if event and (not inPlw or not blacklist[event]) then
			self:TriggerEvent(event, ...)
		end
	end)
	if self.delayRegistry then
		delayRegistry = self.delayRegistry
		self.frame:SetScript("OnUpdate", OnUpdate)
	end

	self:UnregisterAllEvents()
	self:CancelAllScheduledEvents()

	registeringFromAceEvent = true
	self:RegisterEvent("LOOT_OPENED", function()
		SendAddonMessage("LOOT_OPENED", "", "RAID")
	end)
	registeringFromAceEvent = nil

	local function handleFullInit()
		if not self.postInit then
			local function func()
				self.postInit = true
				self:TriggerEvent("AceEvent_FullyInitialized")
				if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
					self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
				end
				if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
					self:UnregisterEvent("MEETINGSTONE_CHANGED")
				end
				if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
					self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
				end
				if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
					self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
				end
				collectgarbage('collect')
			end
			registeringFromAceEvent = true
			local f = function()
				self.playerLogin = true
				self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
			end
			self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
			self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
				self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15)
			end)
			self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
				if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
					registeringFromAceEvent = true
					self:UnregisterEvent("MEETINGSTONE_CHANGED")
					self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true)
					registeringFromAceEvent = nil
				end
			end)
			self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
			registeringFromAceEvent = nil
		end
	end
	
	if not self.playerLogin then
		registeringFromAceEvent = true
		self:RegisterEvent("PLAYER_LOGIN", function()
			self.playerLogin = true
			handleFullInit()
			handleFullInit = nil
			collectgarbage('collect')
		end, true)
		registeringFromAceEvent = nil
	else
		handleFullInit()
		handleFullInit = nil
	end
	
	
	registeringFromAceEvent = true
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_REGEN_DISABLED")
	inCombat = InCombatLockdown()
	registeringFromAceEvent = nil
	
	for event in pairs(self.registry) do
		self.frame:RegisterEvent(event)
	end

	self:activate(oldLib, oldDeactivate)
	if oldLib then
		oldDeactivate(oldLib)
	end
end

AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)

else -- WoW 2.1

--[[
Name: AceEvent-2.0
Revision: $Rev: 36174 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
Description: Mixin to allow for event handling, scheduling, and inter-addon
             communication.
Dependencies: AceLibrary, AceOO-2.0
License: LGPL v2.1
]]

local MAJOR_VERSION = "AceEvent-2.0"
local MINOR_VERSION = tostring(("$Revision: 36174 $"):match("(%d+)"))

if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end

if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end

local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local Mixin = AceOO.Mixin
local AceEvent = Mixin {
						"RegisterEvent",
						"RegisterAllEvents",
						"UnregisterEvent",
						"UnregisterAllEvents",
						"TriggerEvent",
						"ScheduleEvent",
						"ScheduleRepeatingEvent",
						"CancelScheduledEvent",
						"CancelAllScheduledEvents",
						"IsEventRegistered",
						"IsEventScheduled",
						"RegisterBucketEvent",
						"UnregisterBucketEvent",
						"UnregisterAllBucketEvents",
						"IsBucketEventRegistered",
						"ScheduleLeaveCombatAction",
						"CancelAllCombatSchedules",
					   }

local weakKey = {__mode="k"}

local WoW21 = IsLoggedIn and true

local FAKE_NIL
local RATE
local addonFrames
local onceRegistry
local throttleRegistry
local buckets
local registry
local combatSchedules
local AceEvent_debugTable

local eventsWhichHappenOnce = {
	PLAYER_LOGIN = true,
	AceEvent_FullyInitialized = true,
	VARIABLES_LOADED = true,
	PLAYER_LOGOUT = true,
}
local next = next
local pairs = pairs
local pcall = pcall
local type = type
local GetTime = GetTime
local gcinfo = gcinfo
local unpack = unpack
local geterrorhandler = geterrorhandler

local new, del
do
	local cache = setmetatable({}, {__mode='k'})
	function new(...)
		local t = next(cache)
		if t then
			cache[t] = nil
			for i = 1, select('#', ...) do
				t[i] = select(i, ...)
			end
			return t
		else
			return { ... }
		end
	end
	function del(t)
		for k in pairs(t) do
			t[k] = nil
		end
		cache[t] = true
		return nil
	end
end

local makeFrameForAddon

local registeringFromAceEvent
function AceEvent:RegisterEvent(event, method, once)
	AceEvent:argCheck(event, 2, "string")
	if self == AceEvent and not registeringFromAceEvent then
		AceEvent:argCheck(method, 3, "function")
		self = method
	else
		AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
		if type(method) == "boolean" or type(method) == "number" then
			AceEvent:argCheck(once, 4, "nil")
			once, method = method, event
		end
	end
	AceEvent:argCheck(once, 4, "number", "boolean", "nil")
	if eventsWhichHappenOnce[event] then
		once = true
	end
	local throttleRate
	if type(once) == "number" then
		throttleRate, once = once
	end
	if not method then
		method = event
	end
	if type(method) == "string" and type(self[method]) ~= "function" then
		AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
	else
		assert(type(method) == "function" or type(method) == "string")
	end

	if not registry[event] then
		registry[event] = new()
	end
	if event:match("^[A-Z_]+$") then
		-- Blizzard event
		if self == method then
			addonFrames[AceEvent]:RegisterEvent(event)
		else
			if not addonFrames[self] then
				-- HACK
				makeFrameForAddon(self)
			end
			addonFrames[self]:RegisterEvent(event)
		end
	end

	local remember = true
	if registry[event][self] then
		remember = false
	end
	registry[event][self] = method

	if once then
		if not onceRegistry[event] then
			onceRegistry[event] = new()
		end
		onceRegistry[event][self] = true
	else
		if onceRegistry[event] then
			onceRegistry[event][self] = nil
			if not next(onceRegistry[event]) then
				onceRegistry[event] = del(onceRegistry[event])
			end
		end
	end

	if throttleRate then
		if not throttleRegistry[event] then
			throttleRegistry[event] = new()
		end
		if throttleRegistry[event][self] then
			throttleRegistry[event][self] = nil
		end
		throttleRegistry[event][self] = setmetatable(new(), weakKey)
		local t = throttleRegistry[event][self]
		t[RATE] = throttleRate
	else
		if throttleRegistry[event] then
			if throttleRegistry[event][self] then
				throttleRegistry[event][self] = nil
			end
			if not next(throttleRegistry[event]) then
				throttleRegistry[event] = del(throttleRegistry[event])
			end
		end
	end

	if remember then
		AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
	end
end

local ALL_EVENTS

function AceEvent:RegisterAllEvents(method)
	if self == AceEvent then
		AceEvent:argCheck(method, 1, "function")
		self = method
	else
		AceEvent:argCheck(method, 1, "string", "function")
		if type(method) == "string" and type(self[method]) ~= "function" then
			AceEvent:error("Cannot register all events to method %q, it does not exist", method)
		end
	end

	if not registry[ALL_EVENTS] then
		registry[ALL_EVENTS] = new()
	end
	if self == method then
		addonFrames[AceEvent]:RegisterAllEvents()
	else
		if not addonFrames[self] then
			-- HACK
			makeFrameForAddon(self)
		end
		addonFrames[self]:RegisterAllEvents()
	end

	registry[ALL_EVENTS][self] = method
end

local memstack, timestack = {}, {}
local memdiff, timediff

function AceEvent:TriggerEvent(event, ...)
	local tmp = new()
	AceEvent:argCheck(event, 2, "string")
	if not registry[event] and not registry[ALL_EVENTS] then
		return
	end
	local lastEvent = AceEvent.currentEvent
	AceEvent.currentEvent = event

	if onceRegistry[event] then
		for obj, method in pairs(onceRegistry[event]) do
			tmp[obj] = registry[event] and registry[event][obj] or nil
		end
		local obj = next(tmp)
		while obj do
			local mem, time
			if AceEvent_debugTable then
				if not AceEvent_debugTable[event] then
					AceEvent_debugTable[event] = {}
				end
				if not AceEvent_debugTable[event][obj] then
					AceEvent_debugTable[event][obj] = {
						mem = 0,
						time = 0,
						count = 0,
					}
				end
				if memdiff then
					table.insert(memstack, memdiff)
					table.insert(timestack, timediff)
				end
				memdiff, timediff = 0, 0
				mem, time = gcinfo(), GetTime()
			end
			local method = tmp[obj]
			AceEvent.UnregisterEvent(obj, event)
			if type(method) == "string" then
				local obj_method = obj[method]
				if obj_method then
					local success, err = pcall(obj_method, obj, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
			elseif method then -- function
				local success, err = pcall(method, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
			if AceEvent_debugTable then
				local dmem, dtime = memdiff, timediff
				mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
				AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
				AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
				AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

				memdiff, timediff = table.remove(memstack), table.remove(timestack)
				if memdiff then
					memdiff = memdiff + mem + dmem
					timediff = timediff + time + dtime
				end
			end
			tmp[obj] = nil
			obj = next(tmp)
		end
	end

	local throttleTable = throttleRegistry[event]
	if registry[event] then
		for obj, method in pairs(registry[event]) do
			tmp[obj] = method
		end
		local obj = next(tmp)
		while obj do
			local method = tmp[obj]
			local continue = false
			if throttleTable and throttleTable[obj] then
				local a1 = ...
				if a1 == nil then
					a1 = FAKE_NIL
				end
				if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
					throttleTable[obj][a1] = GetTime()
				else
					continue = true
				end
			end
			if not continue then
				local mem, time
				if AceEvent_debugTable then
					if not AceEvent_debugTable[event] then
						AceEvent_debugTable[event] = {}
					end
					if not AceEvent_debugTable[event][obj] then
						AceEvent_debugTable[event][obj] = {
							mem = 0,
							time = 0,
							count = 0,
						}
					end
					if memdiff then
						table.insert(memstack, memdiff)
						table.insert(timestack, timediff)
					end
					memdiff, timediff = 0, 0
					mem, time = gcinfo(), GetTime()
				end
				if type(method) == "string" then
					local obj_method = obj[method]
					if obj_method then
						local success, err = pcall(obj_method, obj, ...)
						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
					end
				elseif method then -- function
					local success, err = pcall(method, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
				if AceEvent_debugTable then
					local dmem, dtime = memdiff, timediff
					mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
					AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
					AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
					AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

					memdiff, timediff = table.remove(memstack), table.remove(timestack)
					if memdiff then
						memdiff = memdiff + mem + dmem
						timediff = timediff + time + dtime
					end
				end
			end
			tmp[obj] = nil
			obj = next(tmp)
		end
	end
	if registry[ALL_EVENTS] then
		for obj, method in pairs(registry[ALL_EVENTS]) do
			tmp[obj] = method
		end
		local obj = next(tmp)
		while obj do
			local method = tmp[obj]
			local mem, time
			if AceEvent_debugTable then
				if not AceEvent_debugTable[event] then
					AceEvent_debugTable[event] = {}
				end
				if not AceEvent_debugTable[event][obj] then
					AceEvent_debugTable[event][obj] = {}
					AceEvent_debugTable[event][obj].mem = 0
					AceEvent_debugTable[event][obj].time = 0
					AceEvent_debugTable[event][obj].count = 0
				end
				if memdiff then
					table.insert(memstack, memdiff)
					table.insert(timestack, timediff)
				end
				memdiff, timediff = 0, 0
				mem, time = gcinfo(), GetTime()
			end
			if type(method) == "string" then
				local obj_method = obj[method]
				if obj_method then
					local success, err = pcall(obj_method, obj, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
			elseif method then -- function
				local success, err = pcall(method, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
			if AceEvent_debugTable then
				local dmem, dtime = memdiff, timediff
				mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
				AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
				AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
				AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

				memdiff, timediff = table.remove(memstack), table.remove(timestack)
				if memdiff then
					memdiff = memdiff + mem + dmem
					timediff = timediff + time + dtime
				end
			end
			tmp[obj] = nil
			obj = next(tmp)
		end
	end
	tmp = del(tmp)
	AceEvent.currentEvent = lastEvent
end

local delayRegistry

local delayParents = {}
local function ScheduleEvent(self, repeating, event, delay, ...)
	local id
	if type(event) == "string" or type(event) == "table" then
		if type(event) == "table" then
			if not delayRegistry[event] then
				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
			end
		end
		if type(delay) ~= "number" then
			id, event, delay = event, delay, ...
			AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
			AceEvent:argCheck(delay, 4, "number")
			self:CancelScheduledEvent(id)
		end
	else
		AceEvent:argCheck(event, 2, "string", "function")
		AceEvent:argCheck(delay, 3, "number")
	end
	
	local t
	if type(id) == "table" then
		for k in pairs(id) do
			id[k] = nil
		end
		t = id
		for i = 2, select('#', ...) do
			t[i-1] = select(i, ...)
		end
		t.n = select('#', ...) - 1
	elseif id then
		t = new(select(2, ...))
		t.n = select('#', ...) - 1
	else
		t = { n = select('#', ...), ... }
	end
	t.event = event
	t.time = GetTime() + delay
	t.self = self
	t.id = id or t
	t.repeatDelay = repeating and delay
	if AceEvent_debugTable then
		t.mem = 0
		t.count = 0
		t.timeSpent = 0
	end
	delayRegistry[t.id] = t
	if not delayParents[self] then
		delayParents[self] = new()
		if not addonFrames[self] then
			-- HACK
			makeFrameForAddon(self)
		end
		addonFrames[self]:Show()
	end
	delayParents[self][t.id] = t
	return t.id
end

function AceEvent:ScheduleEvent(event, delay, ...)
--	DEFAULT_CHAT_FRAME:AddMessage(debugstack() .. "\n--------\n")
	if type(event) == "string" or type(event) == "table" then
		if type(event) == "table" then
			if not delayRegistry[event] then
				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
			end
		end
		if type(delay) ~= "number" then
			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
			AceEvent:argCheck(..., 4, "number")
		end
	else
		AceEvent:argCheck(event, 2, "string", "function")
		AceEvent:argCheck(delay, 3, "number")
	end

	return ScheduleEvent(self, false, event, delay, ...)
end

function AceEvent:ScheduleRepeatingEvent(event, delay, ...)
	if type(event) == "string" or type(event) == "table" then
		if type(event) == "table" then
			if not delayRegistry[event] then
				AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
			end
		end
		if type(delay) ~= "number" then
			AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
			AceEvent:argCheck(..., 4, "number")
		end
	else
		AceEvent:argCheck(event, 2, "string", "function")
		AceEvent:argCheck(delay, 3, "number")
	end

	return ScheduleEvent(self, true, event, delay, ...)
end

function AceEvent:CancelScheduledEvent(t)
	AceEvent:argCheck(t, 2, "string", "table")
	local v = delayRegistry[t]
	if v then
		delayRegistry[t] = nil
		local v_self = v.self
		local parent = delayParents[v_self]
		if not parent then
			return true
		end
		parent[t] = nil
		if not next(parent) then
			delayParents[v_self] = del(parent)
			addonFrames[v_self]:Hide()
		end
		if type(t) == "string" then
			del(v)
		end
		return true
	end
	return false
end

function AceEvent:IsEventScheduled(t)
	AceEvent:argCheck(t, 2, "string", "table")
	local v = delayRegistry[t]
	if v then
		return true, v.time - GetTime()
	end
	return false, nil
end

function AceEvent:UnregisterEvent(event)
	AceEvent:argCheck(event, 2, "string")
	if registry[event] and registry[event][self] then
		registry[event][self] = nil
		if onceRegistry[event] and onceRegistry[event][self] then
			onceRegistry[event][self] = nil
			if not next(onceRegistry[event]) then
				onceRegistry[event] = del(onceRegistry[event])
			end
		end
		if throttleRegistry[event] and throttleRegistry[event][self] then
			throttleRegistry[event][self] = nil
			if not next(throttleRegistry[event]) then
				throttleRegistry[event] = del(throttleRegistry[event])
			end
		end
		if not next(registry[event]) then
			registry[event] = del(registry[event])
		end
		if type(self) == "function" or self == AceEvent then
			local has = false
			if event == "PLAYER_REGEN_ENABLED" then
				has = true
			else
				if registry[event] then
					for obj, event in pairs(registry[event]) do
						if type(obj) == "function" or obj == AceEvent then
							has = true
							break
						end
					end
				end
				if not has then
					if registry[ALL_EVENTS] then
						for obj, event in pairs(registry[ALL_EVENTS]) do
							if type(obj) == "function" or obj == AceEvent then
								has = true
								break
							end
						end
					end
					if not has then
						addonFrames[AceEvent]:UnregisterEvent(event)
					end
				end
			end
		else
			local has = false
			if registry[event] and registry[event][self] then
				has = true
			elseif registry[ALL_EVENTS] and registry[ALL_EVENTS][self] then
				has = true
			elseif event == "PLAYER_REGEN_ENABLED" and combatSchedules[self] then
				has = true
			end
			if not has then
				if not addonFrames[self] then
					-- HACK
					makeFrameForAddon(self)
				end
				addonFrames[self]:UnregisterEvent(event)
			end
		end
	else
		if self == AceEvent then
			error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2)
		else
			AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
		end
	end
	AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end

function AceEvent:UnregisterAllEvents()
	local addonFrame
	if type(self) == "function" then
		addonFrame = addonFrames[AceEvent]
	else
		if not addonFrames[self] then
			-- HACK
			makeFrameForAddon(self)
		end
		addonFrame = addonFrames[self]
	end
	if registry[ALL_EVENTS] and registry[ALL_EVENTS][self] then
		registry[ALL_EVENTS][self] = nil
		if not next(registry[ALL_EVENTS]) then
			registry[ALL_EVENTS] = del(registry[ALL_EVENTS])
		end
		if type(self) == "function" or self == AceEvent then
			addonFrame:UnregisterAllEvents()
			for event, data in pairs(registry) do
				local has = false
				for obj, method in pairs(data) do
					if type(obj) == "function" or obj == AceEvent then
						has = true
						break
					end
				end
				if has then
					addonFrame:RegisterEvent(event)
				end
			end
		else
			addonFrame:UnregisterAllEvents()
			for event, data in pairs(registry) do
				if data[self] then
					addonFrame:RegisterEvent(event)
				end
			end
		end
	end
	if registry.AceEvent_EventUnregistered then
		local event, data = "AceEvent_EventUnregistered", registry.AceEvent_EventUnregistered
		local x = data[self]
		data[self] = nil
		if x then
			if not next(data) then
				if not registry[ALL_EVENTS] then
					addonFrame:UnregisterEvent(event)
				end
				registry[event] = del(registry[event])
			end
			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
		end
	end
	for event, data in pairs(registry) do
		local x = data[self]
		data[self] = nil
		if x and event ~= ALL_EVENTS then
			if not next(data) then
				if not registry[ALL_EVENTS] then
					addonFrame:UnregisterEvent(event)
				end
				registry[event] = del(registry[event])
			end
			AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
		end
	end
	for event, data in pairs(onceRegistry) do
		data[self] = nil
	end
	if combatSchedules[self] or self == AceEvent or type(self) == "function" then
		addonFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
	end
end

function AceEvent:CancelAllScheduledEvents()
	for k,v in pairs(delayRegistry) do
		if v.self == self then
			if type(k) == "string" then
				del(delayRegistry[k])
			end
			delayRegistry[k] = nil
			local parent = delayParents[self]
			if not parent then
				return true
			end
			parent[k] = nil
			if not next(parent) then
				delayParents[self] = del(parent)
				addonFrames[self]:Hide()
			end
		end
	end
end

function AceEvent:IsEventRegistered(event)
	AceEvent:argCheck(event, 2, "string")
	if self == AceEvent then
		return registry[event] and next(registry[event]) and true or false
	end
	if registry[event] and registry[event][self] then
		return true, registry[event][self]
	end
	return false, nil
end

local UnitExists = UnitExists
local bucketfunc
function AceEvent:RegisterBucketEvent(event, delay, method, ...)
	AceEvent:argCheck(event, 2, "string", "table")
	if type(event) == "table" then
		for k,v in pairs(event) do
			if type(k) ~= "number" then
				AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
			elseif type(v) ~= "string" then
				AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
			end
		end
	end
	AceEvent:argCheck(delay, 3, "number")
	if AceEvent == self then
		AceEvent:argCheck(method, 4, "function")
		self = method
	else
		if type(event) == "string" then
			AceEvent:argCheck(method, 4, "string", "function", "nil")
			if not method then
				method = event
			end
		else
			AceEvent:argCheck(method, 4, "string", "function")
		end

		if type(method) == "string" and type(self[method]) ~= "function" then
			AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
		end
	end
	if not buckets[event] then
		buckets[event] = new()
	end
	if not buckets[event][self] then
		local t = new()
		t.current = new()
		t.self = self
		buckets[event][self] = t
	else
		AceEvent.CancelScheduledEvent(self, buckets[event][self].id)
	end
	local bucket = buckets[event][self]
	bucket.method = method
	
	local n = select('#', ...)
	if n > 0 then
		for i = 1, n do
			bucket[i] = select(i, ...)
		end
	end
	bucket.n = n

	local func = function(arg1)
		bucket.run = true
		if arg1 then
			bucket.current[arg1] = true
		end
	end
	buckets[event][self].func = func
	local isUnitBucket = true
	if type(event) == "string" then
		AceEvent.RegisterEvent(self, event, func)
		if not event:find("^UNIT_") then
			isUnitBucket = false
		end
	else
		for _,v in ipairs(event) do
			AceEvent.RegisterEvent(self, v, func)
			if isUnitBucket and not v:find("^UNIT_") then
				isUnitBucket = false
			end
		end
	end
	bucket.unit = isUnitBucket
	if not bucketfunc then
		bucketfunc = function(bucket)
			local current = bucket.current
			local method = bucket.method
			local self = bucket.self
			if bucket.run then
				if bucket.unit then
					for unit in pairs(current) do
						if not UnitExists(unit) then
							current[unit] = nil
						end
					end
				end
				if type(method) == "string" then
					self[method](self, current, unpack(bucket, 1, bucket.n))
				elseif method then -- function
					method(current, unpack(bucket, 1, bucket.n))
				end
				for k in pairs(current) do
					current[k] = nil
					k = nil
				end
				bucket.run = false
			end
		end
	end
	bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
end

function AceEvent:IsBucketEventRegistered(event)
	AceEvent:argCheck(event, 2, "string", "table")
	return buckets[event] and buckets[event][self]
end

function AceEvent:UnregisterBucketEvent(event)
	AceEvent:argCheck(event, 2, "string", "table")
	if not buckets or not buckets[event] or not buckets[event][self] then
		AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
	end

	local bucket = buckets[event][self]

	if type(event) == "string" then
		AceEvent.UnregisterEvent(self, event)
	else
		for _,v in ipairs(event) do
			AceEvent.UnregisterEvent(self, v)
		end
	end
	AceEvent:CancelScheduledEvent(bucket.id)

	bucket.current = del(bucket.current)
	buckets[event][self] = del(bucket)
	if not next(buckets[event]) then
		buckets[event] = del(buckets[event])
	end
end

function AceEvent:UnregisterAllBucketEvents()
	for k,v in pairs(buckets) do
		if v == self then
			AceEvent.UnregisterBucketEvent(self, k)
			k = nil
		end
	end
end

function AceEvent:CancelAllCombatSchedules()
	local combatSchedules_self = combatSchedules[self]
	if not combatSchedules_self then
		return
	end
	for i,v in ipairs(combatSchedules_self) do
		combatSchedules_self[i] = del(v)
	end
	combatSchedules[self] = del(combatSchedules_self)
end

local inCombat = false

function AceEvent:ScheduleLeaveCombatAction(method, ...)
	local style = type(method)
	if self == AceEvent then
		if style == "table" then
			local func = (...)
			AceEvent:argCheck(func, 3, "string")
			if type(method[func]) ~= "function" then
				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
			end
		else
			AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table")
		end
		self = method
	else
		AceEvent:argCheck(method, 2, "function", "string", "table")
		if style == "string" and type(self[method]) ~= "function" then
			AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method)
		elseif style == "table" then
			local func = (...)
			AceEvent:argCheck(func, 3, "string")
			if type(method[func]) ~= "function" then
				AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
			end
		end
	end
	
	if not inCombat then
		local success, err
		if type(method) == "function" then
			success, err = pcall(method, ...)
		elseif type(method) == "table" then
			local func = (...)
			success, err = pcall(method[func], method, select(2, ...))
		else
			success, err = pcall(self[method], self, ...)
		end
		if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
		return
	end
	local t
	local n = select('#', ...)
	if style == "table" then
		t = new(select(2, ...))
		t.obj = method
		t.method = (...)
		t.n = n-1
	else
		t = new(...)
		t.n = n
		if style == "function" then
			t.func = method
		else
			t.method = method
		end
	end
	t.self = self
	local combatSchedules_self = combatSchedules[self]
	if not combatSchedules_self then
		combatSchedules_self = new()
		combatSchedules[self] = combatSchedules_self
	end
	combatSchedules_self[#combatSchedules_self+1] = t
	if not addonFrames[self] then
		-- HACK
		makeFrameForAddon(self)
	end
	addonFrames[self]:RegisterEvent("PLAYER_REGEN_ENABLED")
end

function AceEvent:OnEmbedDisable(target)
	self.UnregisterAllEvents(target)

	self.CancelAllScheduledEvents(target)

	self.UnregisterAllBucketEvents(target)
	
	self.CancelAllCombatSchedules(target)
end

function AceEvent:EnableDebugging()
	if not self.debugTable then
		self.debugTable = {}
		AceEvent_debugTable = self.debugTable

		for k,v in pairs(self.delayRegistry) do
			if not v.mem then
				v.mem = 0
				v.count = 0
				v.timeSpent = 0
			end
		end
	end
end

function AceEvent:IsFullyInitialized()
	return self.postInit or false
end

if WoW21 then
	function AceEvent:IsPostPlayerLogin()
		return IsLoggedIn() and true or false
	end
else
	function AceEvent:IsPostPlayerLogin()
		return self.playerLogin or false
	end
end

local inPlw = false
local blacklist = {
	UNIT_INVENTORY_CHANGED = true,
	BAG_UPDATE = true,
	ITEM_LOCK_CHANGED = true,
	ACTIONBAR_SLOT_CHANGED = true,
}
local function runEvent(obj, event, ...)
	local registry_event_obj = registry[event] and registry[event][obj]
	local registry_ALL_EVENTS_obj = registry[ALL_EVENTS] and registry[ALL_EVENTS][obj]
	
	if not registry_event_obj and not registry_ALL_EVENTS_obj then
		return true
	end
	
	local lastEvent = AceEvent.currentEvent
	AceEvent.currentEvent = event

	if onceRegistry[event] and onceRegistry[event][obj] then
		local mem, time
		if AceEvent_debugTable then
			if not AceEvent_debugTable[event] then
				AceEvent_debugTable[event] = {}
			end
			if not AceEvent_debugTable[event][obj] then
				AceEvent_debugTable[event][obj] = {
					mem = 0,
					time = 0,
					count = 0,
				}
			end
			if memdiff then
				table.insert(memstack, memdiff)
				table.insert(timestack, timediff)
			end
			memdiff, timediff = 0, 0
			mem, time = gcinfo(), GetTime()
		end
	
		local method = registry_event_obj
		AceEvent.UnregisterEvent(obj, event)
		if type(method) == "string" then
			local obj_method = obj[method]
			if obj_method then
				local success, err = pcall(obj_method, obj, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
		elseif method then -- function
			local success, err = pcall(method, ...)
			if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
		end
	
		if AceEvent_debugTable then
			local dmem, dtime = memdiff, timediff
			mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
			AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
			AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
			AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

			memdiff, timediff = table.remove(memstack), table.remove(timestack)
			if memdiff then
				memdiff = memdiff + mem + dmem
				timediff = timediff + time + dtime
			end
		end
	elseif registry_event_obj then
		local method = registry_event_obj
		local throttleTable = throttleRegistry[event]
		local throttleTable_obj = throttleTable and throttleTable[obj]
		local continue = false
		if throttleTable_obj then
			local a1 = ...
			if a1 == nil then
				a1 = FAKE_NIL
			end
			if not throttleTable_obj[a1] or GetTime() - throttleTable_obj[a1] >= throttleTable_obj[RATE] then
				throttleTable_obj[a1] = GetTime()
			else
				continue = true
			end
		end
		if not continue then
			local mem, time
			if AceEvent_debugTable then
				if not AceEvent_debugTable[event] then
					AceEvent_debugTable[event] = {}
				end
				if not AceEvent_debugTable[event][obj] then
					AceEvent_debugTable[event][obj] = {
						mem = 0,
						time = 0,
						count = 0,
					}
				end
				if memdiff then
					table.insert(memstack, memdiff)
					table.insert(timestack, timediff)
				end
				memdiff, timediff = 0, 0
				mem, time = gcinfo(), GetTime()
			end
		
			if type(method) == "string" then
				local obj_method = obj[method]
				if obj_method then
					local success, err = pcall(obj_method, obj, ...)
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				end
			elseif method then -- function
				local success, err = pcall(method, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end

			if AceEvent_debugTable then
				local dmem, dtime = memdiff, timediff
				mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
				AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
				AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
				AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

				memdiff, timediff = table.remove(memstack), table.remove(timestack)
				if memdiff then
					memdiff = memdiff + mem + dmem
					timediff = timediff + time + dtime
				end
			end
		end
	end

	if registry_ALL_EVENTS_obj then
		local mem, time
		if AceEvent_debugTable then
			if not AceEvent_debugTable[event] then
				AceEvent_debugTable[event] = {}
			end
			if not AceEvent_debugTable[event][obj] then
				AceEvent_debugTable[event][obj] = {
					mem = 0,
					time = 0,
					count = 0,
				}
			end
			if memdiff then
				table.insert(memstack, memdiff)
				table.insert(timestack, timediff)
			end
			memdiff, timediff = 0, 0
			mem, time = gcinfo(), GetTime()
		end
	
		local method = registry_ALL_EVENTS_obj
		if type(method) == "string" then
			local obj_method = obj[method]
			if obj_method then
				local success, err = pcall(obj_method, obj, ...)
				if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
			end
		elseif method then -- function
			local success, err = pcall(method, ...)
			if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
		end

		if AceEvent_debugTable then
			local dmem, dtime = memdiff, timediff
			mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
			AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
			AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
			AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1

			memdiff, timediff = table.remove(memstack), table.remove(timestack)
			if memdiff then
				memdiff = memdiff + mem + dmem
				timediff = timediff + time + dtime
			end
		end
	end

	AceEvent.currentEvent = lastEvent
end

local tmp = {}
local function frame_OnEvent(this, event, ...)
	if inPlw and blacklist[event] then
		return
	end
	local obj = this.obj
	
	if event == "PLAYER_REGEN_ENABLED" then
		local combatSchedules_obj = combatSchedules[obj]
		if combatSchedules_obj then
			for i, v in ipairs(combatSchedules_obj) do
				tmp[i] = v
				combatSchedules_obj[i] = nil
			end
			combatSchedules[obj] = del(combatSchedules_obj)
			for i, v in ipairs(tmp) do
				local func = v.func
				if func then
					local success, err = pcall(func, unpack(v, 1, v.n))
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				else
					local obj = v.obj or v.self
					local method = v.method
					local obj_method = obj[method]
					if obj_method then
						local success, err = pcall(obj_method, obj, unpack(v, 1, v.n))
						if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
					end
				end
				tmp[i] = del(v)
			end
			
			if obj ~= AceEvent then
				local registry_event_obj = registry[event] and registry[event][obj]
				local registry_ALL_EVENTS_obj = registry[ALL_EVENTS] and registry[ALL_EVENTS][obj]
				if not registry_event_obj and not registry_ALL_EVENTS_obj then
					this:UnregisterEvent(event)
					return
				end
			end
		end
	end
	
	if obj == AceEvent then
		local registry_event = registry[event]
		if registry_event then
			for obj, method in pairs(registry_event) do
				tmp[obj] = method
			end
			for obj, method in pairs(tmp) do
				tmp[obj] = nil
				if type(obj) == "function" then
					runEvent(obj, event, ...)
				elseif obj == AceEvent then
					runEvent(obj, event, ...)
				end
			end
		end
		return
	else
		if runEvent(obj, event, ...) then
			this:UnregisterEvent(event)
		end
	end
end

local function frame_OnUpdate(this, elapsed)
	local obj = this.obj
	local list = delayParents[obj]
	if not list then
		this:Hide()
		return
	end
	local t = GetTime()
	for k in pairs(list) do
		tmp[k] = true
	end
	for k in pairs(tmp) do
		tmp[k] = nil
		local v = delayRegistry[k]
		if v then
			local v_time = v.time
			if not v_time then
				delayRegistry[k] = nil
				list[k] = nil
			elseif v_time <= t then
				local v_repeatDelay = v.repeatDelay
				if v_repeatDelay then
					-- use the event time, not the current time, else timing inaccuracies add up over time
					v.time = v_time + v_repeatDelay
				end
				local event = v.event
				local mem, time
				if AceEvent_debugTable then
					mem, time = gcinfo(), GetTime()
				end
				if type(event) == "function" then
					local success, err = pcall(event, unpack(v, 1, v.n))
					if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
				else
					AceEvent:TriggerEvent(event, unpack(v, 1, v.n))
				end
				if AceEvent_debugTable then
					mem, time = gcinfo() - mem, GetTime() - time
					v.mem = v.mem + mem
					v.timeSpent = v.timeSpent + time
					v.count = v.count + 1
				end
				if not v_repeatDelay then
					local x = delayRegistry[k]
					if x and x.time == v_time then -- check if it was manually reset
						if type(k) == "string" then
							del(delayRegistry[k])
						end
						delayRegistry[k] = nil
						list[k] = nil
					end
				end
			end
		end
	end
	if not next(list) then
		delayParents[obj] = del(list)
		this:Hide()
	end
end

function makeFrameForAddon(self)
	local frame = CreateFrame("Frame")
	addonFrames[self] = frame
	frame.obj = obj
	frame:SetScript("OnEvent", frame_OnEvent)
	frame:SetScript("OnUpdate", frame_OnUpdate)
	frame:RegisterAllEvents()
end

function AceEvent:OnInstanceInit(obj)
	if not addonFrames[obj] then
		local frame = CreateFrame("Frame")
		addonFrames[obj] = frame
		frame.obj = obj
		frame:SetScript("OnEvent", frame_OnEvent)
		frame:SetScript("OnUpdate", frame_OnUpdate)
		frame:Hide()
	end
end
AceEvent.OnManualEmbed = AceEvent.OnInstanceInit

local function activate(self, oldLib, oldDeactivate)
	AceEvent = self
	
	if oldLib and select(2,oldLib:GetLibraryVersion()) < 33494 then
		if StaticPopupDialogs and not StaticPopupDialogs["AceUpgradeAlert33494"] then
			StaticPopupDialogs["AceUpgradeAlert33494"] = {
				text = ("Error with AceEvent-2.0 upgrade path. Please upgrade all your AceEvent-2.0 instances to revision %d or install the Ace2 standalone from http://files.wowace.com/"):format(MINOR_VERSION),
				button1 = TEXT(CLOSE) or "Close",
				showAlert = 1,
				timeout = 0,
				hideOnEscape = 1,
				whileDead = 1,
			}
			StaticPopup_Show("AceUpgradeAlert33494")
		end
		return
	end
	
	self.onceRegistry = oldLib and oldLib.onceRegistry or {}
	onceRegistry = self.onceRegistry
	self.throttleRegistry = oldLib and oldLib.throttleRegistry or {}
	throttleRegistry = self.throttleRegistry
	self.delayRegistry = oldLib and oldLib.delayRegistry or {}
	delayRegistry = self.delayRegistry
	self.buckets = oldLib and oldLib.buckets or {}
	buckets = self.buckets
	self.registry = oldLib and oldLib.registry or {}
	registry = self.registry
	self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame")
	self.frame:SetScript("OnEvent", nil)
	self.frame:SetScript("OnUpdate", nil)
	self.debugTable = oldLib and oldLib.debugTable
	if WoW21 then
		self.playerLogin = IsLoggedIn() and true
	else
		self.playerLogin = oldLib and oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
	end
	self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
	self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or {}
	ALL_EVENTS = self.ALL_EVENTS
	self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or {}
	FAKE_NIL = self.FAKE_NIL
	self.RATE = oldLib and oldLib.RATE or {}
	RATE = self.RATE
	self.combatSchedules = oldLib and oldLib.combatSchedules or {}
	combatSchedules = self.combatSchedules
	self.addonFrames = oldLib and oldLib.addonFrames or {}
	addonFrames = self.addonFrames
	addonFrames[self] = self.frame
	for id, t in pairs(delayRegistry) do
		if not delayParents[t.self] then
			delayParents[t.self] = new()
		end
		delayParents[t.self][id] = t
	end
	if oldLib and oldLib.embedList then
		for obj in pairs(oldLib.embedList) do
			if not addonFrames[obj] then
				self:OnManualEmbed(obj)
				assert(addonFrames[obj])
			end
		end
	end
	for event, data in pairs(registry) do
		for obj, method in pairs(data) do
			if type(obj) == "table" then
				if not addonFrames[obj] then
					self:OnManualEmbed(obj)
					assert(addonFrames[obj])
				end
				if event == event:upper() then
					addonFrames[obj]:RegisterEvent(event)
				end
			end
		end
	end
	for obj, frame in pairs(addonFrames) do
		frame.obj = obj
		frame:SetScript("OnEvent", frame_OnEvent)
		frame:SetScript("OnUpdate", frame_OnUpdate)
		if delayParents[obj] then
			frame:Show()
		else
			frame:Hide()
		end
		frame:RegisterEvent("PLAYER_REGEN_ENABLED")
	end
	for k,v in pairs(combatSchedules) do
		tmp[k] = v
		combatSchedules[k] = nil
	end
	for k,v in pairs(tmp) do
		if type(k) == "number" then
			local obj = v.self
			if obj then
				local combatSchedules_obj = combatSchedules[obj]
				if not combatSchedules_obj then
					combatSchedules_obj = new()
					combatSchedules[obj] = combatSchedules_obj
				end
				combatSchedules_obj[#combatSchedules_obj+1] = v
			end
		end
		tmp[k] = nil
	end
	
	self:UnregisterAllEvents()
	self:CancelAllScheduledEvents()
	
	registeringFromAceEvent = true
	self:RegisterEvent("PLAYER_ENTERING_WORLD", function()
		inPlw = false
	end)
	self:RegisterEvent("PLAYER_LEAVING_WORLD", function()
		inPlw = true
	end)
	self:RegisterEvent("PLAYER_REGEN_DISABLED", function()
		inCombat = true
	end)
	self:RegisterEvent("PLAYER_REGEN_ENABLED", function()
		inCombat = false
	end)
	inCombat = InCombatLockdown()

	self:RegisterEvent("LOOT_OPENED", function()
		SendAddonMessage("LOOT_OPENED", "", "RAID")
	end)
	registeringFromAceEvent = nil

	local function handleFullInit()
		if not self.postInit then
			local function func()
				self.postInit = true
				self:TriggerEvent("AceEvent_FullyInitialized")
				if registry["CHAT_MSG_CHANNEL_NOTICE"] and registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
					self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
				end
				if registry["MEETINGSTONE_CHANGED"] and registry["MEETINGSTONE_CHANGED"][self] then
					self:UnregisterEvent("MEETINGSTONE_CHANGED")
				end
				if registry["MINIMAP_ZONE_CHANGED"] and registry["MINIMAP_ZONE_CHANGED"][self] then
					self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
				end
				if registry["LANGUAGE_LIST_CHANGED"] and registry["LANGUAGE_LIST_CHANGED"][self] then
					self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
				end
				collectgarbage('collect')
			end
			registeringFromAceEvent = true
			local f = function()
				self.playerLogin = true
				self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
			end
			self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
			self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
				self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15)
			end)
			self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
				if registry["MEETINGSTONE_CHANGED"] and registry["MEETINGSTONE_CHANGED"][self] then
					registeringFromAceEvent = true
					self:UnregisterEvent("MEETINGSTONE_CHANGED")
					self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true)
					registeringFromAceEvent = nil
				end
			end)
			self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
			registeringFromAceEvent = nil
		end
	end
	
	if not self.playerLogin then
		registeringFromAceEvent = true
		self:RegisterEvent("PLAYER_LOGIN", function()
			self.playerLogin = true
			handleFullInit()
			handleFullInit = nil
			collectgarbage('collect')
		end, true)
		registeringFromAceEvent = nil
	else
		handleFullInit()
		handleFullInit = nil
	end

	self:activate(oldLib, oldDeactivate)
	if oldLib then
		oldDeactivate(oldLib)
	end
end

AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)

end
