changeset 19:605e8f0e46db

ObjectiveCore / Style / Events / Frame - polishing the execution path for better performance - make use of the Blizzard_ObjectiveTracker bitfield values to ensure compatibility in possible secure hooks - avoid full updates when possible (using said bitfield values to indicate targeted sections) - extreme streamlining of event handling layout: specific reason updates are invoked from API hooks; broader updates are invoked by when the event listener catches something vague like 'QUEST_LOG_UPDATE'
author Nenue
date Wed, 06 Apr 2016 07:38:35 -0400
parents d1812fb10ae6
children 6bd2102d340b
files ObjectiveCore.lua ObjectiveEvents.lua ObjectiveFrame.lua ObjectiveInfo.lua ObjectiveStyle.lua ObjectiveTracker.xml ObjectiveUI.lua ObjectiveWidgets.lua XPTracker.lua
diffstat 9 files changed, 640 insertions(+), 498 deletions(-) [+]
line wrap: on
line diff
--- a/ObjectiveCore.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveCore.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -3,29 +3,16 @@
 -- @project-revision@ @project-hash@
 -- @file-revision@ @file-hash@
 -- Created: 3/26/2016 1:51 AM
-local B = select(2,...).frame
-local pairs, setmetatable, type, tostring = pairs, setmetatable, type, tostring
-local format = string.format
+local B, _G = select(2,...).frame, _G
+local pairs, setmetatable, type, tostring = _G.pairs, _G.setmetatable, _G.type, _G.tostring
+local format = _G.format
 local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
 local print = B.print('Objectives')
-local ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame = ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame
-
---[[
-  Full quest info is available if:
-    - It's in the player quest log, or is available from the Gossip interface
-    - It's being shared from another player and is acceptible
-    - It's an auto-quest that is available in the current location
-  Partial quest info is availabe if:
-    - It's already completed (i.e. it appears in CompletedQuestInfo()).
-    - It's an scheduled interval quest (daily, weekly, etc.)
-    - It's contained in a quest link received from chat
-  Under any other circumstances, only minimal info can be pulled:
-    - Its availability to the player
-    - Its relation with the currently engaged NPC
-    - Its binary completion status
-
-]]
-
+local ObjectiveTrackerFrame, VeneerObjectiveScroll, CreateFrame = _G.ObjectiveTrackerFrame, _G.VeneerObjectiveScroll, _G.CreateFrame
+local Wrapper = _G.VeneerObjectiveWrapper
+local ipairs, tinsert, hooksecurefunc = _G.ipairs, _G.tinsert, _G.hooksecurefunc
+local Scroller = VeneerObjectiveWrapper.scrollArea
+local Scroll = _G.VeneerObjectiveScroll
 
 --- Performance values
 --[[
@@ -45,155 +32,324 @@
 	self:RegisterEvent("QUEST_TURNED_IN");
 	self:RegisterEvent("PLAYER_MONEY");
  ]]
-mod.Reason ={
-  UPDATE_MASK_AUTOQUEST            = 0x00000001,
-  UPDATE_MASK_QUEST                = 0x00000002,
-  UPDATE_MASK_BONUS                = 0x00000004,
-  UPDATE_MASK_CHEEVS               = 0x00000008,
-  UPDATE_MASK_ALL                  = 0x00000017,
 
-  QUEST_LOG_UPDATE                 = 0x00000003,
-  TRACKED_ACHIEVEMENT_LIST_CHANGED = 0x00000008,
-  QUEST_WATCH_LIST_CHANGED         = 0x00000003,
-  QUEST_AUTOCOMPLETE               = 0x00000003,
-  QUEST_ACCEPTED                   = 0x00000003,
-  SUPER_TRACKED_QUEST_CHANGED      = 0x00000002,
-  SCENARIO_UPDATE                  = 0x00000004,
-  SCENARIO_CRITERIA_UPDATE         = 0x00000004,
-  TRACKED_ACHIEVEMENT_UPDATE       = 0x00000008,
-  ZONE_CHANGED_NEW_AREA            = 0x00000017,
-  ZONE_CHANGED                     = 0x00000017,
-  QUEST_POI_UPDATE                 = 0x00000003,
-  QUEST_TURNED_IN                  = 0x00000003,
-}
+
+--- These are the bitfields used by Blizzard_ObjectiveTracker to determine which segments get parsed.
+--- They are replicated here so that plugins can make use of any securehook args involving this info.
+local OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST                       -- 0x0100
+local OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP = OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP	-- 0x0200
+local OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE		-- 0x0400
+local OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO	    		        -- 0x0800
+local OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT	= OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT           -- 0x1000
+
+
+local OBJECTIVE_TRACKER_UPDATE_STATIC = OBJECTIVE_TRACKER_UPDATE_STATIC					                         	-- 0x0000
+local OBJECTIVE_TRACKER_UPDATE_ALL = OBJECTIVE_TRACKER_UPDATE_ALL			                    	          		-- 0xFFFF
+local OBJECTIVE_TRACKER_UPDATE_ID = OBJECTIVE_TRACKER_UPDATE_ID                                           -- 0
+
+local OBJECTIVE_TRACKER_UPDATE_QUEST = OBJECTIVE_TRACKER_UPDATE_QUEST				        	                  	-- 0x0001
+local OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED = OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED		               		    -- 0x0002
+local OBJECTIVE_TRACKER_UPDATE_TASK_ADDED = OBJECTIVE_TRACKER_UPDATE_TASK_ADDED		    	              		-- 0x0004
+local OBJECTIVE_TRACKER_UPDATE_SCENARIO = OBJECTIVE_TRACKER_UPDATE_SCENARIO			      	                 	-- 0x0008
+local OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE = OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE		       	-- 0x0010
+local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT			                   	-- 0x0020
+local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED		  	      -- 0x0040
+local OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED = OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED		-- 0x0080
+
+local OBJECTIVE_TRACKER_UPDATE_REASON = OBJECTIVE_TRACKER_UPDATE_ALL -- default
+--- Used to determine which trackers are listening for money events
 mod.MoneyReasons = 0
 
---- Baseline defaults
+--- Baseline defaults table; values defined in the files that they pertain to
 mod.defaults = {}
 
---- list used to make things happen
+--- Tracker display order
 mod.orderedNames = {'Bonus', 'AutoQuest', 'Quest', 'Cheevs'}
 
---- ipairs() list of handlers for wrapper update
-mod.orderedHandlers = {}
-mod.orderedTrackers = {}
-mod.indexedTrackers = {}
---- pairs() list of handler frames for tracker updates
-mod.namedTrackers = {}
+--- ipairs() argument tables
+mod.orderedHandlers = setmetatable({}, {__mode = "k"})
+mod.orderedTrackers = setmetatable({}, {__mode = "k"})
+mod.indexedTrackers = setmetatable({}, {__mode = "k"})
 
---- Handler stubs
+--- pairs() argument tables
+mod.namedTrackers = setmetatable({}, {__mode = "k"})
+
+local WRAPPER_ANCHOR_POINT = 'TOPRIGHT'
+local WRAPPER_OFFSET_X = 0
+local WRAPPER_OFFSET_Y = -200
+local WRAPPER_MAX_HEIGHT = 670
+local WRAPPER_WIDTH = 280
+local WRAPPER_HEADER_HEIGHT = 24
+
+mod.defaults.Wrapper = {
+  AnchorPoint = WRAPPER_ANCHOR_POINT,
+  OffsetX = WRAPPER_OFFSET_X,
+  OffsetY = WRAPPER_OFFSET_Y,
+  Height = WRAPPER_MAX_HEIGHT,
+  Width = WRAPPER_WIDTH,
+  HeaderHeight = WRAPPER_HEADER_HEIGHT
+}
+--- Tracker module definitions begin here; innards dealing with data retreival and output are defined further in
+mod.DefaultTracker = {
+  previousHeight = 0,
+
+  name = "temp",
+  displayName = "temp",
+  updateReasonModule = 0xFF00,
+  updateReasonEvent  = 0x00FF,
+
+  numWatched = 0,   --- number of entries being handled
+  numBlocks = 0,    --- number of blocks created
+  actualBlocks = 0, --- number of blocks in use
+
+  freeBlocks = {},  --- block heap
+  usedBlocks = {},
+
+  Info = {},        -- find data by ID
+  BlockInfo = {},   -- find data by block ID
+  Watched = {},     -- find watchIndex by data ID
+  WatchInfo = {},   -- find data by watch index
+  WatchBlock = {},  -- find block by watch index
+}
+
 mod.AutoQuest = {
   name = "AutoQuest",
   displayName = "Notice",
+  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST,
+  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
+      OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED,
 }
 mod.Quest = {
   name = "Quest",
   displayName = "Quests",
+  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST,
+  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
+      OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED,
 }
 mod.Cheevs = {
   name = "Cheevs",
   displayName = "Achievements",
+  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT,
+  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT +
+      OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED,
 }
 mod.Bonus = {
   name = "Bonus",
   displayName = "Bonus Objectives",
+  updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE,
+  updateReasonEvents = OBJECTIVE_TRACKER_UPDATE_QUEST +
+        OBJECTIVE_TRACKER_UPDATE_TASK_ADDED +
+        OBJECTIVE_TRACKER_UPDATE_SCENARIO +
+        OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE +
+        OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED
 }
 
---- Handler template
-local CreateHandler = function (self, name, index)
-  print(self, name)
+local Tracker_string = function (self)
+  return self.name
+end
+local Tracker_call = function (self, reason)
+  self:Update(reason)
+end
+
+local Tracker_Initialize = function (self, name, index)
+  print('Initializing |cFF00FFFF'..name..'|r module...')
 
   local handler = setmetatable(mod[name] or {}, {
-    __tostring = function() return name end,
-    __call = function (self) mod.UpdateTracker(self) end
+    __tostring = Tracker_string,
+    __call = Tracker_call
   })
   if type(mod.orderedHandlers[index]) == 'table' then
     return mod.orderedHandlers[index]
   end
 
-  print('take up locals first')
+  print('|cFFFFFF00Acquiring locals')
   local preset = {}
-  for k,v in pairs(mod[name]) do
+  for k, _ in pairs(handler) do
     preset[k] = true
-    if type(v) == 'table' then
-      handler[k] = {}
-    else
-      handler[k] = v
-    end
   end
 
 
-  print('resulting handler contents')
+  print('|cFFFF8800Inheriting')
   for k, v in pairs(self) do
     if not handler[k] then
       if type(v) == 'table' then
         -- assume all tables to be local data; don't inherit or ref
         handler[k] = {}
       else
-        handler[k] = mod.Tracker[k]
+        handler[k] = self[k]
       end
-    else
-      print(name, 'has its own', k)
+      print('copying', k)
     end
   end
   print('|cFFFF4400'..tostring(name)..'|r:')
   for k, v in pairs(handler) do
-    print(format("%24s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v)))
+    print(format("%32s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v)))
   end
 
   mod[name] = handler
 
+  local trackerName = 'Veneer'..name..'Tracker'
+  local handler = mod[name]
+  local frame = CreateFrame('Frame', trackerName, _G.VeneerObjectiveScroll, 'VeneerTrackerTemplate')
+  frame.title:SetText(handler.displayName)
+  mod.SetBlockStyle(frame, 'Tracker', 'Normal')
+  handler.frame = frame
+  handler.trackerName = trackerName
+  mod.orderedTrackers[index] = frame
+  mod.namedTrackers[name] = frame
+  mod.indexedTrackers[handler] = frame
+  print('|cFFFF0088' .. trackerName .. '|r created for |cFF00FFFF' .. handler.displayName .. '|r module')
+
   mod.orderedHandlers[index] = handler
   return true
 end
 
-mod.Tracker = setmetatable({}, {
-  __call = CreateHandler,
-  __tostring = function() return 'DEFAULT_TRACKING_HANDLER' end
-})
-local Tracker = mod.Tracker
-Tracker.numWatched = 0   --- number of entries being handled
-Tracker.numBlocks = 0    --- number of blocks created
-Tracker.actualBlocks = 0 --- number of blocks in use
-
-Tracker.freeBlocks = {}  --- block heap
-Tracker.usedBlocks = {}
-
-Tracker.Watched = {}     -- find by watchIndex
-Tracker.Info = {}        -- find by data ID
-Tracker.BlockInfo = {}   -- find by block ID
-Tracker.WatchInfo = {}   -- find data  by watch index
-Tracker.WatchBlock = {}  -- find block by watch index
-
-
-
-Tracker.GetBlock = function(handler, blockIndex)
-  local block = handler.usedBlocks[blockIndex]
-  if not handler.usedBlocks[blockIndex] then
-    if #handler.freeBlocks >= 1 then
-      block = handler.freeBlocks[#handler.freeBlocks]
-      handler.freeBlocks[#handler.freeBlocks] = nil
+function mod:OnEvent (event, ...)
+  local isHandled
+  print('|cFF00FF00'.. event ..'|r', ...)
+  if ( event == "QUEST_LOG_UPDATE" ) then
+    mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST);
+  elseif ( event == "TRACKED_ACHIEVEMENT_UPDATE" ) then
+    --AchievementObjectiveTracker_OnAchievementUpdate(...);
+    mod.Cheevs:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT)
+  elseif ( event == "QUEST_ACCEPTED" ) then
+    local questLogIndex, questID = ...;
+    if ( IsQuestTask(questID) ) then
+      mod:Update(OBJECTIVE_TRACKER_UPDATE_TASK_ADDED, questID);
     else
-      block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, VeneerObjectiveScroll, 'VeneerTrackerBlock')
-      block.SetStyle = mod.SetBlockStyle
-      block.Select = handler.Select
-      block.Open = handler.Open
-      block.Remove = handler.Remove
-      block.Link = handler.Link
-      block:SetScript('OnMouseUp', handler.OnMouseUp)
-      block:SetScript('OnMouseDown', handler.OnMouseDown)
-      block:ClearAllPoints()
+      if ( AUTO_QUEST_WATCH == "1" and GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then
+        AddQuestWatch(questLogIndex);
+        SetSuperTrackedQuestID(questID);
+      end
+    end
+  elseif ( event == "TRACKED_ACHIEVEMENT_LIST_CHANGED" ) then
+    local achievementID, added = ...;
+    if ( added ) then
+      mod:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED, achievementID);
+    else
+      mod:Update(OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT);
+    end
+  elseif ( event == "QUEST_WATCH_LIST_CHANGED" ) then
+    local questID, added = ...;
+    if ( added ) then
+      if ( not IsQuestTask(questID) ) then
+        mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED, questID);
+      end
+    else
+      mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST);
+    end
+  elseif ( event == "QUEST_POI_UPDATE" ) then
+    QuestPOIUpdateIcons();
+    if ( GetCVar("trackQuestSorting") == "proximity" ) then
+      SortQuestWatches();
     end
 
-    handler.usedBlocks[blockIndex] = block
+    mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST);
+
+  elseif ( event == "SCENARIO_CRITERIA_UPDATE" ) then
+    mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO);
+  elseif ( event == "SUPER_TRACKED_QUEST_CHANGED" ) then
+    mod:Update(OBJECTIVE_TRACKER_UPDATE_QUEST)
+  elseif ( event == "ZONE_CHANGED" ) then
+    local inMicroDungeon = IsPlayerInMicroDungeon();
+    if ( inMicroDungeon ~= self.inMicroDungeon ) then
+      if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
+        SetMapToCurrentZone();			-- update the zone to get the right POI numbers for the tracker
+      end
+      --SortQuestWatches();
+      self.inMicroDungeon = inMicroDungeon;
+    end
+  elseif ( event == "QUEST_AUTOCOMPLETE" ) then
+    local questId = ...;
+    AddAutoQuestPopUp(questId, "COMPLETE");
+  elseif ( event == "SCENARIO_UPDATE" ) then
+    local newStage = ...;
+    if ( newStage ) then
+      mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE);
+    else
+      mod:Update(OBJECTIVE_TRACKER_UPDATE_SCENARIO);
+    end
+  elseif ( event == "ZONE_CHANGED_NEW_AREA" ) then
+    if ( not WorldMapFrame:IsShown() and GetCVarBool("questPOI") ) then
+      SetMapToCurrentZone();			-- update the zone to get the right POI numbers for the tracker
+    end
+    SortQuestWatches();
+  elseif ( event == "QUEST_TURNED_IN" ) then
+    local questID, xp, money = ...;
+    if ( IsQuestTask(questID) ) then
+      mod.Bonus:Update()
+    end
+  elseif ( event == "PLAYER_MONEY" and self.watchMoneyReasons > 0 ) then
+    mod:Update(self.watchMoneyReasons);
   end
-  return handler.usedBlocks[blockIndex]
 end
 
+--- Done once per ui load
+local BlizzHooks = {
+  ['AddQuestWatch'] = 'AddQuestWatch',
+  ['RemoveQuestWatch'] = 'RemoveQuestWatch',
+  ['AbandonQuest'] = 'AbandonQuest',
+  ['AcknowledgeAutoAcceptQuest'] = 'AcknowledgeAutoAcceptQuest',
+  ['AddAutoQuestPopUp'] = 'AddAutoQuestPopUp',
+  ['RemoveAutoQuestPopUp'] = 'RemoveAutoQuestPopUp',
+  ['AddTrackedAchievement'] = 'AddTrackedAchievement',
+  ['RemoveTrackedAchievement'] = 'RemoveTrackedAchievement',
+  ['SetSuperTrackedQuestID'] = 'SetSuperTrackedQuestID'
+}
+local VeneerData
 function mod:OnInitialize()
-  self.InitializeWrapper()
-  self.InitializeXPTracker()
-  mod.SetEvents()
+  local c = mod.Conf.Wrapper
+  VeneerData = _G.VeneerData
+  VeneerData.CallLog = VeneerData.CallLog or {}
+  if not mod.isHooked then
+    mod.isHooked = true
+    for blizzFunc, veneerFunc in pairs(BlizzHooks) do
+      if mod[veneerFunc] then
+        hooksecurefunc(blizzFunc, mod[veneerFunc])
+      else
+        hooksecurefunc(blizzFunc, function(...)
+          print('|cFFFF0088securehook('..tostring(blizzFunc)..')|r args:', ...)
+          tinsert(VeneerData.CallLog, {blizzFunc, ...})
+        end)
+      end
+    end
+  end
+  Scroller:SetScrollChild(Scroll)
+  Scroller:SetWidth(c.Width)
+  Scroll:SetPoint('TOPLEFT', Scroller, 'TOPLEFT')
+  Scroll:SetWidth(c.Width)
   ObjectiveTrackerFrame:UnregisterAllEvents()
   ObjectiveTrackerFrame:Hide()
 end
+
+--- Done any time the the minimize button is toggled up
+
+function mod:OnEnable()
+  for id, name in ipairs(mod.orderedNames) do
+    if not mod.orderedHandlers[id] then
+      Tracker_Initialize(mod.DefaultTracker, name, id)
+    end
+  end
+
+  for event, func in pairs(mod) do
+    if type(func) == 'function' and event:match('^[A-Z_]+$') then
+      print('|cFFFF44FFlistening to', event)
+      Wrapper:RegisterEvent(event)
+    end
+  end
+
+  local c = mod.Conf.Wrapper
+  Wrapper:SetPoint(c.AnchorPoint, UIParent, c.AnchorPoint, c.OffsetX, c.OffsetY)
+  B.Conf.FramePosition[Wrapper:GetName()] = {c.AnchorPoint, c.AnchorPoint, c.OffsetX, c.OffsetY}
+  Wrapper:SetWidth(c.Width)
+
+
+  mod.InitializeWidgets()
+  mod:Update()
+end
+
+function mod:OnDisable()
+
+end
+
+
--- a/ObjectiveEvents.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveEvents.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -5,133 +5,17 @@
 -- Created: 3/30/2016 1:23 AM
 local B = select(2,...).frame
 local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
-local print = B.print('ObjectiveEvent')
-
-local isHooked
-local SmallEvents = {
-  QUEST_ACCEPTED = 'OnQuestAccepted',
-  QUEST_REMOVED = 'OnQuestRemoved'
-}
-
---- Using the same values as Blizzard_ObjectiveTracker for use in securehook
-local OBJECTIVE_TRACKER_UPDATE_QUEST				        		= 0x0001;
-local OBJECTIVE_TRACKER_UPDATE_QUEST_ADDED		      		= 0x0002;
-local OBJECTIVE_TRACKER_UPDATE_TASK_ADDED		    	  		= 0x0004;
-local OBJECTIVE_TRACKER_UPDATE_SCENARIO			      	  	= 0x0008;
-local OBJECTIVE_TRACKER_UPDATE_SCENARIO_NEW_STAGE		  	= 0x0010;
-local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT			      	= 0x0020;
-local OBJECTIVE_TRACKER_UPDATE_ACHIEVEMENT_ADDED		  	= 0x0040;
-local OBJECTIVE_TRACKER_UPDATE_SCENARIO_BONUS_DELAYED		= 0x0080;
-
-local OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST			      	= 0x0100;
-local OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP	= 0x0200;
-local OBJECTIVE_TRACKER_UPDATE_MODULE_BONUS_OBJECTIVE		= 0x0400;
-local OBJECTIVE_TRACKER_UPDATE_MODULE_SCENARIO	    		= 0x0800;
-local OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT		  	= 0x1000;
-
-local OBJECTIVE_TRACKER_UPDATE_STATIC					        	= 0x0000;
-local OBJECTIVE_TRACKER_UPDATE_ALL				          		= 0xFFFF;
-
-local OBJECTIVE_TRACKER_UPDATE_REASON                   = OBJECTIVE_TRACKER_UPDATE_ALL;		-- default
-local OBJECTIVE_TRACKER_UPDATE_ID                       = 0;
-
-local HandlerEvents = {
-  QUEST_ACCEPTED = 0x0003,
-  QUEST_WATCH_LIST_CHANGED = 0x0003,
-  SUPER_TRACKED_QUEST_CHANGED = mod.Quest,
-  QUEST_LOG_UPDATE = mod.Quest,
-  TRACKED_ACHIEVEMENT_LIST_CHANGED = mod.Cheevs,
-  TRACKED_ACHIEVEMENT_UPDATE = mod.Cheevs
-}
-
-local BlizzHooks = {
-  ['AddQuestWatch'] = 'AddQuestWatch',
-  ['RemoveQuestWatch'] = 'RemoveQuestWatch',
-  ['AbandonQuest'] = 'AbandonQuest',
-  ['AcknowledgeAutoAcceptQuest'] = 'AcknowledgeAutoAcceptQuest',
-  ['AddAutoQuestPopUp'] = 'AddAutoQuestPopUp',
-  ['RemoveAutoQuestPopUp'] = 'RemoveAutoQuestPopUp',
-  ['RemoveTrackedAchievement'] = 'RemoveTrackedAchievement'
-}
-
-mod.SetEvents = function()
-
-  for event, _ in pairs(SmallEvents) do
-    mod:RegisterEvent(event)
-  end
-
-  for event, _ in pairs(HandlerEvents) do
-    mod:RegisterEvent(event)
-  end
-  mod:SetScript('OnEvent', mod.OnEvent)
-
-
-  if not isHooked then
-    VeneerData.CallLog = {}
-    isHooked = true
-    for blizzFunc, veneerFunc in pairs(BlizzHooks) do
-      if mod[veneerFunc] then
-        hooksecurefunc(blizzFunc, mod[veneerFunc])
-      else
-        hooksecurefunc(blizzFunc, function(...)
-          print('catching', blizzFunc, ...)
-          tinsert(VeneerData.CallLog, {blizzFunc, ...})
-        end)
-      end
-    end
-
-  end
-end
-
-function mod:OnEvent (event, ...)
-  local isHandled
-  if SmallEvents[event] then
-    print('|cFF00FF00'..SmallEvents[event]..'(' ..event..'|r', ...)
-    mod[SmallEvents[event]](event, ...)
-    isHandled = true
-  end
-  if HandlerEvents[event] then
-    print('|cFF0088FF'..event..'|r wrapper update')
-    mod.UpdateWrapper(event)
-    isHandled = true
-  end
-  if not isHandled then
-    print('|cFFFF4400'..event..'|r', ...)
-  end
-end
+local print = B.print('Objectives')
 
 --------------------------------------------------------------------
 --- Events that are handled by Blizzard_ObjectiveTracker
 --------------------------------------------------------------------
-print(mod:GetName())
-mod.OnQuestAccepted = function(_, questLogIndex, questID)
-  AddQuestWatch(questLogIndex)
-  SetSuperTrackedQuestID(questID)
-end
-
-mod.OnQuestComplete = function(_, questLogIndex, questID)
-  QuestPOIUpdateIcons()
-end
-
-mod.OnQuestFinished = function(_, questLogIndex, questID)
-  mod.TrackClosest()
-  RemoveQuestWatch(questLogIndex)
-end
-
-
-mod.OnQuestRemoved = function(_, questLogIndex, questID)
-
-  mod.UpdateWrapper(0x00000003)
-
-end
-
-mod.OnQuestFromLocation = function(event) end
 
 -------------------------------------------------------------------
 --- Function hooks for BlizzUI compatibility
 -------------------------------------------------------------------
 mod.AddQuestWatch = function(questID)
-  mod.UpdateWrapper(0x00000003)
+    mod:Update(0x00000003)
 end
 
 mod.RemoveQuestWatch = function(questIndex, ...)
@@ -147,34 +31,40 @@
     print('cleaning dead WatchInfo entry')
     mod.Quest.WatchInfo[info.watchIndex] = nil
   end
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST)
+end
 
-  mod.UpdateWrapper('RemovedQuestWatch' .. tostring(questIndex))
-  QuestPOIUpdateIcons()
+mod.AddTrackedAchievement = function(cheevID)
+  mod.CleanWidgets()
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT)
 end
 
+
 mod.RemoveTrackedAchievement = function(cheevID)
   print('|cFFFF8800UntrackAchievement', cheevID)
   mod.CleanWidgets()
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_ACHIEVEMENT)
 end
 
 mod.AcceptQuest = function()
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST_ADDED)
 end
 
 mod.AbandonQuest = function()
-
   QuestPOIUpdateIcons()
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST)
+end
+mod.TurnInQuest = function()
+  QuestPOIUpdateIcons()
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_QUEST)
+end
+mod.AddAutoQuestPopUp = function(...)
+   mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP)
+end
+mod.RemoveAutoQuestPopUp = function(...)
+  mod:Update(OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP)
 end
 
-mod.TurnInQuest = function()
-
-  QuestPOIUpdateIcons()
-end
-
-mod.AddAutoQuestPopUp = function(...)
- print('|cFFFF8800AddAutoQuestPopUp|r', ...)
- mod.UpdateWrapper(OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP)
-end
-mod.RemoveAutoQuestPopUp = function(...)
-  print('|cFFFF8800RemoveAutoQuestPopUp|r', ...)
-  mod.UpdateWrapper(OBJECTIVE_TRACKER_UPDATE_MODULE_AUTO_QUEST_POPUP)
+mod.SetSuperTrackedQuestID = function(questID)
+  mod:Update()
 end
\ No newline at end of file
--- a/ObjectiveFrame.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveFrame.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -8,10 +8,11 @@
 local ipairs, max, min, unpack, floor, pairs, tostring, type, band = ipairs, max, min, unpack, floor, pairs, tostring, type, bit.band
 local IsResting, UnitXP, UnitXPMax, GetXPExhaustion = IsResting, UnitXP, UnitXPMax, GetXPExhaustion
 local UnitLevel, IsQuestWatched, UIParent = UnitLevel, IsQuestWatched, UIParent
-local Quest, Bonus, Cheevs = mod.Quest, mod.Bonus, mod.Cheevs
+local DefaultTracker, Quest, Bonus, Cheevs = mod.DefaultTracker, mod.Quest, mod.Bonus, mod.Cheevs
 local CreateFrame = CreateFrame
-local print = B.print('Objectives')
+local print = B.print('ObjWrapper')
 local unitLevel = 1
+local OBJECTIVE_TRACKER_UPDATE_REASON = OBJECTIVE_TRACKER_UPDATE_REASON
 --------------------------------------------------------------------
 --- Global frame layout
 --------------------------------------------------------------------
@@ -41,138 +42,119 @@
 local headerOutline, headerColor, headerSpacing = 'OUTLINE', {1,1,1,1}, 2
 local wrapperPosition = {'RIGHT', UIParent, 'RIGHT', -84, 0}
 
-mod.InitializeWrapper = function()
+local band = bit.band
+local currentPosition, anchorFrame, anchorPoint
+function mod:Update (reason, dataID)
+  local updateWrapper = 0
+  local hasStuff
+  local insertingStuff
+  reason = reason or OBJECTIVE_TRACKER_UPDATE_REASON
+  currentPosition = 0
+  anchorPoint = 'TOPLEFT'
+  anchorFrame = Scroll
 
-  mod.SetBlockStyle(Scroller, 'Scroller', 'Normal')
-  mod.SetBlockStyle(Scroller, 'Scroll', 'Normal')
-  mod.SetBlockStyle(Wrapper, 'Wrapper', 'Normal')
+  local wrapperHeight = 0
+  for id, handler in pairs(mod.orderedHandlers) do
+    local frame = handler.frame
 
-  for i, name in ipairs(orderedNames) do
-    if not mod.orderedHandlers[i] then
-      if mod.Tracker(name, i) then
-        local handler = mod[name]
-        local tracker = CreateFrame('Frame', 'Veneer'..name..'Tracker', Scroll, 'VeneerTrackerTemplate')
-        tracker.title:SetText(handler.displayName)
-        mod.SetBlockStyle(tracker, 'Tracker', 'Normal')
-        handler.Tracker = tracker
-        mod.orderedTrackers[i] = tracker
-        mod.namedTrackers[name] = tracker
-        mod.indexedTrackers[handler] = tracker
-        print('created new tracker frames for new handler')
-      end
+    print(format('|cFF00FFFFbitcheck (%04X vs %04x+%04x):|r', reason, handler.updateReasonModule, handler.updateReasonEvents), band(reason, handler.updateReasonModule + handler.updateReasonEvents))
+    if band(reason, handler.updateReasonModule + handler.updateReasonEvents) > 0 then
+      handler:Update(reason, dataID)
+      print('|cFF00FF00'..id..'|r', handler.displayName, 'count:', handler.numWatched)
+      insertingStuff = true
+    else
+      print('|cFFFF0088'..id..'|r', 'no reason')
+    end
+
+    if handler.numWatched >= 1 then
+      hasStuff = true
+      currentPosition = currentPosition + 1
+      frame:SetParent(Scroll)
+      frame:SetPoint('TOPLEFT', anchorFrame, anchorPoint, 0, 0)
+      print('  |cFF00BBFFpinning to', anchorFrame:GetName(), anchorPoint)
+      anchorFrame = handler.frame
+      anchorPoint = 'BOTTOMLEFT'
+
+      print('current frame height:', frame.height)
+      wrapperHeight = wrapperHeight + frame.height
+      print('|cFFFF0088total height:', wrapperHeight)
+    else
+      handler.frame:Hide()
     end
   end
 
-  Scroller:SetScrollChild(Scroll)
 
-  mod.InitializeWrapperWidgets()
-  if B.Conf.ObjectiveTrackerMinimized then
-    Scroller_OnShow(Scroller)
+  if  hasStuff or insertingStuff then
+
+    print('updating height to', wrapperHeight)
+    Wrapper:SetHeight(wrapperHeight)
+    Scroller:SetHeight(wrapperHeight)
+    Scroll:SetHeight(wrapperHeight)
+    print('|cFFFF8800Wrapper:', Wrapper:GetSize())
+    for i = 1, Wrapper:GetNumPoints() do
+      print(' ', Wrapper:GetPoint(i))
+    end
+    print('  |cFF00FFFFScroller:', Scroller:GetSize())
+    for i = 1, Scroller:GetNumPoints() do
+      print(' ', Scroller:GetPoint(i))
+    end
+    print('  |cFF00FFFFScroll:', Scroll:GetSize())
+    for i = 1, Scroll:GetNumPoints() do
+      print(' ', Scroll:GetPoint(i))
+    end
+
+    Wrapper:Show()
+    Scroller:Show()
+    Scroll:Show()
   end
-  mod.UpdateWrapperStyle()
+
 end
 
-mod.InitializeXPTracker = function()
-  local XPBar = Wrapper.XPBar
-  if UnitLevel('player') == 100 then
-    XPBar:Hide()
-    return
+DefaultTracker.GetBlock = function(handler, blockIndex)
+  local block = handler.usedBlocks[blockIndex]
+  if not handler.usedBlocks[blockIndex] then
+    if #handler.freeBlocks >= 1 then
+      block = handler.freeBlocks[#handler.freeBlocks]
+      handler.freeBlocks[#handler.freeBlocks] = nil
+    else
+      block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, Scroll, 'VeneerTrackerBlock')
+      block.SetStyle = mod.SetBlockStyle
+      block.Select = handler.Select
+      block.Open = handler.Open
+      block.Remove = handler.Remove
+      block.Link = handler.Link
+      block:SetScript('OnMouseUp', handler.OnMouseUp)
+      block:SetScript('OnMouseDown', handler.OnMouseDown)
+      block.attachmentHeight = 0
+      block:ClearAllPoints()
+    end
+
+    handler.usedBlocks[blockIndex] = block
   end
-
-  --- xp bar
-  XPBar:SetWidth(mod.Conf.Wrapper.WrapperWidth - Wrapper.CloseButton:GetWidth())
-  XPBar.statusbg:SetAllPoints(XPBar)
-  XPBar:RegisterEvent('DISABLE_XP_GAIN')
-  XPBar:RegisterEvent('ENABLE_XP_GAIN')
-  XPBar:SetScript('OnEvent', mod.UpdateXP)
-
-  if not IsXPUserDisabled() then
-    mod.EnableXP(XPBar)
-  else
-    mod.DisableXP(XPBar)
-  end
-
-  mod.UpdateXP(XPBar)
+  return handler.usedBlocks[blockIndex]
 end
 
-mod.EnableXP = function(self)
-  self:RegisterEvent('PLAYER_XP_UPDATE')
-  self:RegisterEvent('PLAYER_LEVEL_UP')
-  self:RegisterEvent('PLAYER_UPDATE_RESTING')
-  self.statusbg:SetTexture(0,0,0,.25)
-  self:Show()
-end
-
-mod.DisableXP = function(self)
-  self:UnregisterEvent('PLAYER_XP_UPDATE')
-  self:UnregisterEvent('PLAYER_LEVEL_UP')
-  self:UnregisterEvent('PLAYER_UPDATE_RESTING')
-  self.statusbg:SetTexture(0.5,0.5,0.5,0.5)
-  self:Hide()
-end
-
-mod.UpdateXP = function(self, event)
-  if event == 'DISABLE_XP_GAIN' then
-    mod.DisableXP(self)
-  elseif event == 'ENABLE_XP_GAIN' then
-    mod.EnableXP(self)
-  end
-
-  if not IsXPUserDisabled() then
-
-    local xp = UnitXP('player')
-    local xpmax = UnitXPMax('player')
-    local rest = GetXPExhaustion()
-    self.foreground:SetWidth((xp/xpmax) * self:GetWidth())
-    if rest then
-      self.rested:ClearAllPoints()
-      if xp == 0 then
-        self.rested:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, 0)
-      else
-        self.rested:SetPoint('TOPLEFT', self.fg, 'TOPRIGHT', 0, 0)
-      end
-
-      if (xp + rest) > xpmax then
-        self.rested:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', 0, 0)
-      else
-        self.rested:SetWidth((rest/xpmax) * self:GetWidth())
-      end
-      self.rested:SetPoint('BOTTOM', self, 'BOTTOM')
-      self.rested:Show()
-    else
-      self.rested:Hide()
-    end
-
-    if IsResting() then
-      self.statusbg:SetTexture(.2,.8,.2,.5)
-    else
-      self.statusbg:SetTexture(0,0,0,.25)
-    end
-    self.xpText:SetText(xp .. '/'.. xpmax .. (rest and (' ('..tostring(rest)..')') or ''))
-  end
-end
-
-
-
-mod.UpdateTracker = function(handler)
-  local tracker = handler.Tracker
+DefaultTracker.Update = function (self, reason, dataID)
+  local tracker = self.frame
   print('|cFFFF4400'..tracker:GetName().. '|r:Update()')
   local blockIndex = 0
-  local trackerHeight = tracker.titleHeight
+  local trackerHeight = 0
 
 
-  previousBlock = tracker.title
-  local numWatched = handler.GetNumWatched()
-  local numBlocks = handler.numBlocks
+  self.currentAnchor = tracker.titlebg
+  local numWatched = self:GetNumWatched()
+  local numBlocks = self.numBlocks
   local actualBlocks = 0
   for watchIndex = 1, 25 do
     blockIndex = blockIndex + 1
     if watchIndex <= numWatched then
-      local info = handler:GetInfo(watchIndex)
+      local info = self:GetInfo(watchIndex)
       if info then
-        local currentBlock = mod.UpdateTrackerBlock(handler, blockIndex, info)
-        previousBlock = currentBlock
+        local currentBlock = self:UpdateBlock(blockIndex, info)
+        self.currentAnchor = currentBlock
         print('    |cFFFFFF00'..watchIndex..'|r', '|cFF00FF00'..currentBlock:GetName()..'|r', currentBlock.height)
+        print(currentBlock:IsVisible())
+        print(currentBlock:GetPoint(1))
         trackerHeight = trackerHeight + currentBlock.height
         numBlocks = max(numBlocks, watchIndex)
         actualBlocks = actualBlocks + 1
@@ -181,8 +163,8 @@
       end
 
     elseif watchIndex <= numBlocks then
-      local used = handler.usedBlocks
-      local free = handler.freeBlocks
+      local used = self.usedBlocks
+      local free = self.freeBlocks
       print('clean up dead quest block')
       if used[blockIndex] then
         used[blockIndex]:Hide()
@@ -195,16 +177,24 @@
       break -- done with quest stuff
     end
   end
-  handler.numWatched = numWatched
-  handler.numBlocks = numBlocks
-  handler.actualBlocks = actualBlocks
-  handler:Report()
+  self.numWatched = numWatched
+  self.numBlocks = numBlocks
+  self.actualBlocks = actualBlocks
+  self:Report()
 
+  tracker.previousHeight = tracker.height
   if numBlocks >= 1 then
     previousBlock = nil
-    tracker.height = trackerHeight
+
+    tracker.height = trackerHeight + tracker.titlebg:GetHeight()
+    tracker:SetHeight(tracker.height)
+    tracker:Show()
+
+    print(tracker.height)
+
   else
     tracker.height = 0
+    tracker:Hide()
   end
 
   return tracker.numWatched, tracker.numAll
@@ -215,54 +205,53 @@
 -- @param blockNum the ordered block to be updated, not a watchIndex value
 -- @param info the reference returned by the GetXInfo functions
 -- REMEMBER: t.info and questData[questID] are the same table
-mod.UpdateTrackerBlock = function (handler, blockIndex, info)
+DefaultTracker.UpdateBlock = function (self, blockIndex, info)
   local print = B.print('BlockParse')
   print('  Read list item |cFF00FFFF'..blockIndex..'|r')
   if not blockIndex or not info then
     return
   end
-  local tracker = handler.Tracker
-  local t = handler:GetBlock(blockIndex)
-  t.handler = handler
+  local frame = self.frame
+  local t = self:GetBlock(blockIndex)
+  t.handler = self
   t.info = info
   t.mainStyle = info.mainStyle or 'Normal'
   t.subStyle = info.subStyle
 
   info.blockIndex = blockIndex
-  if info.questID then handler.QuestBlock[info.questID] = t end
-  if info.questLogIndex then handler.LogBlock[info.questLogIndex] = t end
-  if info.watchIndex then handler.WatchBlock[info.watchIndex] = t end
-  handler.BlockInfo[blockIndex] = info
-
+  if info.questID then self.QuestBlock[info.questID] = t end
+  if info.questLogIndex then self.LogBlock[info.questLogIndex] = t end
+  if info.watchIndex then self.WatchBlock[info.watchIndex] = t end
+  self.BlockInfo[blockIndex] = info
 
   t.attachmentHeight = 0
-
-
-
-
-
-  if info.isComplete == 1 then
-    if info.popupInfo then
+  if info.isComplete then
+    if mod.AutoQuest.Info[info.questID] then
       t.status:SetText('(Click to Complete)')
+      t.status:Show()
     else
       t.status:SetText('Ready to turn in')
+      t.status:Show()
     end
   elseif info.completed then
     t.status:SetText(nil)
+    t.status:Hide()
   elseif info.numObjectives >= 1 then
     t.attachmentHeight = 0
     t.status:Show()
-    print('    lines to build:', info.numObjectives)
+    print('    lines to parse:', info.numObjectives)
     local text = ''
 
     mod.UpdateObjectives(t, info, text)
+    print('    |cFF00FF00attachment', t.attachmentHeight)
   elseif info.description then
     t.status:SetText(info.description)
+    t.status:Show()
   else
     t.status:SetText(nil)
+    t.status:Show()
   end
   t.title:SetText(info.title)
-  print('     ', t.status:CanWordWrap(), t.status:GetStringHeight())
 
 
   if info.specialItem and not info.itemButton then
@@ -272,15 +261,16 @@
     --info.itemButton = nil
   end
 
-  if previousBlock then
-    t:SetPoint('TOPLEFT', previousBlock, 'BOTTOMLEFT', 0, 0)
-    t:SetPoint('RIGHT', tracker,'RIGHT', 0, 0)
-    print('    anchor to|cFF0088FF', previousBlock:GetName())
+  if self.currentAnchor then
+    t:SetPoint('TOPLEFT', self.currentAnchor, 'BOTTOMLEFT', 0, 0)
+    t:SetPoint('RIGHT', frame,'RIGHT', 0, 0)
+    print('    anchor to|cFF0088FF', self.currentAnchor:GetName())
   end
 
 
   --- metrics are calculated in SetStyle
-  t:SetStyle('TrackerBlock', handler.name, t.mainStyle, t.subStyle)
+  t:SetStyle('TrackerBlock', self.name, t.mainStyle, t.subStyle)
+  print('     |cFFFFFF00height|r', t.height)
   t:Show()
 
   print('  |cFF00FFFF)|r -> ', t, t:GetHeight())
@@ -338,11 +328,14 @@
   return t
 end
 
+
+
 mod.UpdateObjectives = function(block, info, text)
   local print = B.print('BlockLine')
   print('   |cFF00FF00objective updates for', block:GetName())
 
   local attachmentHeight = block.attachmentHeight
+  print(attachmentHeight)
   if info.description and not(info.earnedBy or info.isComplete) then
     print('  -- has description text:', select('#', info.description), info.description)
     text = info.description
@@ -350,6 +343,7 @@
   local completionScore, completionMax = 0, 0
 
   for i, line in ipairs(info.objectives) do
+    print(attachmentHeight)
     print('     |cFF88FF00objective', i)
     block.handler.ParseObjective(line, info)
 
@@ -360,7 +354,8 @@
 
     if line.widget then
       if attachmentHeight == 0 then
-        attachmentHeight = block.status.spacing
+        attachmentHeight = (block.status.spacing or block.status:GetSpacing()) * 2
+        --print(attachmentHeight)
       end
       line.widget:Show()
       line.widget:SetParent(block)
@@ -377,6 +372,8 @@
     end
   end
 
+
+
   block.completionScore = completionScore / completionMax
   block.attachmentHeight = attachmentHeight
 
@@ -396,7 +393,7 @@
 -- * lines    - number of non-wrapped text lines to account for line space; may be discarded depending on things
 -- * money    - boolean that determines listening for money events or not
 -- * progress - number ranging 0 to 2 indicating none/partial/full completion respectively
-mod.Tracker.ParseObjective = function(line, info)
+DefaultTracker.ParseObjective = function(line, info)
 
   if line.finished then
     line.progress = 2
@@ -482,6 +479,7 @@
 mod.Quest.numButtons = 0
 local usedButtons = mod.Quest.itemButtons
 local freeButtons = mod.Quest.freeButtons
+--[=[
 mod.UpdateWrapper = function(reason)
   print('|cFF00FFFFUpdateWrapper:|r', reason)
   unitLevel = UnitLevel('player')
@@ -492,16 +490,16 @@
   scrollHeight = 0
   for i, handler in ipairs(orderedHandlers) do
     mod.UpdateTracker(handler)
-    local tracker = handler.Tracker
+    local frame = handler.frame
     if handler.actualBlocks >= 1 then
-      tracker:SetParent(Scroll)
-      tracker:SetPoint('TOPLEFT', Scroll, 'TOPLEFT', 0, - scrollHeight)
-      tracker:SetSize(wrapperWidth, tracker.height)
-      print('|cFF00FFFF'..tracker:GetName()..'|r h:|cFF00FF00', tracker.height, '|r y:|cFF00FF00', -scrollHeight)
-      scrollHeight = scrollHeight + tracker.height
-      tracker:Show()
+      frame:SetParent(Scroll)
+      frame:SetPoint('TOPLEFT', Scroll, 'TOPLEFT', 0, - scrollHeight)
+      frame:SetSize(wrapperWidth, frame.height)
+      print('|cFF00FFFF'..frame:GetName()..'|r h:|cFF00FF00', frame.height, '|r y:|cFF00FF00', -scrollHeight)
+      scrollHeight = scrollHeight + frame.height
+      frame:Show()
     else
-      tracker:Hide()
+      frame:Hide()
     end
     wrapperBlocks = wrapperBlocks + handler.actualBlocks
   end
@@ -561,6 +559,7 @@
   mod.UpdateActionButtons()
 
 end
+--]=]
 
 --- Queue any active item buttons for update for that frame
 mod.UpdateActionButtons = function(updateReason)
--- a/ObjectiveInfo.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveInfo.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -19,7 +19,7 @@
 local LE_QUEST_FREQUENCY_WEEKLY = LE_QUEST_FREQUENCY_WEEKLY
 local FACTION_ALLIANCE, LE_QUEST_FACTION_HORDE, FACTION_HORDE, LE_QUEST_FACTION_HORDE = FACTION_ALLIANCE, LE_QUEST_FACTION_HORDE, FACTION_HORDE, LE_QUEST_FACTION_HORDE
 
-local Tracker, Bonus, AutoQuest, Quest, Cheevs = mod.Tracker, mod.Bonus, mod.AutoQuest, mod.Quest, mod.Cheevs
+local Tracker, Bonus, AutoQuest, Quest, Cheevs = mod.DefaultTracker, mod.Bonus, mod.AutoQuest, mod.Quest, mod.Cheevs
 --------------------------------------------------------------------
 --- Tracker-specific data retrieval functions
 --------------------------------------------------------------------
@@ -31,9 +31,10 @@
 AutoQuest.LogBlock = {}
 AutoQuest.QuestBlock = {}
 AutoQuest.WatchBlock = {}
-AutoQuest.GetNumWatched = function()
-  AutoQuest.numWatched = GetNumAutoQuestPopUps()
-  return AutoQuest.numWatched
+function AutoQuest:GetNumWatched ()
+  print(self.name, self)
+  self.numWatched = GetNumAutoQuestPopUps()
+  return self.numWatched
 end
 AutoQuest.GetInfo = function(self, popupIndex)
 
@@ -66,7 +67,8 @@
 local taskData = {}
 Bonus.QuestBlock = {}
 Bonus.TaskWatch = {}
-Bonus.GetNumWatched = function()
+function Bonus:GetNumWatched ()
+  print(self.name, self)
   local tasks = GetTasksTable()
   local numTasks = 0
   Bonus.TaskWatch = {}
@@ -86,6 +88,7 @@
 end
 
 Bonus.GetInfo = function(self, taskIndex)
+  print(self.name, self)
   return Bonus.TaskWatch[taskIndex]
 end
 
@@ -183,16 +186,21 @@
 Quest.LogBlock = {}
 Quest.LogInfo = {}
 
-Quest.GetNumWatched = function()
-  Quest.numAll = GetNumQuestLogEntries()
-  Quest.numWatched = GetNumQuestWatches()
-  return Quest.numWatched
+function Quest:GetNumWatched ()
+  print(self.name, self)
+  self.numAll = GetNumQuestLogEntries()
+  self.numWatched = GetNumQuestWatches()
+  return self.numWatched, self.numAll
 end
 Quest.GetInfo = function (self, watchIndex)
   print('|cFF00DDFFQuest|r.|cFF0088FFGetInfo(|r'.. tostring(watchIndex)..'|r)')
   local questID, title, questIndex, numObjectives, requiredMoney, isComplete,
   startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
 
+  if not questIndex then
+    return
+  end
+
   local _, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, _, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(questIndex)
 
 
--- a/ObjectiveStyle.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveStyle.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -15,19 +15,6 @@
 local headerOutline, headerSpacing = 'OUTLINE', 2
 
 
-mod.defaults.Wrapper = {
-  WrapperPoint = 'TOPRIGHT',
-  WrapperFloatX = -25,
-  WrapperFloatV = 'TOP',
-  WrapperFloatY = -200,
-
-  WrapperWidth = 270,
-  WrapperHeight = 600,
-}
-mod.defaults.Tracker = {
-  HeaderHeight = 24,
-}
-
 mod.defaults.Style = {
   Format = {
     Frame = {
@@ -56,23 +43,17 @@
       Indent = 2,
     },
     titlebg = {
-      Background = {0, 0, 0, 1},
-      Width = 270,
     },
     status = {
       Width = 270,
       Spacing = 0,
     },
     statusbg = {
-      Width = 270,
     },
     Frame = {
-      Width = 270,
     }
   },
   Wrapper = {
-    Frame = {
-    BackgroundComplex = {Left = {'', 0, 0.4, 0,1, 100}, Right={'', 0.6,1,0,1}, Tile = {'', 0.4,.6,0,1, 100}}, },
     title = {
       Font = {wrapperHeadFont, wrapperHeadSize, wrapperHeadOutline},
       Spacing = 4,}
@@ -96,12 +77,12 @@
         Gradient = { 'HORIZONTAL', MinColor = {0.7, 0, 0.9, 0}, MaxColor = {.7, 0, 0.9, .25}},
       },
       title = {
-        TextColor = {1,1,1,0.8},
+        TextColor = {1,1,1,1},
         Font = {titleFont, titleSize, titleOutline},
         Spacing = titleSpacing,
       },
       status = {
-        TextColor = {1,1,1,0.8},
+        TextColor = {1,1,1,1},
         Font = {textFont, textSize, textOutline},
         Spacing = textSpacing,
       },
@@ -122,7 +103,7 @@
         Spacing = titleSpacing,
       },
       status = {
-        TextColor = {1,1,1,0.5},
+        TextColor = {1,1,1,1},
         Font = {textFont, textSize, textOutline},
         Spacing = textSpacing,
       },
@@ -163,14 +144,14 @@
     },
     Complete = {
       title = {
-        TextColor = {1,1,1,0.5},
+        TextColor = {1,1,1,1},
         Font = {titleFont, titleSize, titleOutline},        Spacing = titleSpacing,
       },
       titlebg = {
         Gradient = {'HORIZONTAL', MinColor = {0, 1, 0, 0},          MaxColor = {0, 1, 0, 0.34},        },
       },
       status = {
-        TextColor = {1,1,1,0.5},
+        TextColor = {1,1,1,1},
         Font = {textFont, textSize, textOutline},        Spacing = textSpacing,
       },
       statusbg = {
@@ -257,23 +238,40 @@
   local c = mod.defaults.Normal
   local style_list = {... }
   local styleName = frameType .. '-' .. table.concat(style_list,'')
-  local previousClass = mod.Conf.Style[frameType]
+  local previousClass = {mod.Conf.Style[frameType] }
+  local previousClassString = {'frame' }
+  local parentName
 
   if not style_cache[styleName] then
     local style = {}
 
+    --[[
     if mod.defaults.Style[frameType] then
       print(' setting style class |cFF00FFFF'..frameType)
     else
       print(' resorting to class Normal (missing |cFFFF8800'.. frameType..'|r)')
     end
+    --]]
     local normal = mod.defaults.Style.Normal
     local root =  mod.defaults.Style[frameType] or normal
     for i, className in ipairs(style_list) do
+      print('|cFF00FF00'..i..'|r', className)
       local class = normal
-      if previousClass and previousClass[className] then
-        class = previousClass[className]
-        print('  ChildClass |cFFFF0088'.. className .. '|r')
+      local childClass
+      if previousClass  then
+        for i = #previousClass, 1, -1  do
+          print('checking if '..className..' child of '.. previousClassString[i])
+          if previousClass[i][className] then
+            print('  it is!')
+            childClass = previousClass[i][className]
+            parentName = previousClassString[i]
+            break
+          end
+        end
+      end
+      if childClass then
+        class = childClass
+        print('  ChildClass '..parentName..'.|cFFFF0088'.. className .. '|r')
       elseif root[className] then
         class = root[className]
         print('  SubClass |cFF0088FF'.. className .. '|r')
@@ -281,19 +279,20 @@
         class = normal[className]
         print('  SubClass Normal.|cFFFF0088'..className..'|r')
       else
-        print('  SubClass not found '..className..'')
+        --print('  SubClass not found '..className..'')
       end
-      previousClass = class
+      tinsert(previousClass, class)
+      tinsert(previousClassString, className)
 
       for elementName, element in pairs(class) do
         if not elementName:match('^%u') then
-          print('   scanning Element |cFF8800FF'.. elementName ..'|r')
+          --print('   scanning Element |cFF8800FF'.. elementName ..'|r')
           if not style[elementName] then
             style[elementName] = {}
           end
           for key, value in pairs(element) do
             if mod.SetBlockAttribute[key] then
-              print('   |cFF00FF00'..elementName..'|r.|cFF00FFFF'..key..' =', (type(value) == 'table' and ('{'..table.concat(value,', ')..'}') or tostring(value)))
+              --print('   |cFF00FF00'..elementName..'|r.|cFF00FFFF'..key..' =', (type(value) == 'table' and ('{'..table.concat(value,', ')..'}') or tostring(value)))
               style[elementName][key] = value
             end
 
@@ -310,17 +309,22 @@
     end
 
 
-    print('result for: ', frame:GetName())
+    --[[print('result for: ', frame:GetName())
     for k,v in pairs(style) do
       if type(v) == 'table' and not k:match('^%u') then
         for kk, vv in pairs(v) do
-        print('  |cFFFFFF00'..k..'|r.|cFF00FF00'..kk..'|r =', (type(vv) == 'table' and ('{'..table.concat(vv,', ')..'}') or tostring(vv)))
+        --print('  |cFFFFFF00'..k..'|r.|cFF00FF00'..kk..'|r =', (type(vv) == 'table' and ('{'..table.concat(vv,', ')..'}') or tostring(vv)))
         end
       else
-        print(' |cFFFFFFFF' .. k ..'|r =', tostring(v))
+        --print(' |cFFFFFFFF' .. k ..'|r =', tostring(v))
       end
     end
+    --]]
+    print('saving |cFFFFFF00'..styleName)
     style_cache[styleName] = style
+  else
+
+    print('using |cFFFF00FF'..styleName)
   end
 
   local style = style_cache[styleName]
@@ -338,7 +342,7 @@
 
         for attributeName, value in pairs(styleset) do
           if mod.SetBlockAttribute[attributeName] then
-            print('  add function '..elementName..':'.. attributeName ..'(', (type(value) == 'table' and ('{'..table.concat(value,', ')..'}') or tostring(value)), ')')
+            --print('  add function '..elementName..':'.. attributeName ..'(', (type(value) == 'table' and ('{'..table.concat(value,', ')..'}') or tostring(value)), ')')
 
 
             --mod.SetBlockAttribute[attributeName](region, value)
@@ -349,9 +353,9 @@
 
             --- Set any frame.blah variables used in Updates
             if block_vars[elementName .. attributeName] then
-              print('|cFF008800BVar|r', elementName..attributeName)
+              --print('|cFF008800BVar|r', elementName..attributeName)
               for i, blockKey in ipairs(block_vars[elementName .. attributeName]) do
-                print('  assigning |cFF008800'..blockKey..'|r')
+                --print('  assigning |cFF008800'..blockKey..'|r')
                 frame[blockKey] = (type(value) == 'table') and value[i] or value
               end
             end
@@ -365,20 +369,25 @@
     end
     code = code .. "\nend"
     local result = assert(loadstring(code))
-    print('storing style func', styleName, result())
+    --print('storing style func', styleName, result())
     style_cache_func[styleName] = result()
 
   end
   style_cache_func[styleName](frame)
 
   --- Hardcoding the sizing vars for sanity
+  local defaultWidth = mod.Conf.Wrapper.Width
   local normalSettings = mod.defaults.Style.Format
-  frame.width = normalSettings.Frame.Width
-  frame.statusWidth = frame.width - normalSettings.status.Indent
-  frame.titleWidth = frame.width - normalSettings.title.Indent
+  frame.width = defaultWidth
+  frame.statusWidth = defaultWidth - normalSettings.status.Indent
+  frame.titleWidth = defaultWidth - normalSettings.title.Indent
 
   if frame.title then
-    frame.titleHeight = frame.title and (frame.title:GetStringHeight() + (frame.title.spacing or 0)*2) or 0
+    frame.titleHeight = frame.title and frame.title:GetStringHeight() or 0
+    if frame.titleHeight > 0 then
+      frame.titleHeight = frame.titleHeight + (frame.title.spacing or 0)*2
+    end
+
     frame.title.spacing = frame.title.spacing or frame.title:GetSpacing()
     frame.title:SetPoint('LEFT', frame, 'LEFT', normalSettings.title.Indent)
     frame.title:SetPoint('TOP', frame, 'TOP', 0, -frame.title.spacing)
@@ -387,36 +396,35 @@
       frame.titlebg:SetHeight(frame.titleHeight)
       frame.titlebg:SetWidth(frame.width)
     end
-    print('  title, textHeight', frame.titleHeight, 'indent', normalSettings.title.Indent, 'spacing', frame.title.spacing)
+    print('  titleHeight', frame.titleHeight, 'indent', normalSettings.title.Indent, 'spacing', frame.title.spacing)
   else
     frame.titleHeight = 0
   end
 
   if frame.status then
-    frame.statusHeight   = frame.status and (frame.status:GetStringHeight() + (frame.status.spacing or 0)*2)  or 0
+    frame.statusHeight   = frame.status and frame.status:GetStringHeight()  or 0
+    if frame.statusHeight > 0 then
+      frame.statusHeight = frame.statusHeight  + (frame.status.spacing or 0)*2
+    end
+
     frame.status.spacing = frame.status.spacing or frame.status:GetSpacing()
     frame.status:SetWidth(frame.width)
     frame.status:SetPoint('LEFT', frame, 'LEFT', normalSettings.status.Indent, 0)
-    frame.status:SetPoint('TOPLEFT', frame.titlebg, 'BOTTOMLEFT', normalSettings.status.Indent, -frame.status.spacing)
-    --frame.status:SetHeight(frame.statusHeight)
+    frame.status:SetPoint('TOP', frame.titlebg, 'BOTTOM', 0, 0)
+    frame.status:SetHeight(frame.statusHeight)
     if frame.statusbg then
 
-      frame.statusbg:SetHeight(frame.statusHeight)
+      frame.statusbg:SetHeight(frame.statusHeight + (frame.attachmentHeight or 0))
       frame.statusbg:SetWidth(frame.width)
     end
-    print('  status, textHeight', frame.statusHeight, 'indent', normalSettings.status.Indent, 'spacing', frame.status.spacing)
+    print('  status tHeight', frame.statusHeight, 'indent', normalSettings.status.Indent, 'spacing', frame.status.spacing)
   else
     frame.statusHeight = 0
   end
 
   frame.height = frame.titleHeight + frame.statusHeight + (frame.attachmentHeight or 0)
   frame:SetSize(frame.width, frame.height)
-  print('    sizing frame', frame.width, frame.height)
-end
-mod.UpdateWrapperStyle = function()
-  local  c = mod.Conf.Wrapper
-  --Wrapper:ClearAllPoints()
-  --Wrapper:SetPoint(c.WrapperPoint, UIParent, c.WrapperPoint, c.WrapperFloatX, c.WrapperFloatY)
+  print('  |cFF0088FFsizing frame', frame.width, frame.height)
 end
 
 --- Argument containers
--- a/ObjectiveTracker.xml	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveTracker.xml	Wed Apr 06 07:38:35 2016 -0400
@@ -80,6 +80,9 @@
     <Frames>
 
       <ScrollFrame name="$parentScrollFrame" enableMouseWheel="true" parentKey="scrollArea" parentArray="minimizeFrames">
+        <Anchors>
+          <Anchor point="TOPLEFT" />
+        </Anchors>
         <Layers>
           <Layer level="BACKGROUND">
             <Texture setAllPoints="true" parentKey="bg">
@@ -90,21 +93,22 @@
         <Frames>
 
 
-          <!-- Can't get it to work as 'Slider'; implement as click frame
-          <Slider name="$parentBar" parentKey="scrollBar" minValue="1" maxValue="100" valueStep="1" stepsPerPage="1" defaultValue="1" orientation="VERTICAL">
-            <HitRectInsets top="-1" bottom="1" right="1" left="0" />
-            <ThumbTexture name="$parentThumb">
-              <Color r="1" g="1" b="1" a="0.85" />
-            </ThumbTexture>
+          <Frame name="VeneerObjectiveScroll">
+            <Anchors>
+              <Anchor point="TOPLEFT" />
+            </Anchors>
             <Layers>
               <Layer level="BACKGROUND">
-                <Texture setAllPoints="true">
-                  <Color r="1" g="0" b="0" a=".5" />
+                <Texture setAllPoints="true" parentKey="bg">
+                  <Color r="1" g="1" b="1" a="1" />
+                  <Gradient orientation="HORIZONTAL">
+                    <MinColor r="0" g="0.5" b="0.5" a="0" />
+                    <MaxColor r="0" g="0.5" b="0.5" a="0" />
+                  </Gradient>
                 </Texture>
               </Layer>
             </Layers>
-          </Slider>
-          -->
+          </Frame>
         </Frames>
       </ScrollFrame>
 
@@ -178,22 +182,6 @@
   <!-- Header Panel -->
 
   <!-- Background panels -->
-  <Frame name="VeneerObjectiveScroll" parent="VeneerObjectiveWrapperScrollFrame">
-    <Anchors>
-      <Anchor point="TOPLEFT" />
-    </Anchors>
-    <Layers>
-      <Layer level="BACKGROUND">
-        <Texture setAllPoints="true" parentKey="bg">
-          <Color r="1" g="1" b="1" a="1" />
-          <Gradient orientation="HORIZONTAL">
-            <MinColor r="0" g="0.5" b="0.5" a="0" />
-            <MaxColor r="0" g="0.5" b="0.5" a="0" />
-          </Gradient>
-        </Texture>
-      </Layer>
-    </Layers>
-  </Frame>
 
   <Frame name="VeneerTrackerTemplate" parent="UIParent" virtual="true">
     <Layers>
@@ -356,4 +344,5 @@
   <Script file="ObjectiveFrame.lua" />
   <Script file="ObjectiveEvents.lua" />
   <Script file="ObjectiveWidgets.lua" />
+  <Script file="XPTracker.lua" />
 </Ui>
\ No newline at end of file
--- a/ObjectiveUI.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveUI.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -6,7 +6,7 @@
 local B = select(2,...).frame
 local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
 local print = B.print('Objectives')
-local Tracker, AutoQuest, Quest, Cheevs = mod.Tracker, mod.AutoQuest, mod.Quest, mod.Cheevs
+local DefaultTracker, AutoQuest, Quest, Cheevs = mod.DefaultTracker, mod.AutoQuest, mod.Quest, mod.Cheevs
 local itemButtonSize, itemButtonSpacing =  36, 1
 local tremove, tremovebyval = table.remove, table.removebyval
 
@@ -16,14 +16,14 @@
 --- -
 --------------------------------------------------------------------
 
-Tracker.Select = function(self) end
-Tracker.Open = function(self) end
-Tracker.Remove = function(self) end
-Tracker.Report = function(self)
+DefaultTracker.Select = function(self) end
+DefaultTracker.Open = function(self) end
+DefaultTracker.Remove = function(self) end
+DefaultTracker.Report = function(self)
   print('Stats:', self.numWatched,'items tracked,', self.numBlocks,'blocks assigned.')
 end
 
-Tracker.OnMouseUp = function(self, button)
+DefaultTracker.OnMouseUp = function(self, button)
   print(self.handler.name, self.mainStyle, self.subStyle)
   if button == 'LeftButton' then
     if IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() then
@@ -43,12 +43,13 @@
   print('|cFFFF8800'..tostring(self:GetName())..':MouseUp()|r')
 end
 
-Tracker.OnMouseDown = function(self, button)
+DefaultTracker.OnMouseDown = function(self, button)
   self:SetStyle('TrackerBlock', self.handler.name, 'MouseDown')
   print(IsModifiedClick("CHATLINK"), IsModifiedClick("QUESTWATCHTOGGLE"))
   print(self.info.title)
 end
 
+
 AutoQuest.Select = function(self)
   if self.info.popupType == 'OFFER'  then
     ShowQuestOffer(self.info.questIndex)
@@ -58,13 +59,12 @@
   RemoveAutoQuestPopUp(self.info.questID)
 end
 
-Quest.Select = function(self) -- remote quests will get listed here as well, so their turn-in data needs to be checked
-  if AutoQuest.Info[self.info.questID] then
-    AutoQuest.Select(self)
+Quest.Select = function(self)
+  if self.info.isAutoComplete and self.info.isComplete then
+    ShowQuestComplete(self.info.questLogIndex)
   else
     SetSuperTrackedQuestID(self.info.questID)
   end
-  mod.UpdateWrapper()
 end
 
 Quest.Link = function(self)
@@ -92,7 +92,7 @@
   RemoveTrackedAchievement(self.info.cheevID)
 end
 Cheevs.OnMouseUp = function(self, button)
-  Tracker.OnMouseUp(self, button)
+  DefaultTracker.OnMouseUp(self, button)
 end
 Cheevs.Link = function(self)
   local achievementLink = GetAchievementLink(self.info.cheevID);
--- a/ObjectiveWidgets.lua	Tue Apr 05 02:38:01 2016 -0400
+++ b/ObjectiveWidgets.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -47,8 +47,8 @@
 
 local Scroller_OnShow = function()
   Wrapper.watchMoneyReasons = 0;
-  mod.UpdateWrapper()
-  mod.SetEvents()
+  --mod:Update()
+  --mod:OnInitialize()
   for i, region in ipairs(Wrapper.headerComplex) do
     region:Show()
   end
@@ -103,7 +103,7 @@
   ToggleWorldMap()
 end
 
-mod.InitializeWrapperWidgets = function()
+mod.InitializeWidgets = function()
   --- tracker scroll
   Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel)
   Scroller:SetScript('OnShow', Scroller_OnShow)
@@ -311,7 +311,7 @@
   __call = function(t, frame)
     -- todo: config pull
 
-    frame:SetWidth(mod.Conf.Wrapper.WrapperWidth - mod.Conf.Style.Format.status.Indent * 2)
+    frame:SetWidth(mod.Conf.Wrapper.Width - mod.Conf.Style.Format.status.Indent * 2)
     frame:SetScript('OnEvent', mod.UpdateWidget[frame.widgetType])
     if frame.info.isCurrency then
       frame:RegisterEvent('CHAT_MSG_CURRENCY')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XPTracker.lua	Wed Apr 06 07:38:35 2016 -0400
@@ -0,0 +1,92 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 4/6/2016 4:44 AM
+
+local B = select(2,...).frame
+local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
+local tostring = tostring
+local UnitLevel, IsResting, UnitXP, UnitXPMax, GetXPExhaustion, IsXPUserDisabled = UnitLevel, IsResting, UnitXP, UnitXPMax, GetXPExhaustion, IsXPUserDisabled
+local Wrapper = _G.VeneerObjectiveWrapper
+local print = B.print('XPTracker')
+
+mod.InitializeXPTracker = function()
+  local XPBar = Wrapper.XPBar
+  if UnitLevel('player') == 100 then
+    XPBar:Hide()
+    return
+  end
+
+  --- xp bar
+  XPBar:SetWidth(mod.Conf.Wrapper.WrapperWidth - Wrapper.CloseButton:GetWidth())
+  XPBar.statusbg:SetAllPoints(XPBar)
+  XPBar:RegisterEvent('DISABLE_XP_GAIN')
+  XPBar:RegisterEvent('ENABLE_XP_GAIN')
+  XPBar:SetScript('OnEvent', mod.UpdateXP)
+
+  if not IsXPUserDisabled() then
+    mod.EnableXP(XPBar)
+  else
+    mod.DisableXP(XPBar)
+  end
+
+  mod.UpdateXP(XPBar)
+end
+
+mod.EnableXP = function(self)
+  self:RegisterEvent('PLAYER_XP_UPDATE')
+  self:RegisterEvent('PLAYER_LEVEL_UP')
+  self:RegisterEvent('PLAYER_UPDATE_RESTING')
+  self.statusbg:SetTexture(0,0,0,.25)
+  self:Show()
+end
+
+mod.DisableXP = function(self)
+  self:UnregisterEvent('PLAYER_XP_UPDATE')
+  self:UnregisterEvent('PLAYER_LEVEL_UP')
+  self:UnregisterEvent('PLAYER_UPDATE_RESTING')
+  self.statusbg:SetTexture(0.5,0.5,0.5,0.5)
+  self:Hide()
+end
+
+mod.UpdateXP = function(self, event)
+  if event == 'DISABLE_XP_GAIN' then
+    mod.DisableXP(self)
+  elseif event == 'ENABLE_XP_GAIN' then
+    mod.EnableXP(self)
+  end
+
+  if not IsXPUserDisabled() then
+
+    local xp = UnitXP('player')
+    local xpmax = UnitXPMax('player')
+    local rest = GetXPExhaustion()
+    self.foreground:SetWidth((xp/xpmax) * self:GetWidth())
+    if rest then
+      self.rested:ClearAllPoints()
+      if xp == 0 then
+        self.rested:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, 0)
+      else
+        self.rested:SetPoint('TOPLEFT', self.fg, 'TOPRIGHT', 0, 0)
+      end
+
+      if (xp + rest) > xpmax then
+        self.rested:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', 0, 0)
+      else
+        self.rested:SetWidth((rest/xpmax) * self:GetWidth())
+      end
+      self.rested:SetPoint('BOTTOM', self, 'BOTTOM')
+      self.rested:Show()
+    else
+      self.rested:Hide()
+    end
+
+    if IsResting() then
+      self.statusbg:SetTexture(.2,.8,.2,.5)
+    else
+      self.statusbg:SetTexture(0,0,0,.25)
+    end
+    self.xpText:SetText(xp .. '/'.. xpmax .. (rest and (' ('..tostring(rest)..')') or ''))
+  end
+end
\ No newline at end of file