Index: Damage/Damage.lua
===================================================================
--- Damage/Damage.lua	(revision 39414)
+++ Damage/Damage.lua	(working copy)
@@ -16,10 +16,6 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = 0
-local dirty = nil
 local moduleName = "Damage"
 
 local parser = ParserLib:GetInstance("1.1")
@@ -32,75 +28,31 @@
 local mod = Violation:NewModule(moduleName)
 mod.revision = tonumber(("$Revision$"):sub(12, -3)) or 1
 mod.version = 4
-mod.canMergeData = true
 mod.violationCategory = "damage"
 
 -----------------------------------------------------------------------
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = self:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "hit", self.OnParserEvent)
+	parser:RegisterInfoType(self, "hit", "OnParserEvent")
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName)
+	parser:UnregisterAllInfoTypes(self)
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = self:del(data)
-	end
-
-	data = self:new()
-	data[playerName] = 0
-	dirty = nil
-	broadcastdirty = 0
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Damage done"] end
 function mod:GetShortDisplayName() return L["D"] end
-function mod:GetBroadcastData()
-	local x = broadcastdirty
-	broadcastdirty = 0
-	return x
-end
 
-function mod:IsBroadcastDirty()
-	return broadcastdirty > 0 and true or false
-end
-
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
-function mod:OnParserEvent( info, event )
-	local source, amount, victim = info.source, info.amount, info.victim
+function mod:OnParserEvent( infoType, info, event )
+	local source, victim, amount = self:GetSourceVictimAmount(info)
 	
-	if Violation:IsAnonymousPetEvent(event, info) then
-		source = ParserLib_SELF
-	end
-
-	if not source or source == ParserLib_NONE or not amount or amount == 0 then
+	if not source or amount == 0 or not self:AcceptDataFor(source) then
 		return
 	end
 
@@ -108,24 +60,14 @@
 	-- this includes soullink damage from you to your pet.
 	-- thanks rophy for pointing this out.
 	if info.isSplit and victim then
-		if victim == ParserLib_SELF or roster:GetUnitIDFromName( victim ) then
+		if victim == playerName or roster:GetUnitIDFromName( victim ) then
 			return
 		end
 	end
 
-	if source == ParserLib_SELF then
-		broadcastdirty = broadcastdirty + amount
-		data[playerName] = data[playerName] + amount
-		dirty = true
-	elseif Violation:AcceptDataFromSource( source, moduleName ) then
-		mod:OnRemoteData( source, amount )
+	if Violation:IsAnonymousPetEvent(event, info) then
+		source = self.playerName
 	end
-end
 
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
+	self:OnData(source, amount)
 end
Index: Damage/DamageTaken.lua
===================================================================
--- Damage/DamageTaken.lua	(revision 39414)
+++ Damage/DamageTaken.lua	(working copy)
@@ -16,15 +16,8 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local position = nil
-local dirty = nil
-local broadcastdirty = 0
 local moduleName = "DamageTaken"
-
 local parser = ParserLib:GetInstance("1.1")
-local roster = AceLibrary("Roster-2.1")
 
 -----------------------------------------------------------------------
 -- Module declaration
@@ -33,89 +26,31 @@
 local mod = Violation:NewModule(moduleName)
 mod.revision = tonumber(("$Revision$"):sub(12, -3)) or 1
 mod.version = 4
-mod.canMergeData = true
 mod.violationCategory = "damage"
 
 -----------------------------------------------------------------------
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType( moduleName, "hit", mod.OnParserEvent)
-	parser:RegisterInfoType( moduleName, "environment", mod.OnParserEvent)
+	parser:RegisterInfoType( self, "hit", self.OnParserEvent)
+	parser:RegisterInfoType( self, "environment", self.OnParserEvent)
 end
 
 function mod:OnModuleDisable()
 	parser:UnregisterAllInfoTypes(moduleName)
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-
-	data = mod:new()
-	data[playerName] = 0
-	dirty = nil
-	broadcastdirty = 0
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return mod.revision end
 function mod:GetDisplayName() return L["Damage taken"] end
 function mod:GetShortDisplayName() return L["DT"] end
-function mod:GetBroadcastData()
-	local x = broadcastdirty
-	broadcastdirty = 0
-	return x
-end
 
-function mod:IsDirty()
-	return dirty
+function mod:OnParserEvent( infoType, info, event )
+	local victim, amount = select(2, self:GetSourceVictimAmount(info))
+	if victim and amount > 0 and self:AcceptDataFor(victim) then
+		self:OnData(victim, amount)
+	end	
 end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:IsBroadcastDirty()
-	return broadcastdirty > 0 and true or false
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
-function mod:OnParserEvent( info, event )
-	local victim, amount = info.victim, info.amount
-
-	if not victim or victim == ParserLib_NONE or not amount or amount == 0 then
-		return
-	end
-	if victim == ParserLib_SELF then
-		data[playerName] = data[playerName] + amount
-		broadcastdirty = broadcastdirty + amount
-		dirty = true
-	elseif Violation:AcceptDataFromSource( victim, moduleName ) then
-		mod:OnRemoteData( victim, amount )
-	end
-end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
-
Index: Damage/DPS.lua
===================================================================
--- Damage/DPS.lua	(revision 39414)
+++ Damage/DPS.lua	(working copy)
@@ -16,14 +16,9 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = nil
-local dirty = nil
 local seconds = nil
 local damageDone = nil
 local moduleName = "DPS"
-local isInCombat = {}
 local combatStartTime = {}
 local lastShotTime = {}
 
@@ -31,6 +26,7 @@
 
 local roster = AceLibrary("Roster-2.1")
 local parser = ParserLib:GetInstance("1.1")
+local combatEvents = AceLibrary("CombatEvents-1.0")
 
 -----------------------------------------------------------------------
 -- Module declaration
@@ -46,29 +42,17 @@
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "hit", self.OnParserEvent)
-	mod:RegisterEvent("PLAYER_REGEN_ENABLED") -- handle player dps time via regen enabled
-	mod:ScheduleRepeatingEvent( self.CheckPartyCombat, 1, self )
+	parser:RegisterInfoType(self, "hit", "OnParserEvent")
+	self:RegisterEvent("CombatEvents_UnitStopped", "ResetDPSTimer")
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName)
+	parser:UnregisterAllInfoTypes(self)
+	self:UnregisterAllEvents()
 end
 
 function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-
-	data = mod:new()
-	data[playerName] = 0
-	
 	if type(seconds) == "table" then
 		seconds = mod:del(seconds)
 	end
@@ -78,129 +62,117 @@
 		damageDone = mod:del(damageDone)
 	end
 	damageDone = mod:new()
-	dirty = nil
-	broadcastdirty = nil
 end
 
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Damage per Second"] end
 function mod:GetShortDisplayName() return L["DPS"] end
-function mod:GetBroadcastData()
-	broadcastdirty = nil
-	return data[playerName]
+
+function mod:OnRemoteData(name, input)
+	if name and input then
+		self.dirty = (input ~= (self.data[name] or 0))
+		self.data[name] = input
+	end
 end
 
-function mod:IsDirty()
-	return dirty
+function mod:OnData(name, input)
+	if not self:IsLocal(name) and self.data[name] then
+		return
+	end	
+	self.data[name] = nil
+	self.broadcastdirty = self:IsLocal(name)
+	self.dirty = true
 end
 
-function mod:ResetDirty()
-	dirty = nil
+function mod:IsDirty()
+	return self.dirty or combatEvents:IsGroupInCombat()
 end
 
 function mod:IsBroadcastDirty()
-	return broadcastdirty
+	return self.broadcastdirty or combatEvents:IsGroupInCombat()
 end
 
-function mod:OnRemoteData(sender, input)
-	if data[sender] ~= input then
-		data[sender] = input
-		dirty = true
-	end
-end
-
 local function getDuration(name)
 	local duration = seconds[name] or 0
 	if combatStartTime[name] then
-		duration = duration + math.max((lastShotTime[name] or GetTime()) - combatStartTime[name], 1.5)
+		duration = duration + math.max(lastShotTime[name] - combatStartTime[name], 1.5)
 	end
-	return math.max(duration, 1.5)
+	return math.max(duration, 1.5) 
 end
 
-function mod:ResetDPSTimer(name)
-	seconds[name] =  getDuration(name)
-	
-	combatStartTime[name] = nil
-	lastShotTime[name] = nil
-	
-	mod:UpdateDPS(name)
+local function calculateData(name)
+	return math.floor((damageDone[name] or 0) / getDuration(name))
 end
 
-function mod:PLAYER_REGEN_ENABLED()
-	mod:ResetDPSTimer( playerName )
+local moduleData
+function mod:GetData(name)
+	if name then
+		return self.data[name] or calculateData(name)
+	else
+		moduleData = self:del(moduleData)
+		moduleData = self:new()
+		for name in pairs(damageDone) do
+			moduleData[name] = calculateData(name)
+		end
+		for name, value in pairs(self.data) do
+			moduleData[name] = value 
+		end
+		return moduleData
+	end
 end
 
+function mod:GetBroadcastData()
+	return self:GetData(self.playerName)
+end
+
 function mod:UpdateDPS(name)
-	local newDPS = math.floor((damageDone[name] or 0) / getDuration(name))
-	if name == playerName then
-		if newDPS ~= data[name] then
-			data[name], broadcastdirty, dirty = newDPS, true, true
-		end
-	else
-		mod:OnRemoteData( name, newDPS )
-	end
+	self:OnData(name, true)
 end
 
-function mod:OnParserEvent( info, event )
-	local name, amount, victim = info.source, info.amount, info.victim
+function mod:ResetDPSTimer(name)
+	if combatStartTime[name] then
+		seconds[name] = getDuration(name)
+		
+		combatStartTime[name] = nil
+		lastShotTime[name] = nil
+		
+		self:UpdateDPS(name)
+	end	
+end
 
-	if Violation:IsAnonymousPetEvent(event, info) then
-		name = ParserLib_SELF
+function mod:CheckDPSTimer(name)
+	if lastShotTime[name] and lastShotTime[name] + COMBAT_TIMEOUT < GetTime() then
+		self:ResetDPSTimer(name)
 	end
+end
 
-	if not name or name == ParserLib_NONE or not amount or amount == 0 then
-		return
-	end
+function mod:OnParserEvent( infoType, info, event )
+	local name, victim, amount = self:GetSourceVictimAmount(info)
 
-	if not Violation:AcceptDataFromSource( name, moduleName ) then
+	if not name or amount == 0 or not self:AcceptDataFor( name ) then
 		return
 	end
 	
 	-- We ignore split damage from known units to known units.
 	-- this includes soullink damage from you to your pet.
 	-- thanks rophy for pointing this out.
-	if info.isSplit and victim then
-		if victim == ParserLib_SELF or roster:GetUnitIDFromName( victim ) then
-			return
-		end
+	if info.isSplit and victim and (victim == self.playerName or roster:GetUnitIDFromName( victim )) then
+		return
 	end
-	
-	if name == ParserLib_SELF then
-		name = playerName
+
+	if Violation:IsAnonymousPetEvent(event, info) then
+		name = self.playerName
 	end
- 	local newTime = GetTime()
-	if lastShotTime[name] and lastShotTime[name] + COMBAT_TIMEOUT < newTime then
-		mod:ResetDPSTimer(name)
-	end
 	
+ 	self:CheckDPSTimer(name)
+	
+ 	local newTime = GetTime()
 	combatStartTime[name] = combatStartTime[name] or newTime
 	lastShotTime[name] = newTime
 	damageDone[name] = ( damageDone[name] or 0 ) + amount
 	
-	mod:UpdateDPS(name)
+	self:UpdateDPS(name)
 end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
-function mod:CheckPartyCombat()
-	for name, unit in pairs( roster.roster ) do
-		if isInCombat[name] and not UnitAffectingCombat( unit.unitid ) then
-			isInCombat[name] = nil
-			mod:ResetDPSTimer( name )
-		elseif isInCombat[name] and lastShotTime[name] and lastShotTime[name] + COMBAT_TIMEOUT < GetTime() then
-			mod:ResetDPSTimer(name)
-		elseif not isInCombat[name] and UnitAffectingCombat( unit.unitid ) then
-			isInCombat[name] = true
-		end
-	end
-end
Index: Healing/Healing.lua
===================================================================
--- Healing/Healing.lua	(revision 39414)
+++ Healing/Healing.lua	(working copy)
@@ -25,9 +25,6 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local data = nil
-local broadcastdirty = 0
-local dirty = nil
 local moduleName = "Healing"
 
 -----------------------------------------------------------------------
@@ -37,66 +34,27 @@
 local mod = Violation:NewModule(moduleName, "AceEvent-2.0")
 mod.revision = tonumber(("$Revision$"):sub(12, -3)) or 1
 mod.version = 4
-mod.canMergeData = true
 mod.violationCategory = "healing"
 
 -----------------------------------------------------------------------
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "heal", self.OnParserEvent)
+	parser:RegisterInfoType(self, "heal", self.OnParserEvent)
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName)
+	parser:UnregisterAllInfoTypes(self)
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-	data = mod:new()
-	data[playerName] = 0
-	broadcastdirty = 0
-	dirty = nil
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Healing done"] end
 function mod:GetShortDisplayName() return L["H"] end
-function mod:GetBroadcastData()
-	local x = broadcastdirty
-	broadcastdirty = 0
-	return x
-end
 
-function mod:IsBroadcastDirty()
-	return broadcastdirty > 0 and true or false
-end
-
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
 local function getOverheal( unit, amount )
 	local overheal = 0
 	if unit and UnitExists(unit) then
@@ -108,40 +66,14 @@
 	return overheal
 end
 
-function mod:OnParserEvent( info, event )
-	local source, amount, victim = info.source, info.amount, info.victim
-
-	if not source or source == ParserLib_NONE or not amount or amount == 0 or not victim then
+function mod:OnParserEvent( infoType, info, event )
+	local source, victim, amount = self:GetSourceVictimAmount(info)
+	
+	if not source or not victim or amount == 0 or not self:AcceptDataFor( source ) then
 		return
 	end
 
-	if not Violation:AcceptDataFromSource( source, moduleName ) then
-		return
-	end
-
-	local victimid
-	if victim == ParserLib_SELF then
-		victimid = "player"
-	else
-		victimid = roster:GetUnitIDFromName( victim )
-	end
-
+	local victimid = roster:GetUnitIDFromName( victim )
 	amount = amount - getOverheal( victimid, amount )
-	if amount > 0 then
-		if source == ParserLib_SELF then
-			data[playerName] = data[playerName] + amount
-			broadcastdirty = broadcastdirty + amount
-			dirty = true
-		else 
-			mod:OnRemoteData( source, amount )
-		end
-	end
+	self:OnData(source, amount)
 end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
Index: Healing/HealingTaken.lua
===================================================================
--- Healing/HealingTaken.lua	(revision 39414)
+++ Healing/HealingTaken.lua	(working copy)
@@ -16,12 +16,6 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-
-local data = nil
-local position = nil
-local dirty = nil
-local broadcastdirty = 0
 local moduleName = "HealingTaken"
 
 local parser = ParserLib:GetInstance("1.1")
@@ -34,68 +28,27 @@
 local mod = Violation:NewModule(moduleName)
 mod.revision = tonumber(("$Revision$"):sub(12, -3)) or 1
 mod.version = 4
-mod.canMergeData = true
-mod.hidePercentage = true
 mod.violationCategory = "healing"
 
 -----------------------------------------------------------------------
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "heal", self.OnParserEvent)
+	parser:RegisterInfoType(self, "heal", self.OnParserEvent)
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName)
+	parser:UnregisterAllInfoTypes(self)
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-
-	data = mod:new()
-	data[playerName] = 0
-	broadcastdirty = 0
-	dirty = nil
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Healing taken"] end
 function mod:GetShortDisplayName() return L["HT"] end
-function mod:GetBroadcastData()
-	local x = broadcastdirty
-	broadcastdirty = 0
-	return x
-end
 
-function mod:IsBroadcastDirty()
-	return broadcastdirty > 0 and true or false
-end
-
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
 local function getOverheal( unit, amount )
 	local overheal = 0
 	if unit and UnitExists(unit) then
@@ -107,39 +60,14 @@
 	return overheal
 end
 
-function mod:OnParserEvent( info, event )
-	local victim, amount = info.victim, info.amount
-
-	if not victim or victim == ParserLib_NONE or not amount or amount == 0 then
+function mod:OnParserEvent( infoType, info, event )
+	local victim, amount = select(2, self:GetSourceVictimAmount(info))
+	
+	if not victim or amount == 0 or not self:AcceptDataFor( victim ) then
 		return
 	end
-	if not Violation:AcceptDataFromSource( victim, moduleName ) then
-		return
-	end
-	local victimid
-	if victim == ParserLib_SELF then
-		victimid = "player"
-	else
-		victimid = roster:GetUnitIDFromName( victim )
-	end
+
+	local victimid = roster:GetUnitIDFromName( victim )
 	amount = amount - getOverheal( victimid, amount )
-	if amount > 0 then
-		if victim == ParserLib_SELF then
-			broadcastdirty = broadcastdirty + amount
-			data[playerName] = data[playerName] + amount
-			dirty = true
-		else
-			mod:OnRemoteData( victim, amount )			
-		end
-	end
+	self:OnData(victim, amount)
 end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
-
Index: Healing/HPS.lua
===================================================================
--- Healing/HPS.lua	(revision 39414)
+++ Healing/HPS.lua	(working copy)
@@ -16,11 +16,6 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-
-local data = nil
-local dirty = nil
-local broadcastdirty = nil
 local seconds = nil
 local healingDone = nil
 local moduleName = "HPS"
@@ -32,6 +27,7 @@
 
 local roster = AceLibrary("Roster-2.1")
 local parser = ParserLib:GetInstance("1.1")
+local combatEvents = AceLibrary("CombatEvents-1.0")
 
 -----------------------------------------------------------------------
 -- Module declaration
@@ -47,30 +43,17 @@
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "heal", self.OnParserEvent)
-	
-	mod:RegisterEvent("PLAYER_REGEN_ENABLED") -- handle player dps time via regen enabled
-	mod:ScheduleRepeatingEvent( self.CheckPartyCombat, 1, self )
+	parser:RegisterInfoType(self, "heal", "OnParserEvent")
+	self:RegisterEvent("CombatEvents_UnitStopped", "ResetHPSTimer")
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName )
+	parser:UnregisterAllInfoTypes(self)
+	self:UnregisterAllEvents()
 end
 
 function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-
-	data = mod:new()
-	data[playerName] = 0
-	
 	if type(seconds) == "table" then
 		seconds = mod:del(seconds)
 	end
@@ -80,33 +63,37 @@
 		healingDone = mod:del(healingDone)
 	end
 	healingDone = mod:new()
-
-	dirty = nil
-	broadcastdirty = nil
 end
 
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Healing per Second"] end
 function mod:GetShortDisplayName() return L["HPS"] end
-function mod:GetBroadcastData()
-	broadcastdirty = nil
-	return data[playerName]
+
+function mod:OnRemoteData(name, input)
+	if name and input then
+		self.dirty = (input ~= (self.data[name] or 0))
+		self.data[name] = input
+	end
 end
 
-function mod:IsBroadcastDirty()
-	return broadcastdirty
+function mod:OnData(name, input)
+	if not self:IsLocal(name) and self.data[name] then
+		return
+	end	
+	self.data[name] = nil
+	self.broadcastdirty = self:IsLocal(name)
+	self.dirty = true
 end
 
 function mod:IsDirty()
-	return dirty
+	return self.dirty or combatEvents:IsGroupInCombat()
 end
 
-function mod:ResetDirty()
-	dirty = nil
+function mod:IsBroadcastDirty()
+	return self.broadcastdirty or combatEvents:IsGroupInCombat()
 end
 
 local function getDuration(name)
@@ -117,37 +104,52 @@
 	return math.max(duration, 1.5)
 end
 
-function mod:OnRemoteData(sender, input)
-	if data[sender] ~= input then
-		data[sender] = input
-		dirty = true
-	end
+local function calculateData(name)
+	return math.floor((healingDone[name] or 0) / getDuration(name))
 end
 
-function mod:ResetHPSTimer(name)
-	seconds[name] = getDuration(name)
-	
-	combatStartTime[name] = nil
-	lastHealTime[name] = nil
-	
-	mod:UpdateHPS(name)
+local moduleData
+function mod:GetData(name)
+	if name then
+		return self.data[name] or calculateData(name)
+	else
+		moduleData = self:del(moduleData)
+		moduleData = self:new()
+		for name in pairs(healingDone) do
+			moduleData[name] = calculateData(name)
+		end
+		for name, value in pairs(self.data) do
+			moduleData[name] = value 
+		end
+		return moduleData
+	end
 end
 
-function mod:PLAYER_REGEN_ENABLED()
-	mod:ResetHPSTimer( playerName )
+function mod:GetBroadcastData()
+	return self:GetData(self.playerName)
 end
 
 function mod:UpdateHPS(name)
-	local newHPS = math.floor((healingDone[name] or 0) / getDuration(name))
-	if name == playerName then
-		if newHPS ~= data[name] then
-			data[name], dirty, broadcastdirty = newHPS, true, true
-		end
-	else 
-		mod:OnRemoteData( name, newHPS )
+	self:OnData(name, true)
+end
+
+function mod:ResetHPSTimer(name)
+	if combatStartTime[name] then
+		seconds[name] = getDuration(name)
+		
+		combatStartTime[name] = nil
+		lastHealTime[name] = nil
+		
+		self:UpdateHPS(name)
 	end
 end
 
+function mod:CheckHPSTimer(name)
+	if lastHealTime[name] and lastHealTime[name] + COMBAT_TIMEOUT < GetTime() then
+		self:ResetHPSTimer(name)
+	end
+end
+
 local function getOverheal( unit, amount )
 	local overheal = 0
 	if unit and UnitExists(unit) then
@@ -159,58 +161,22 @@
 	return overheal
 end
 
-function mod:OnParserEvent( info, event )
-	local name, amount, victim = info.source, info.amount, info.victim
+function mod:OnParserEvent( infoType, info, event )
+	local name, target, amount = self:GetSourceVictimAmount(info)
 
-	if not name or name == ParserLib_NONE or not victim or victim == ParserLib_NONE or not amount or amount == 0 then
+	if not name or not target or amount == 0 or not self:AcceptDataFor( name ) then
 		return
 	end
-	
-	if not Violation:AcceptDataFromSource( name, moduleName ) then
-		return
-	end
 
-	local victimid
-	if victimid == ParserLib_SELF then
-		victimid = "player"
-	else
-		victimid = roster:GetUnitIDFromName( victim ) 
-	end
+	local targetid = roster:GetUnitIDFromName( target )
+	amount = amount - getOverheal( targetid, amount )
 	
-	if name == ParserLib_SELF then
-		name = playerName
-	end
- 	local newTime = GetTime()
-	if lastHealTime[name] and lastHealTime[name] + COMBAT_TIMEOUT < newTime then
-		mod:ResetHPSTimer(name)
-	end
+	self:CheckHPSTimer()
 	
+ 	local newTime = GetTime()
 	combatStartTime[name] = combatStartTime[name] or newTime
 	lastHealTime[name] = newTime
-
-	amount = amount - getOverheal( victimid, amount )
 	healingDone[name] = ( healingDone[name] or 0 ) + amount	
 	
 	mod:UpdateHPS(name)
 end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
-function mod:CheckPartyCombat()
-	for name, unit in pairs( roster.roster ) do
-		if isInCombat[name] and not UnitAffectingCombat( unit.unitid ) then
-			isInCombat[name] = nil
-			mod:ResetHPSTimer( name )
-		elseif isInCombat[name] and lastHealTime[name] and lastHealTime[name] + COMBAT_TIMEOUT < GetTime() then
-			mod:ResetHPSTimer(name)			
-		elseif not isInCombat[name] and UnitAffectingCombat( unit.unitid ) then
-			isInCombat[name] = true
-		end
-	end
-end
Index: Healing/Overhealing.lua
===================================================================
--- Healing/Overhealing.lua	(revision 39414)
+++ Healing/Overhealing.lua	(working copy)
@@ -25,9 +25,6 @@
 -- Locals for  module
 -----------------------------------------------------------------------
 
-local data = nil
-local broadcastdirty = 0
-local dirty = nil
 local moduleName = "Overhealing"
 
 -----------------------------------------------------------------------
@@ -37,74 +34,26 @@
 local mod = Violation:NewModule(moduleName)
 mod.revision = tonumber(("$Revision$"):sub(12, -3)) or 1
 mod.version = 4
-mod.canMergeData = true
 mod.violationCategory = "healing"
 
 -----------------------------------------------------------------------
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "heal", self.OnParserEvent)
+	parser:RegisterInfoType(self, "heal", self.OnParserEvent)
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName)
+	parser:UnregisterAllInfoTypes(self)
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(Data)
-	end
-	data = mod:new()
-	data[playerName] = 0
-	broadcastdirty = 0
-	dirty = nil
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Overhealing done"] end
 function mod:GetShortDisplayName() return L["OH"] end
-function mod:GetBroadcastData()
-	local x = broadcastdirty
-	broadcastdirty = 0
-	return x
-end
-
-function mod:IsBroadcastDirty()
-	return broadcastdirty > 0 and true or false
-end
-
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
 local function getOverheal( unit, amount )
 	local overheal = 0
 	if unit and UnitExists(unit) then
@@ -116,34 +65,13 @@
 	return overheal
 end
 
-function mod:OnParserEvent( info, event )
-	local source, amount, victim = info.source, info.amount, info.victim
-
-	if not source or source == ParserLib_NONE or not amount or amount == 0 or not victim then
+function mod:OnParserEvent( infoType, info, event )
+	local source, victim, amount = self:GetSourceVictimAmount(info)
+	
+	if not source or not victim or amount == 0 or not self:AcceptDataFor( source ) then
 		return
 	end
 
-	if not Violation:AcceptDataFromSource( source, moduleName ) then
-		return
-	end
-
-	local victimid
-	if victim == ParserLib_SELF then
-		victimid = "player"
-	else
-		victimid = roster:GetUnitIDFromName( victim )
-	end
-
-	local overheal = getOverheal( victimid, amount )
-	if overheal > 0 then
-		if source == ParserLib_SELF then
-			data[playerName] = data[playerName] + overheal
-			broadcastdirty = broadcastdirty + overheal
-			dirty = true
-		else 
-			mod:OnRemoteData( source, overheal )
-		end
-	end	
+	local victimid = roster:GetUnitIDFromName( victim )
+	self:OnData(source, getOverheal( victimid, amount ))
 end
-
-
Index: Other/Banzai.lua
===================================================================
--- Other/Banzai.lua	(revision 39414)
+++ Other/Banzai.lua	(working copy)
@@ -10,10 +10,6 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = nil
-local dirty = nil
 local moduleName = "Banzai"
 local gainedAggroTime
 
@@ -32,29 +28,10 @@
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	self:RegisterEvent("Banzai_UnitGainedAggro", 
-		function(id) 
-			local unit = Roster:GetUnitObjectFromUnit(id)
-			if unit then
-				self:GainedAggro(unit.name) 
-			end
-		end
-	)
-	self:RegisterEvent("Banzai_UnitLostAggro",
-		function(id) 
-			local unit = Roster:GetUnitObjectFromUnit(id)
-			if unit then
-				self:LostAggro(unit.name)
-			end
-		end
-	)
-	
+	AceLibrary("Banzai-1.1") -- Ensure it is loaded
+	self:RegisterEvent("Banzai_UnitGainedAggro")
+	self:RegisterEvent("Banzai_UnitLostAggro")	
 	self:SetupAggroTable()
 end
 
@@ -64,59 +41,16 @@
 end
 
 function mod:OnReset()
-	self:ClearAggroTable()
-
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-
-	data = mod:new()
-	data[playerName] = 0
-	
-	self:SetupAggroTable()
-	
-	dirty = nil
-	broadcastdirty = nil
+	gainedAggroTime = mod:del(gainedAggroTime)
 end
 
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return "Aggro duration" end
 function mod:GetShortDisplayName() return "Aggro" end
-function mod:GetBroadcastData()
-	local data = broadcastdirty
-	broadcastdirty = nil
-	return data
-end
 
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:IsBroadcastDirty()
-	return broadcastdirty
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
 function mod:ClearAggroTable()
 	if gainedAggroTime then
 		for name in pairs(gainedAggroTime) do
@@ -136,40 +70,48 @@
 	end
 end
 
-local function updateData(self, name)
+function mod:UpdateData(name)
 	if not gainedAggroTime[name] then return end
 	local now = GetTime()
 	local delta = now - gainedAggroTime[name]
 	gainedAggroTime[name] = now
-	if delta > 0 then
-		if Violation:AcceptDataFromSource(name, moduleName) then
-			self:OnRemoteData(name, delta)
-			if name == playerName then
-				broadcastdirty = (broadcastdirty or 0) + delta
-			end
-		end
-	end	
+	self:OnData(name, delta)
 end
 
 function mod:LostAggro(name)
-	if gainedAggroTime[name] then
-		updateData(self, name)
+	if self:AcceptDataFor(name) and gainedAggroTime and gainedAggroTime[name] then
+		self:UpdateData(name)
 		gainedAggroTime[name] = nil
 	end
 end
 
 function mod:GainedAggro(name)
-	if not gainedAggroTime[name] then
+	if self:AcceptDataFor(name) and (not gainedAggroTime or not gainedAggroTime[name]) then
+		if not gainedAggroTime then
+			gainedAggroTime = self:new()
+		end
 		gainedAggroTime[name] = GetTime()
+		self:UpdateData(name)
 	end
 	if next(gainedAggroTime) and not self:IsEventScheduled(PERIODICUPDATE_ID) then
 		self:ScheduleRepeatingEvent(PERIODICUPDATE_ID, self.PeriodicUpdate, 1, self) 
 	end
 end
 
+function mod:Banzai_UnitGainedAggro(id) 
+	local unit = Roster:GetUnitObjectFromUnit(id)
+	self:GainedAggro(unit.name) 
+end
+
+function mod:Banzai_UnitLostAggro(id) 
+	local unit = Roster:GetUnitObjectFromUnit(id)
+	self:LostAggro(unit.name)
+end
+
+
 function mod:PeriodicUpdate()
 	for name in pairs(gainedAggroTime) do		
-		updateData(self, name)
+		self:UpdateData(name)
 	end
 	if not next(gainedAggroTime) and self:IsEventScheduled(PERIODICUPDATE_ID) then
 		self:CancelScheduledEvent(PERIODICUPDATE_ID) 
Index: Other/Decurse.lua
===================================================================
--- Other/Decurse.lua	(revision 39414)
+++ Other/Decurse.lua	(working copy)
@@ -17,14 +17,9 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = 0
-local dirty = nil
 local moduleName = "Decurse"
 
 local parser = ParserLib:GetInstance("1.1")
-local roster = AceLibrary("Roster-2.1")
 
 -----------------------------------------------------------------------
 -- Module declaration
@@ -33,90 +28,34 @@
 local mod = Violation:NewModule(moduleName)
 mod.revision = tonumber(("$Revision$"):sub(12, -3)) or 1
 mod.version = 4
-mod.canMergeData = true
 mod.violationCategory = "other"
 
 -----------------------------------------------------------------------
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = self:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType(moduleName, "dispel", self.OnParserEvent)
+	parser:RegisterInfoType(self, "dispel", self.OnParserEvent)
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes(moduleName )
+	parser:UnregisterAllInfoTypes(self)
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = self:del(data)
-	end
-
-	data = self:new()
-	data[playerName] = 0
-	dirty = nil
-	broadcastdirty = 0
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Decursing done"] end
 function mod:GetShortDisplayName() return L["Decursing"] end
-function mod:GetBroadcastData()
-	local x = broadcastdirty
-	broadcastdirty = 0
-	return x
-end
 
-function mod:IsBroadcastDirty()
-	return broadcastdirty > 0 and true or false
-end
-
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:OnRemoteData(sender, input)
-	data[sender] = (data[sender] or 0) + input
-	dirty = true
-end
-
-function mod:OnParserEvent( info, event )
+function mod:OnParserEvent( infoType, info, event )
 	if info.isFailed then return end
-	local source = info.source
+	local source = self:GetSourceVictimAmount(info)
 
-	if not source or source == ParserLib_NONE or not Violation:AcceptDataFromSource( source, moduleName ) then
+	if not source or not self:AcceptDataFor( source ) then
 		return
 	end
 
-	if source == ParserLib_SELF then
-		data[playerName] = data[playerName] + 1
-		broadcastdirty = broadcastdirty + 1
-		dirty = true
-	else
-		mod:OnRemoteData( source, 1 )
-	end
+	self:OnData(source, 1)
 end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
-
-
Index: Other/HitCritRate.lua
===================================================================
--- Other/HitCritRate.lua	(revision 39414)
+++ Other/HitCritRate.lua	(working copy)
@@ -17,10 +17,6 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = nil
-local dirty = nil
 local moduleName = "HitCritRate"
 local hitCount = {}
 local critCount = {}
@@ -43,27 +39,15 @@
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = mod:new()
-end
-
 function mod:OnModuleEnable()
-	parser:RegisterInfoType( moduleName, "hit", self.OnParserEvent)
+	parser:RegisterInfoType( self, "hit", "OnParserEvent" )
 end
 
 function mod:OnModuleDisable()
-	parser:UnregisterAllInfoTypes( moduleName )
+	parser:UnregisterAllInfoTypes( self )
 end
 
 function mod:OnReset()
-	if type(data) == "table" then
-		data = mod:del(data)
-	end
-
-	data = mod:new()
-	data[playerName] = 0
-	
 	if type(hitCount) == "table" then
 		hitCount = mod:del(hitCount)
 	end
@@ -73,59 +57,37 @@
 		critCount = mod:del(critCount)
 	end
 	critCount = mod:new()
-	
-	dirty = nil
-	broadcastdirty = nil
 end
 
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
 function mod:GetDisplayName() return L["Critical hit rate"] end
 function mod:GetShortDisplayName() return L["Crit%"] end
 
-function mod:GetBroadcastData()
-	broadcastdirty = nil
-	return data[playerName]
-end
-
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
-function mod:IsBroadcastDirty()
-	return broadcastdirty
-end
-
-function mod:OnRemoteData(sender, input)
-	if input ~= data[sender] then
-		data[sender] = input
-		dirty = true
+function mod:OnData(name, input, remote)
+	if name and input then
+		if name == self.playerName and not remote then
+			self.broadcastdirty = input
+		end
+		self.dirty = (input ~= (self.data[name] or 0))
+		self.data[name] = input
 	end
 end
 
-function mod:OnParserEvent( info, event )
-	local name, amount, victim = info.source, info.amount, info.victim
+function mod:OnParserEvent( infoType, info, event )
+	local name, victim, amount = self:GetSourceVictimAmount(info)
 
-	if not name or name == ParserLib_NONE or not amount or amount == 0 or info.isDOT then
+	if not name or amount == 0 or info.isDOT or not self:AcceptDataFor(name) then 
 		return
 	end
-
-	if not Violation:AcceptDataFromSource(name, moduleName) then 
-		return
-	end
 	
 	-- We ignore split damage from known units to known units.
 	-- this includes soullink damage from you to your pet.
 	-- thanks rophy for pointing this out.
 	if info.isSplit and victim then
-		if victim == ParserLib_SELF or roster:GetUnitIDFromName( victim ) then
+		if victim == self.playerName or roster:GetUnitIDFromName( victim ) then
 			return
 		end
 	end
@@ -135,20 +97,5 @@
 		critCount[name] = (critCount[name] or 0) + 1
 	end
 	
-	local newCritRate =  math.floor(100.0 * (critCount[name] or 0) / (hitCount[name] or 1))
-	if name == ParserLib_SELF then
-		if newCritRate ~= data[playerName] then
-			data[playerName], dirty, broadcastdirty = newCritRate, true, true
-		end
-	else
-		mod:OnRemoteData(name, newCritRate)
-	end
+	self:OnData(name, math.floor(100.0 * (critCount[name] or 0) / (hitCount[name] or 1)))
 end
-
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
-end
Index: Threat/TargetThreat.lua
===================================================================
--- Threat/TargetThreat.lua	(revision 39414)
+++ Threat/TargetThreat.lua	(working copy)
@@ -16,16 +16,11 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = 0
-local dirty = nil
 local moduleName = "Target Threat"
 local targetName = ""
 
 local roster = AceLibrary("Roster-2.1")
 local threat
-AceLibrary:HasInstance("Threat-1.0")
 
 -----------------------------------------------------------------------
 -- Module declaration
@@ -41,97 +36,61 @@
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = self:new()
-end
-
 function mod:OnModuleEnable()
-	if not threat and AceLibrary:HasInstance("Threat-1.0") then
+	if not threat then
 		threat = AceLibrary("Threat-1.0")
-		self:RegisterEvent("PLAYER_TARGET_CHANGED")
-		self:RegisterEvent("Threat_ThreatUpdated")
-		self:RegisterEvent("Threat_ThreatCleared", function()
-			self:OnReset()
-			dirty = true
-			self:RequestDisplayRefresh()
-		end)	
 	end
+	self:RegisterEvent("PLAYER_TARGET_CHANGED")
+	self:RegisterEvent("Threat_ThreatUpdated")
+	self:RegisterEvent("Threat_ThreatCleared")	
 end
 
 function mod:OnModuleDisable()
 	self:UnregisterAllEvents()
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = self:del(data)
-	end
-
-	data = self:new()
-	data[playerName] = 0
-	dirty = nil
-	broadcastdirty = 0	
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
+
 function mod:GetDisplayName() return L["Target Threat"] end
 function mod:GetShortDisplayName() return L["TT"] end
-function mod:GetBroadcastData()
-	return 0
-end
 
 function mod:IsBroadcastDirty()
 	return false
 end
 
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
 function mod:OnRemoteData(sender, input)
 	return
 end
 
-function mod:PLAYER_TARGET_CHANGED()
-	targetName = UnitName("target")
-	if not targetName then
-		targetName = ""
+function mod:RefreshData(reset)
+	self:Reset()
+	if not reset then
+		for name,value in threat:IterateGroupThreatForTarget(targetName) do
+			if value and value > 0 then
+				self.data[name] = value
+			end
+		end
 	end
-	if type(data) == "table" then
-		data = self:del(data)
-	end
-	data = self:new()
-	for k, v in threat:IterateGroupThreatForTarget(targetName) do
-		data[k] = v
-	end
-	dirty = true
+	self.dirty = true
 	self:RequestDisplayRefresh()
 end
 
+function mod:PLAYER_TARGET_CHANGED()
+	targetName = UnitName("target")
+	self:RefreshData(not targetName)
+end
+
 function mod:Threat_ThreatUpdated( name, unit, target, value )
-	local unitid = roster:GetUnitIDFromName( name )
-	if not unitid or not threat:UnitIsUnit(targetName, target) then
+	if not threat:UnitIsUnit(targetName or "", target) then
 		return
 	end
-	
-	data[name] = value
-	dirty = true
-	
+	self.dirty = true
+	self.data[name] = value
 end
 
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
+function mod:Threat_ThreatCleared()
+	self:RefreshData(true)
 end
Index: Threat/Threat.lua
===================================================================
--- Threat/Threat.lua	(revision 39414)
+++ Threat/Threat.lua	(working copy)
@@ -15,14 +15,9 @@
 -- Locals
 -----------------------------------------------------------------------
 
-local playerName = nil
-local data = nil
-local broadcastdirty = 0
-local dirty = nil
 local moduleName = "Threat"
+local threat
 
-local roster = AceLibrary("Roster-2.1")
-
 -----------------------------------------------------------------------
 -- Module declaration
 -----------------------------------------------------------------------
@@ -37,79 +32,41 @@
 -- Module initialization
 -----------------------------------------------------------------------
 
-function mod:OnModuleRegister()
-	playerName = UnitName("player")
-	data = self:new()
-end
-
 function mod:OnModuleEnable()
+	if not threat then
+		threat = AceLibrary("Threat-1.0")
+	end
 	self:RegisterEvent("Threat_ThreatUpdated")
-	self:RegisterEvent("Threat_ThreatCleared", function()
-		self:OnReset()
-		dirty = true
-		self:RequestDisplayRefresh()
-	end)
+	self:RegisterEvent("Threat_ThreatCleared")
 end
 
 function mod:OnModuleDisable()
 	self:UnregisterAllEvents()
 end
 
-function mod:OnReset()
-	if type(data) == "table" then
-		data = self:del(data)
-	end
-
-	data = self:new()
-	data[playerName] = 0
-	dirty = nil
-	broadcastdirty = 0
-end
-
 -----------------------------------------------------------------------
 -- Module implementation
 -----------------------------------------------------------------------
 
-function mod:GetRevision() return self.revision end
+
 function mod:GetDisplayName() return L["Global Threat"] end
 function mod:GetShortDisplayName() return L["T"] end
-function mod:GetBroadcastData()
-	return 0
-end
 
 function mod:IsBroadcastDirty()
 	return false
 end
 
-function mod:IsDirty()
-	return dirty
-end
-
-function mod:ResetDirty()
-	dirty = nil
-end
-
 function mod:OnRemoteData(sender, input)
 	return
 end
 
-function mod:Threat_ThreatUpdated( name, unit, target, value )
-	local unitid = roster:GetUnitIDFromName( name )
-	if not unitid or target ~= 'GLOBAL' then
-		return
-	end
-	
-	data[name] = value
-	dirty = true
-	
+function mod:Threat_ThreatCleared()
+	self:Reset()
+	self.dirty = true
+	self:RequestDisplayRefresh()
 end
 
-function mod:GetData(player)
-	if player then
-		return data[player]
-	else
-		return data
-	end
+function mod:Threat_ThreatUpdated( name, unit, target, value )
+	self.data[name] = threat:GetThreat(name, "_GLOBAL_")
+	self.dirty = true
 end
-
-
Index: Violation.lua
===================================================================
--- Violation.lua	(revision 39414)
+++ Violation.lua	(working copy)
@@ -2,7 +2,6 @@
 -- To do and/or ideas
 --
 -- From Rabbit:
--- * Parse damage messages from swstats and damagemeters.
 -- * Automatically output our damage done and position to chat when a boss has
 -- been killed; this is easy with Babble-Boss, CHAT_MSG_HOSTILE_DEATH and
 -- UnitClassification.
@@ -33,8 +32,6 @@
 --
 -- From Adirelle:
 -- * Extend communication protocol to allow sending of pet data (at least).
--- * Multidisplay
--- * Character tooltip on hovering over bars
 --
 -- From <person>:
 -- * Brew my coffee when I win the damage meter contest after a boss fight.
@@ -414,6 +411,7 @@
 			desc = "Window Options",
 			args = {
 			},
+			hidden = function() return db.windows.count == 0 end,
 			order = 111,
 		},
 		newwindow = {
@@ -424,6 +422,7 @@
 				db.windows.count = db.windows.count + 1
 				Violation:SetupWindows()
 			end,
+			disabled = function() return not next(runningModules) end,
 			order = 112,
 		},
 		--[[
@@ -699,14 +698,16 @@
 	if incompatible[self] or not Violation.db.char.enabledModules[self.name] then return end
 
 	if not runningModules[self.name] then
-		-- Always reset our data when we enable.
-		self:OnReset()
-
+		-- Always reset our data when we enable.		
+		runningModules[self.name] = self
+	
+		self.playerName = playerName		
+		self:Reset()
+		
 		if type(self.OnModuleEnable) == "function" then
 			self:OnModuleEnable()
 		end
 
-		runningModules[self.name] = self
 		-- options.args.bars.args.display.validate[self.name] = self:GetDisplayName()
 
 		-- Violation:SendCommMessage("GROUP", "ModuleEnabled", self.name)
@@ -719,41 +720,105 @@
 		if type(self.OnModuleDisable) == "function" then
 			self:OnModuleDisable()
 		end
+		
+		local availableMod = next(runningModules, self.name)
 
 		runningModules[self.name] = nil
-		--options.args.bars.args.display.validate[self.name] = nil
-
-		local availableMod
-		for name in pairs(runningModules) do
-			availableMod = name
-			break
+		
+		if not availableMod then
+			availableMod = next(runningModules)
 		end
-
-		for k, w in ipairs( db.windows ) do
-			if w.module == self.name then
-				if availableMod then
-					w.module = availableMod
+		
+		if not availableMod then
+			for i = 1, db.windows.count do
+				-- Always delete first
+				if db.windows[1] then
+					Violation:DeleteWindow( Violation.windows[1] )
 				else
-					Violation:DeleteWindow( self.windows[k] )
+					break
 				end
 			end
+		else
+			for k,w in ipairs(db.windows) do
+				if w.module == self.name then
+					w.module = availableMod
+				end
+			end
 		end
-		
+
 		Violation:UpdateWindows()
-		
-		-- Violation:SendCommMessage("GROUP", "ModuleDisabled", self.name)
+						
 		Violation:TriggerEvent("Violation_ModuleDisabled", self.name)
 	end
 end
 
-function Violation.modulePrototype:GetMergedData(...)
-	local sum = 0
-	for i = 1,select("#", ...) do
-		sum = sum + (self:GetData(select(i, ...)) or 0)
+function Violation.modulePrototype:AcceptDataFor(name)
+	return Violation:AcceptDataFromSource(name, self.name)
+end
+
+function Violation.modulePrototype:GetSourceVictimAmount(info)
+	local source, victim, amount = info.source, info.victim, (info.amount or 0)
+	if source == ParserLib_SELF then
+		source = playerName
+	elseif source == ParserLib_NONE then
+		source = nil
 	end
-	return sum
+	if victim == ParserLib_SELF then
+		victim = playerName
+	elseif victim == ParserLib_NONE then
+		victim = nil
+	end
+	return source, victim, amount
 end
 
+function Violation.modulePrototype:IsLocal(name)
+	return name == ParserLib_SELF or name == playerName or characterDataSource[name] == playerName
+end
+
+function Violation.modulePrototype:GetRevision()
+	return self.revision
+end
+
+function Violation.modulePrototype:Reset()
+	if type(self.data) == "table" then
+		data = del(self.data)
+	end
+	self.data = new()
+	self.data[playerName] = 0
+	self.broadcastdirty = nil
+	self.dirty = nil
+	if type(self.OnReset) == "function" then
+		self:OnReset()
+	end
+end
+
+function Violation.modulePrototype:IsDirty()
+	return self.dirty
+end
+
+function Violation.modulePrototype:ResetDirty()
+	self.dirty = nil
+end
+
+
+function Violation.modulePrototype:IsBroadcastDirty()
+	return self.broadcastdirty and true or false
+end
+
+function Violation.modulePrototype:GetBroadcastData()
+	local x = self.broadcastdirty
+	self.broadcastdirty = nil
+	return x
+end
+
+function Violation.modulePrototype:GetData(name)
+	if name then
+		return self.data[name]
+	else
+		return self.data
+	end
+end
+
 function Violation.modulePrototype:IsShown()
 	local name = self.name
 	if runningModules[name] then
@@ -778,20 +843,62 @@
 function Violation.modulePrototype.dataFormatter(v)
 	if not v then return "" end
 	v = tonumber(v)
-	if v >= 10000000 then
-		return string.format("%d M", math.floor(v/1000000))		
-	elseif v >= 10000 then
-		return string.format("%d k", math.floor(v/1000))		
+	if v >= 1000000 then
+		return string.format("%d %03d %03d", math.floor(v/100000), math.floor(v/1000) % 1000, v % 1000)		
+	elseif v >= 1000 then
+		return string.format("%d %03d", math.floor(v/1000), v % 1000)		
 	else
 		return string.format("%d", v)
 	end
 end
 
+function Violation.modulePrototype:OnRemoteData(name, input)
+	self:OnData(name, input, true)
+end
 
 function Violation.modulePrototype:new(...) return new(...) end
 function Violation.modulePrototype:del(t) return del(t) end
 
 -----------------------------------------------------------------------
+-- Default module data implementation
+-----------------------------------------------------------------------
+-- This implmentation supposes that the modules handle "incremental" data
+-- like damage done, or healing taken, ...
+-- Special modules like DPS or HPS, have to override theses methods
+
+Violation.modulePrototype.canMergeData = true
+
+function Violation.modulePrototype:OnData(name, input, remote)
+	if name and input and input > 0 then
+		if name == playerName and not remote then
+			self.broadcastdirty = (self.broadcastdirty or 0) + input
+		end
+		self.data[name] = (self.data[name] or 0) + input
+		self.dirty = true
+	end
+end
+
+function Violation.modulePrototype:GetMergedData(...)
+	local sum = 0
+	for i = 1,select("#", ...) do
+		sum = sum + (self:GetData(select(i, ...)) or 0)
+	end
+	return sum
+end
+
+--[[
+function Violation.OnDataImpl:Absolute(name, input, remote)
+	if name and input then
+		if name == playerName and not remote then
+			self.broadcastdirty = input
+		end
+		self.dirty = (input ~= (self.data[name] or 0))
+		self.data[name] = input
+	end
+end
+--]]
+
+-----------------------------------------------------------------------
 -- Implicit module interface
 -----------------------------------------------------------------------
 
@@ -842,7 +949,7 @@
 	OnRemoteData = "function",
 
 	-- Invoked by the core when all data should be reset.
-	OnReset = "function",
+	Reset = "function",
 
 	-- Must return a universal unique ID that will be used for this module when
 	-- sending data (where the universe is Violation)
@@ -1011,16 +1118,20 @@
 end
 
 function Violation:Reset()
-	for i, mod in self:IterateRunningModules() do
+	for index, modName in self:IterateRunningModules() do
+		local module = runningModules[modName]
 		if db.printOnReset then
-			local data = self:GetModuleData(mod.name, playerName)
+			local data = self:GetModuleData(modName, playerName)
 			if type(data) == "number" and data > 0 then
-				local name = mod:GetDisplayName()
-				local color = db.colors[mod.name]
-				self:Print(Colorize(string.format(L["%s: %d"], name, data), color.r, color.g, color.b))
+				local color = db.colors[modName]
+				local name = module:GetDisplayName()
+				local formatter = dataFormatter[modName] or tostring
+				name = Colorize(name, color.r, color.g, color.b)
+				data = formatter(data)
+				self:Print(string.format("%s: %s", name, data))
 			end
 		end
-		mod:OnReset()
+		module:Reset()
 	end
 	self:UpdateDisplay()
 	self:UpdateWindows()
@@ -1138,18 +1249,19 @@
 end
 
 local function ModuleSorter(a, b)
-	local diff = a.violationOrdering - b.violationOrdering
-	return (diff == 0) and (a:GetDisplayName() < b:GetDisplayName()) or (diff < 0)
+	local moduleA = runningModules[a]
+	local moduleB = runningModules[b]
+	local diff = moduleA.violationOrdering - moduleB.violationOrdering
+	return (diff == 0) and (moduleA:GetDisplayName() < moduleB:GetDisplayName()) or (diff < 0)
 end
 
 function Violation:UpdateRunningModuleOrdering()
 	runningModuleOrdering = del(runningModuleOrdering)
 	runningModuleOrdering = new()
 	for name, module in pairs(runningModules) do
-		table_insert(runningModuleOrdering, module)
+		table_insert(runningModuleOrdering, module.name)
 	end
 	table.sort(runningModuleOrdering, ModuleSorter)
-	self.runningModuleOrdering = runningModuleOrdering
 end
 
 function Violation:IsModuleRunning(name)
@@ -1160,6 +1272,7 @@
 	return ipairs(runningModuleOrdering)
 end
 
+
 -----------------------------------------------------------------------
 -- Pet merging stuff
 -----------------------------------------------------------------------
@@ -2190,6 +2303,7 @@
 function Violation:DeleteWindow( window )
 	local wdb = self.db.char.windows
 	local oldindex = window:GetID()
+	window:Close()
 	window:DeleteWindowOptions()
 	for i = oldindex, wdb.count - 1 do
 		wdb[i] = wdb[i+1]
@@ -2403,9 +2517,8 @@
 	GameTooltip:AddLine(char)
 	GameTooltip:AddLine(" ")
 	GameTooltip:AddDoubleLine("Module", "Value", 1, 1, 1, 1, 1, 1)
-	for i, module in Violation:IterateRunningModules() do
-		local modName = module.name
-		local displayName = module:GetDisplayName()
+	for index, modName in Violation:IterateRunningModules() do		
+		local displayName = runningModules[modName]:GetDisplayName()
 		local value = Violation:GetModuleData(modName, char)
 		if value and tonumber(value) > 0 then
 			local formatter = Violation.dataFormatter[modName] or tostring
@@ -2724,9 +2837,9 @@
 	local mod = o.module
 	local dirtpile = new()
 	local current
-	for index, module in Violation:IterateRunningModules() do
-		table_insert( dirtpile, module.name )
-		if module.name == mod then
+	for index, modName in Violation:IterateRunningModules() do
+		table_insert( dirtpile, modName )
+		if modName == mod then
 			current = index
 		end
 	end
@@ -2875,6 +2988,6 @@
 end
 
 function VioWindow.prototype:BarAddCallBack(i, rank, name, value, percentage, dataInfo)
-	return self:SetBar(i, rank..".", name, tostring( value ), value, dataInfo.maxValue, percentage)
+	return self:SetBar(i, rank..".", name, dataInfo.formatter( value ), value, dataInfo.maxValue, percentage)
 end
 
Index: Violation.toc
===================================================================
--- Violation.toc	(revision 39414)
+++ Violation.toc	(working copy)
@@ -8,8 +8,8 @@
 ## X-AceForum: 4843
 ## Version: 1.0
 ## X-License: GPLv2 or later.
-## OptionalDeps: Ace2, FuBar, FuBarPlugin-2.0, TabletLib, DewdropLib, ParserLib, Babble-2.2, RosterLib, SharedMedia, SharedMediaLib, SpecialEventsEmbed, Babble-Class-2.2, Threat-1.0, BanzaiLib, Parser-3.0
-## X-Embeds: Ace2, FuBarPlugin-2.0, TabletLib, DewdropLib, ParserLib, Babble-2.2, RosterLib, SharedMediaLib, SpecialEventsEmbed, Threat-1.0, BanzaiLib
+## OptionalDeps: Ace2, FuBar, FuBarPlugin-2.0, TabletLib, DewdropLib, ParserLib, Babble-2.2, RosterLib, SharedMedia, SharedMediaLib, SpecialEventsEmbed, Babble-Class-2.2, Threat-1.0, BanzaiLib, CombatEvents-1.0, Parser-3.0
+## X-Embeds: Ace2, FuBarPlugin-2.0, TabletLib, DewdropLib, ParserLib, Babble-2.2, RosterLib, SharedMediaLib, SpecialEventsEmbed, Threat-1.0, BanzaiLib, CombatEvents-1.0
 ## SavedVariables: ViolationDB
 ## SavedVariablesPerCharacter: ViolationPerCharDB
 
@@ -45,6 +45,8 @@
 
 libs\Banzai-1.1\Banzai-1.1.lua
 
+libs\CombatEvents-1.0\CombatEvents-1.0.lua
+
 Violation.lua
 
 Damage\Damage.lua
