changeset 0:3dbcad2b387d

initial push
author Nenue
date Wed, 30 Mar 2016 02:24:56 -0400
parents
children b0447b382f36
files BuffAnchors.lua BuffButton.lua BuffFrame.xml Config.lua Constants.lua Core.xml Init.lua ObjectiveInfo.lua ObjectiveTracker.lua ObjectiveTracker.xml ObjectiveUI.lua RaidBuffTray.lua Veneer.toc
diffstat 13 files changed, 3386 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BuffAnchors.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,302 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/22/2016 3:10 AM
+
+local MODULE = 'BuffFrame'
+local _, A = ...
+local B, _G = A.frame, _G
+local M = B:RegisterModule(MODULE)
+local type, unpack, select, pairs, ipairs, wipe = type, unpack, select, pairs, ipairs, table.wipe
+local min, ceil, mod, tonumber, tostring = min, ceil, mod, tonumber, tostring
+local CreateFrame = CreateFrame
+local print = B.print('Anchor')
+local fprint = B.fprint
+local bprint = B.print('AnchorFrame')
+
+local GetAnchorFrame = function(name)
+  local c = B.displays[name].conf
+  local anchorFrom, anchorParent, anchorTo, offsetX, offsetY = unpack(c.Anchor)
+  local print = bprint
+  if B.anchor[name] then
+    print('get', B.anchor[name]:GetName())
+    return B.anchor[name], anchorFrom, anchorParent, anchorTo, offsetX, offsetY
+  end
+  print('new frame', name)
+  local frame = CreateFrame('Frame', name..'Anchor', UIParent, B.displays[name].anchorTemplate)
+  frame.conf = c
+
+  local x, dx, y, dy
+  local Anchor_OnMouseDown =  function()
+    if c['Parent'] then
+      return
+    end
+
+    x = frame:GetLeft()
+    y = frame:GetTop()
+    frame:StartMoving()
+    frame.isMoving = true
+  end
+
+  local Anchor_OnMouseUp = function()
+    if c['Parent'] then
+      return
+    end
+
+    frame:StopMovingOrSizing()
+    dx = frame:GetLeft() - x
+    dy = frame:GetTop() - y
+    -- update config
+    print('|cFFFFFF00**changing', name, 'anchor by', dx, dy)
+    offsetX = offsetX + dx
+    offsetY = offsetY + dy
+    B.Conf[name .. 'Anchor'] = {anchorFrom, anchorParent, anchorTo, offsetX, offsetY }
+    frame:SetPoint(anchorFrom, _G[anchorParent], anchorTo, offsetX, offsetY)
+    frame.isMoving = nil
+  end
+
+  local AnchorButton_OnClick = function(self, anchor)
+    local point, parent, relative = anchor:GetPoint(1)
+    print('resetting anchors', point, parent:GetName(), relative)
+    B.Conf[name..'Point'] = {point, relative}
+    B.Conf[name..'RelativeX'] = (point:match('RIGHT')) and -1 or 1
+    B.Conf[name..'RelativeY'] = (point:match('TOP')) and -1 or 1
+    wipe(B.drawn[name])
+    B.UpdateBuffs(name)
+  end
+
+  frame.OnUpdate = function(self, elapsed)
+    print(self:GetName(), elapsed)
+    if self:IsMouseOver() then
+      for i, anchorButton in ipairs(frame.anchorButton) do
+        anchorButton:Show()
+      end
+    else
+      for i, anchorButton in ipairs(frame.anchorButton) do
+        anchorButton:Hide()
+      end
+    end
+  end
+
+  frame:SetScript('OnMouseDown', Anchor_OnMouseDown)
+  frame:SetScript("OnMouseUp", Anchor_OnMouseUp)
+  -- table addition
+  for i, anchorButton in ipairs(frame.anchorButton) do
+    anchorButton:SetScript('OnClick', AnchorButton_OnClick)
+  end
+
+  B.displays[name].anchor = frame
+  print(B.displays[name].anchor:GetName())
+  print(B.anchor[name]:GetName())
+  return frame, anchorFrom, anchorParent, anchorTo, offsetX, offsetY
+end
+
+--- Handles the preliminary positioning calculation for buff guide anchors
+M.UpdateAnchorFrames = function(name)
+  local print = fprint(name)
+  local c = B.displays[name].conf
+  local frame, anchorFrom, anchorParent, anchorTo, offsetX, offsetY = GetAnchorFrame(name)
+  print('got', frame:GetName())
+  frame.buffs = B.guides[name]
+  frame.heading:SetText(name)
+  B.SetConfigLayers(frame)
+
+  local buffMax = c['Max'] or 3
+  local perRow = c['PerRow'] or 2
+  local buffSpacing = c['Spacing']
+  local buffSize = c['Size']
+  local buffDurationSize = c['DurationSize']
+
+  if not frame.isMoving then
+    if not B.Conf[name .. 'Parent'] then
+      frame:SetPoint(anchorFrom, _G[anchorParent], anchorTo, offsetX, offsetY)
+    end
+  end
+
+  if frame.contains then buffMax = buffMax + 1 end
+  local cols, rows = min(perRow, buffMax), ceil(buffMax/perRow)
+  local spaces, breaks = (cols - 1), (rows - 1)
+  frame.columns = cols
+  frame.rows = rows
+  frame.spaces = cols - 1
+  frame.breaks = rows - 1
+
+  local width = cols*buffSize + spaces*buffSpacing
+  local height = rows * (buffSize + buffDurationSize) + (breaks * (buffSpacing))
+
+  frame:SetSize(width, height)
+  frame:Show()
+  print(frame:GetName(), frame:GetSize())
+  print(frame:GetPoint(1))
+end
+
+--- Handles placement of anchors embedded within anchors (consolidated buffs, maybe temp enchant)
+M.UpdateAnchorAnchors = function()
+  local print = fprint()
+  for buttonName, d in pairs(B.displays) do
+    local c = B.displays[buttonName].conf
+    local frame =  B.anchor[buttonName]
+    local parent, child = c.Parent, c.Position
+
+    frame.parent = nil
+    if B.Conf[buttonName .. 'Parent'] and _G[B.Conf[buttonName .. 'Parent']..'Anchor'] then
+
+      local anchorAnchor = _G[B.Conf[buttonName .. 'Parent']..'Anchor']
+      local anchorTarget = B.guides[parent][child]
+      if anchorTarget then
+        print('link', buttonName, 'to', parent, child)
+        print(parent, child, B.displays[parent].guides[child])
+        local ac = B.displays[parent].conf
+        local anchorFrom, anchorTo = unpack(ac.Point)
+        frame:ClearAllPoints()
+        frame:SetPoint(anchorFrom, anchorTarget, anchorTo)
+        frame.parent = anchorTarget
+        anchorTarget.contains = frame
+        anchorAnchor.contains = frame
+        anchorAnchor.containPosition = child
+      else
+        frame.parent = anchorAnchor
+        anchorAnchor.contains = frame
+        anchorAnchor.containPosition = nil
+      end
+    else
+      frame.parent = nil
+    end
+
+  end
+end
+
+-- if facing key direction, anchor point [1] to parent's point [2]
+local childFacing = {
+  ['TOP'] = {'TOP', 'BOTTOM'},
+  ['BOTTOM'] = {'BOTTOM', 'TOP'},
+  ['RIGHT'] = {'LEFT', 'RIGHT'},
+  ['LEFT'] = {'RIGHT', 'LEFT'},
+}
+-- if align in key position, concatenate value with facing point
+local childAlign = {
+  ['TOP'] = 'TOP%s',
+  ['BOTTOM'] = 'BOTTOM%s',
+  ['MIDDLE'] = '%s',
+  ['LEFT'] = '%sLEFT',
+  ['RIGHT'] = '%sRIGHT',
+  ['CENTER'] = '%s',
+}
+
+--- dep handlers
+B.UpdateAnchorChild = function (frame, child, c)
+  if frame.attached ~= child then
+    B.SetAnchorChild(frame, child, c)
+  end
+
+  print('positioning|cFFFF0088', child, '|r of |cFF00FF00', frame, '|r')
+
+  local frameAnchor = unpack(B.Conf[c.Parent.. 'Anchor'])
+  local childAnchor, childPoint = 'BOTTOMRIGHT', 'TOPRIGHT'
+  local direction, position = unpack(c.Anchor)
+  if direction and position then
+    childAnchor = childAlign[position]:format(childFacing[direction][2])
+    childPoint = childAlign[position]:format(childFacing[direction][1])
+    print('align toward', position,'on', direction, 'edge')
+  end
+
+  print(frameAnchor, direction, position)
+  local lX, lY, cX, cY = frame.outer_X, frame.outer_Y, frame.cutout_X, frame.cutout_Y
+  local mX, mY = 0, 0 -- alignment modifiers
+  local pX, pY = 0, 0 -- position value
+  print('|cFFFF0088PUSHOUTS|r:', lX, lY, '|cFFFF8800PULL-IN|r:', cX, cY)
+
+  -- if attachment is on a moving edge
+  if not frameAnchor:match(direction) then
+    print('  child anchors to a growing edge |cFFFF8800', direction,'|r')
+    if direction == 'BOTTOM' then
+      -- horizontal edge
+
+    else
+      -- vertical edge
+      pX = lX
+    end
+
+    if frameAnchor:match(position) then
+
+      print('close alignment', lX, cX)
+      if position == 'RIGHT' then
+        -- and far X val
+        pX = 0
+        lX = -lX
+        cX = -cX
+        pY = lY
+      else
+      end
+    else
+      print('far alignment', position)
+    end
+  else
+    print('  child anchors to a static edge |cFF0088FF', direction,'|r')
+    -- use no Y offset, position doesn't interfere
+    if direction == 'BOTTOM' or direction == 'TOP' then
+      pY = 0
+    else
+      pX = 0
+    end
+  end
+
+  local frameWidth = frame:GetWidth()
+  local frameHeight = frame:GetHeight()
+
+  local overlapY, overlapX
+
+  -- right and bottom anchors offsets need to be inverted
+  if direction == 'BOTTOM' then
+    print('inverting Y values for anchor on BOTTOM edge, options:', cY, lY, 'actual:', pY)
+    pY = frameHeight - pY
+    cY = frameHeight - cY
+    lY = frameHeight - lY
+    print('  new values:', cY, lY, pY)
+  elseif direction == 'RIGHT' then
+    pX = frameWidth -pX
+    cX = frameWidth-cX
+    lX = frameWidth-lX
+  end
+
+
+  print(child, '|cFFFFFF00', childAnchor, '|r', frame, '|cFFFF0088', childPoint, '|r', pX, pY)
+  child:ClearAllPoints()
+  child:SetPoint(childAnchor, frame, childPoint, pX, pY)
+  frame.attachPoint = {childAnchor, childPoint }
+
+  if Devian and Devian.InWorkspace() then
+    frame.alignedJoint:ClearAllPoints()
+    frame.poppingJointX:ClearAllPoints()
+    frame.poppingJointY:ClearAllPoints()
+    frame.cuttingJointX:ClearAllPoints()
+    frame.cuttingJointY:ClearAllPoints()
+    frame.childSpace:ClearAllPoints()
+
+    frame.alignedJoint:SetPoint(childAnchor, frame, childPoint, pX, pY)
+    frame.poppingJointY:SetPoint(childAnchor, frame, childPoint, lX, lY) -- should really only differ when rows exceed 1
+    frame.poppingJointX:SetPoint(childAnchor, frame, childPoint, lX, lY)
+    frame.cuttingJointY:SetPoint(childAnchor, frame, childPoint, cX, cY) -- should really only differ when rows exceed 1
+    frame.cuttingJointX:SetPoint(childAnchor, frame, childPoint, cX, cY)
+    frame.childSpace:SetAllPoints(child)
+
+    frame.alignedJoint:Show()
+    frame.poppingJointX:Show()
+    frame.poppingJointY:Show()
+    frame.cuttingJointX:Show()
+    frame.cuttingJointY:Show()
+    frame.childSpace:Show()
+
+    print('|cFFFF0000MIN  |r', childAnchor, childPoint, pX, pY)
+    print('|cFF00FFFFFAR  |r', childAnchor, childPoint, cX, cY)
+    print('|cFFFFFF00CLOSE|r', childAnchor, childPoint, lX, lY)
+
+  end
+end
+
+B.SetAnchorChild = function(frame, child, c)
+  print('linking', child)
+  frame.attached = child
+  frame.attachmentConf = c
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BuffButton.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,440 @@
+--- Actual BlizzUI modifications are applied here
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/12/2016 12:47 AM
+local MODULE = 'BuffFrame'
+local _, A = ...
+local B, _G = A.frame, _G
+local type, unpack, select, pairs, ipairs = _G.type, _G.unpack, _G.select, _G.pairs, _G.ipairs
+local min, ceil, mod, tonumber, tostring = _G.min, _G.ceil, _G.mod, _G.tonumber, _G.tostring
+local floor, wipe, max = _G.math.floor, _G.table.wipe, _G.math.max
+local CreateFrame, IsInGroup, GetCVarBool = _G.CreateFrame, _G.IsInGroup, _G.GetCVarBool
+local BuffFrame, ConsolidatedBuffs = _G.BuffFrame, _G.ConsolidatedBuffs
+local print, gprint, aprint, fprint = B.print('Buff'), B.print('SetGuides'), B.print('SetAnchors'), B.fprint
+local displays, anchors, guides, decors, positioned, drawn, zoom = B.displays, {}, {}, {}, {}, {}, {}
+local UnitAura, UnitName, RegisterStateDriver = _G.UnitAura, _G.UnitName, _G.RegisterStateDriver
+
+local M = B:RegisterModule(MODULE)
+
+M.GetBuffZoom = function(buffName)
+  local zoom = tonumber(B.displays[buffName].conf['Zoom']) / 100 / 2
+  local zoomL, zoomU, zoomR, zoomD = zoom, zoom, 1-zoom, 1-zoom
+  print(buffName, zoom)
+  return function(self, ...)
+    if select('#',...) == 4 then
+      zoomL, zoomR, zoomU, zoomD = ...
+    end
+    self:SetTexCoord(zoomL, zoomR, zoomU, zoomD)
+    return zoomL, zoomR, zoomU, zoomD
+  end
+end
+
+
+
+M.UpdateButtonAlpha = function(self)
+  if not self.parent.timeLeft or not self:IsVisible() then
+    self:SetScript('OnUpdate', nil)
+    return
+  end
+
+  if self.parent.timeLeft < _G.BUFF_WARNING_TIME then
+    self:SetAlpha(BuffFrame.BuffAlphaValue)
+  else
+    self:SetAlpha(1)
+  end
+end
+
+--- Called infrequently to align stencil frames
+local refreshCount = 0
+M.UpdateGuideFrames = function(buffName)
+  refreshCount = refreshCount + 1
+  local print = fprint()
+
+
+  local anchor = anchors[buffName]
+  local c, g, d = displays[buffName].conf, guides[buffName], decors[buffName]
+  local perRow = c['PerRow']
+  local buffSpacing, buffSize, buffBorder, buffDurationSize, buffCountSize, relativeX, relativeY = c['Spacing'], c['Size'], c['Border'], c['DurationSize'], c['CountSize'], c['RelativeX'], c['RelativeY']
+  local consolidated = (anchors[buffName].contains and IsInGroup())
+  local consolidatedPosition = (consolidated and anchors[buffName].containPosition or 0)
+
+
+  print('|cFF00FF00Setting Guides ('..refreshCount..'):|r', buffName, 'user max:',c['Max'], 'hard max:', displays[buffName].maxIcons)
+
+  local buffMax = min(c['Max'], displays[buffName].maxIcons)
+  local anchorFrom, anchorTo = c.Point[1], c.Point[2]
+  anchor.Zoom = M.GetBuffZoom(buffName)
+
+
+
+  if consolidated then
+    buffMax = buffMax + 1
+  end
+
+  local legend = {}
+  legend.r, legend.g, legend.b, legend.a = unpack(displays[buffName].legendColor)
+  local horizFrom = (relativeX < 0) and 'RIGHT' or 'LEFT'
+  local horizTo = (relativeX < 0) and 'LEFT' or 'RIGHT'
+  local vertFrom = (relativeY < 0) and 'TOP' or 'BOTTOM'
+  local vertTo = (relativeY < 0) and 'BOTTOM' or 'TOP'
+  local previous, up
+  local bottom_extent = 0
+  for i = 1, buffMax do
+    print('update idx', i)
+    if not g[i] then
+      g[i] = CreateFrame('Frame', buffName..'Guide'..i, anchor, displays[buffName].template or 'VeneerGuideTemplate')
+      RegisterStateDriver(g[i], "visibility", "[petbattle] [vehicleui] hide; show")
+    end
+
+    local guide = g[i]
+
+    local row = ceil(i / perRow)
+    local  col = mod(i, perRow)
+    if col == 0 then
+      col = perRow
+    end
+
+    guide.previous = previous
+    guide.up = up
+    local x, y, parent = 0, 0, anchor
+    if i == 1 then
+      parent = anchor
+      up = guide
+    elseif col == 1 then
+      parent = g[i-perRow]
+      y = (buffSpacing + bottom_extent)  * relativeY
+      up = guide
+      anchorFrom = vertFrom .. horizFrom
+      anchorTo = vertFrom .. horizFrom
+      bottom_extent = 0
+    else
+      parent = g[i-1]
+      x = buffSpacing * relativeX
+      anchorFrom = vertFrom .. horizFrom
+      anchorTo = vertFrom .. horizTo
+    end
+    previous = guide
+    guide.parent = parent
+
+    ---------------------------------
+    -- Positioning layer
+    if i ~= consolidatedPosition or not consolidated then
+      guide:SetSize(buffSize, buffSize + buffDurationSize)
+      -- RaidBuffTray will fix the sizing
+    end
+    bottom_extent = max(bottom_extent, guide:GetHeight())
+
+    guide.info = {} -- UnitAura cache
+
+    if i == consolidatedPosition then
+      guide.legend:SetTexture(1,1,0,0.5)
+    else
+      guide.legend:SetTexture(legend.r, legend.g, legend.b, legend.a)
+    end
+
+    guide.idText:SetText(i) -- needs to reflect the current position
+
+    guide:ClearAllPoints()
+    guide:SetPoint(anchorFrom, parent, anchorTo, x, y)
+    print(anchorFrom, parent, anchorTo, x, y)
+
+    guide.icon:SetSize(buffSize - buffBorder * 2, buffSize - buffBorder * 2)
+    guide.icon:ClearAllPoints()
+    guide.icon:SetPoint('TOPLEFT', guide, 'TOPLEFT', buffBorder, -buffBorder )
+
+    local anchorTo, anchorFrom, x, y = unpack(c.DurationPoint)
+    guide.duration:ClearAllPoints()
+    guide.duration:SetPoint(anchorTo, guide, anchorFrom, x, y)
+    --guide.duration:SetSize(buffSize, buffDurationSize)
+    print('  duration ->', anchorFrom, anchorTo, x, y)
+
+    local anchorTo, anchorFrom, x, y = unpack(c.CountPoint)
+    guide.count:ClearAllPoints()
+    guide.count:SetPoint(anchorTo, guide.icon, anchorFrom, x, y)
+    --guide.count:SetSize(buffSize, c.CountSize)
+    print('  count    ->', anchorFrom, anchorTo, x, y)
+
+    -----------------------------------
+    -- Background decorations layer
+    if not d[i] then
+      d[i] = CreateFrame('Frame', buffName..i..'Decor', _G.UIParent, 'VeneerDecorTemplate')
+      RegisterStateDriver(d[i], "visibility", "[petbattle] [vehicleui] hide")
+    end
+
+    d[i]:SetPoint('BOTTOMLEFT', guide.icon, 'BOTTOMLEFT', -buffBorder, -buffBorder)
+    d[i]:SetPoint('TOPRIGHT', guide.icon, 'TOPRIGHT', buffBorder, buffBorder)
+
+
+    guide:Show()
+    B.SetConfigLayers(guide)
+  end
+
+
+  if #guides[buffName] > buffMax then
+    local lim = #guides[buffName]
+    for i = buffMax+1, lim do
+
+      local g = guides[buffName][i]
+      if g:IsVisible() then
+        print('cleaning up #', i, buffName)
+        g:Hide()
+        B.RemoveConfigLayers(g)
+      end
+
+    end
+  end
+
+  anchor.last = previous
+  anchor.up = up
+
+  print(anchor:GetName(), anchor:GetSize())
+end
+
+M.UpdateButtonPositions = function(buffName, auraType)
+  local print = fprint()
+  local c = auraType.conf
+  local numBuffs = 0
+  local actualIcons = auraType.actualIcons()
+  local maxIcons = auraType.maxIcons
+  local anchor = anchors[buffName]
+  local buffMax = c['Max']
+  local consolidated = (anchor.contains and IsInGroup())
+  local consolidatedPosition = (consolidated and anchor.containPosition or 0)
+
+  for k,v in pairs(decors[buffName]) do
+    print(v)
+  end
+
+  if consolidated then
+    decors[buffName][1]:Hide()
+    numBuffs = numBuffs + 1
+    buffMax = buffMax + 1
+  end
+
+  print(' ', 'frame count:', auraType.actualIcons(), 'hardmax:', maxIcons)
+  if auraType.actualIcons() > 0 then
+    for i = 1, actualIcons do
+
+
+      local buff = _G[buffName .. i]
+      local buffIcon = _G[buffName .. i .. 'Icon']
+      local buffBorder = c['Border']
+      local buffDuration = _G[buffName .. i .. 'Duration']
+      local buffCount = _G[buffName .. i .. 'Count']
+      local buffDurationSize = c['DurationSize']
+      local debuffBorder = _G[buffName .. i .. 'Border']
+
+
+      if buff and not buff.consolidated then
+        numBuffs = numBuffs + 1
+        local guide = guides[buffName][numBuffs]
+        local deco = decors[buffName][numBuffs]
+        if numBuffs > buffMax then
+          -- if a limit is reached, start hiding
+          if guide then
+            guide.info = nil
+          end
+          if deco then
+            deco:Hide()
+          end
+          buff:Hide()
+        else
+          local buffData = guide.info
+          buffData.name,  buffData.rank,  buffData.icon,  buffData.count,  buffData.dispelType,  buffData.duration,  buffData.expires,  buffData.caster,  buffData.isStealable,  buffData.shouldConsolidate,  buffData.spellID,  buffData.canApplyAura,  buffData.isBossDebuff,  buffData.value1,  buffData.value2,  buffData.value3
+          = UnitAura(buff.unit, buff:GetID(), nil, buff.filters)
+
+          if guide.caster and buffData.caster then
+            if (buffData.caster ~= 'player' or c.ShowSelfCast) then
+              guide.caster:SetText(UnitName(buffData.caster))
+            else
+              guide.caster:SetText(nil)
+            end
+          end
+
+
+          print(numBuffs, i, buff:GetName(), buff:GetID(), decors[buffName][numBuffs]:GetName())
+
+          buff:SetAllPoints(guide)
+          buffIcon:ClearAllPoints()
+          buffIcon:SetPoint('TOPLEFT', guide.icon, 'TOPLEFT', 0, 0)
+          buffIcon:SetPoint('BOTTOMRIGHT', guide.icon, 'BOTTOMRIGHT', 0, 0)
+
+          deco.parent = buff
+          -- make sure so they aren't re-shown in pet battle
+          if not C_PetBattles.IsInBattle() then
+            deco:Show()
+            deco:SetAlpha(1)
+          end
+
+          if debuffBorder then
+            deco.background:SetTexture(debuffBorder:GetVertexColor())
+            debuffBorder:Hide()
+          else
+            if guide.info.caster == 'player' then
+              print(guide.info.caster)
+              deco.background:SetTexture(unpack(c.PlayerColor))
+            elseif buffData.isBossDebuff then
+              print(guide.info.isBossDebuff)
+              deco.background:SetTexture(unpack(c.BossColor))
+            else
+              print(guide.info.caster)
+              deco.background:SetTexture(unpack(c.Color))
+            end
+          end
+
+
+          buffDuration:ClearAllPoints()
+          local from, to = unpack(c.DurationPoint)
+          buffDuration:SetPoint(from, guide.duration, to)
+          buffDuration:SetText('WHAT')
+
+          if buff.timeLeft and c.WarningFade then
+            deco:SetScript('OnUpdate', M.UpdateButtonAlpha)
+          else
+            deco:SetScript('OnUpdate', nil)
+            deco:SetAlpha(1.0)
+          end
+
+          buffCount:ClearAllPoints()
+          local from, to = unpack(c.CountPoint)
+          buffCount:SetPoint(from, guide.count, to)
+
+          if not drawn[buffName][numBuffs] then
+            anchors[buffName].Zoom(buffIcon)
+
+            if buffDuration then
+              local font = buffDuration:GetFont()
+              buffDuration:SetFont(font, c.DurationSize, 'OUTLINE')
+
+            end
+
+            if buffCount then
+              local font = buffCount:GetFont()
+              buffCount:SetFont(font, c.CountSize, 'OUTLINE')
+            end
+            drawn[buffName][numBuffs] = true
+          end
+        end
+      end
+
+    end
+  end
+  -- clear any outliers
+  for i = numBuffs+1, buffMax do
+    if guides[buffName][i].caster then
+    guides[buffName][i].caster:SetText(nil)
+    end
+    --if not decors[buffName][i].parent or
+
+    decors[buffName][i].parent = nil
+    decors[buffName][i]:SetAlpha(1.0)
+    decors[buffName][i]:SetScript('OnUpdate', nil)
+    decors[buffName][i]:Hide()
+  end
+
+  -- parametric occlusion data for compacted anchor points
+  if numBuffs == 0 then
+    anchor.cutout_X = 0
+    anchor.cutout_Y = 0
+    anchor.outer_X = 0
+    anchor.outer_Y = 0
+  elseif numBuffs <= buffMax then
+    local sX, sY = guides[buffName][numBuffs]:GetWidth(), guides[buffName][numBuffs]:GetHeight()
+    local p = c.PerRow
+    local lX = mod(numBuffs, p)
+    local lY = floor(numBuffs / p)
+    local oX = min(numBuffs, c.PerRow)
+    local oY = ceil(numBuffs / p)
+    anchor.cutout_X = lX * sX + lX * c.Spacing -- max clearance to fit alongside the row
+    anchor.cutout_Y = lY * sY + lY * c.Spacing
+    anchor.outer_Y  = oY * sY + oY * c.Spacing -- distance of farthest row
+    anchor.outer_X  = oX * sX + oX * c.Spacing
+
+
+    print('|cFF0088FF', 'inner corner', lX, lY, 'outer corners', oX, oY)
+    print('cutout delta =', anchor.cutout_X, anchor.cutout_Y, 'out of', floor(anchor:GetWidth()), floor(anchor:GetHeight()))
+    print('extent delta =', anchor.outer_X, anchor.outer_Y)
+  else
+    anchor.cutout_X = 0
+    anchor.cutout_Y = 0
+    anchor.outer_X = 0
+    anchor.outer_Y = 0
+  end
+
+  if anchor.attached then
+    M.UpdateAnchorChild(anchor, anchor.attached, anchor.attachmentConf)
+  end
+
+end
+
+M.PostBuffAnchors  = function()
+  local print = fprint()
+  if M.ShowConsolidatedBuffs then
+    M.UpdateRaidBuffs()
+  end
+  for buttonName, auraType in pairs(displays) do
+    print('sending', buttonName, auraType)
+    -- if waiting for anchors
+    if not anchors[buttonName] then
+      return
+    end
+
+    --if positioned[buttonName] == 0 then
+      print('possibly reloaded UI, check positions')
+      M.UpdateGuideFrames(buttonName)
+    --end
+
+    M.UpdateButtonPositions(buttonName, auraType)
+  end
+end
+
+M.UpdateBuffs = function(buttonName, forced)
+  local print = B.fprint(buttonName)
+  local c = displays[buttonName].conf
+  if drawn[buttonName] then
+    wipe(drawn[buttonName])
+  else
+    drawn[buttonName] = {}
+  end
+
+  M.UpdateAnchorFrames(buttonName)
+  M.UpdateGuideFrames(buttonName)
+  M.UpdateButtonPositions(buttonName, displays[buttonName])
+end
+
+--- should only be called from user input
+print('init def')
+function M:OnInitialize ()
+  drawn = B.Abstract(B.displays, 'drawn')
+  -- Lesser extent of guide frames that have been positioned
+  positioned = B.Abstract(B.displays, 'positioned', positioned)
+  -- Backdrop style frame
+  decors = B.Abstract(B.displays, 'decorator', decors)
+  -- Static positioning frames
+  guides = B.Abstract(B.displays, 'guides', guides)
+  -- Anchor points for guides
+  anchors = B.Abstract(B.displays, 'anchor')
+  -- Stored functions for doing icon texture adjustments
+  zoom = B.Abstract(B.displays, 'zoom', zoom)
+
+  B:RegisterUnitEvent("UNIT_AURA", "player", "vehicle")
+  B:RegisterEvent("GROUP_ROSTER_UPDATE")
+  B:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
+  hooksecurefunc("BuffFrame_UpdateAllBuffAnchors", M.PostBuffAnchors)
+  hooksecurefunc("RaidBuffTray_Update", M.UpdateRaidBuffs)
+end
+print('update def')
+function M:OnUpdate ()
+  M.ShowConsolidated = (IsInGroup() and GetCVarBool("consolidateBuffs"))
+  M.ShowMissingBuffs = (IsInGroup() and B.Conf.RaidShowMissing)
+
+  for name, auraType in pairs(displays) do
+    print(name, auraType)
+    M.UpdateBuffs(auraType.buffName, true)
+  end
+
+  M.UpdateAnchorAnchors()
+  M.UpdateRaidBuffs()
+  M.UpdateBuffsTodo()
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BuffFrame.xml	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,9 @@
+<Ui>
+  <!--
+  Veneer
+  BuffFrame module
+  -->
+  <Script file="BuffAnchors.lua" />
+  <Script file="RaidBuffTray.lua" />
+  <Script file="BuffButton.lua" />
+</Ui>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Config.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,388 @@
+--- All the control GUI stuff, including chat command functions
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/12/2016 12:49 AM
+local B, _G = select(2,...).frame, _G
+local M = B:RegisterModule("Options")
+local tostring, tonumber, floor, format = tostring, tonumber, floor, string.format
+local unpack, select, pairs, ipairs, type, wipe = unpack, select, pairs, ipairs, type, table.wipe
+local CreateFrame, IsControlKeyDown = _G.CreateFrame, _G.IsControlKeyDown
+local max = math.max
+local OpacitySliderFrame, ColorPickerFrame = _G.OpacitySliderFrame, _G.ColorPickerFrame
+local print = B.print('Cfgl')
+local function round(number, decimals)
+  if floor(number) == number then
+    return ('%d'):format(number)
+  end
+
+  return (("%%.%df"):format(decimals)):format(number)
+end
+
+--- STATE VARIABLES
+local configInit
+--- Dummies for addon table upvalues
+local configFrames = {} -- actual frame objects
+local displays = B.displays     -- anchor objects dummy
+
+
+--- Returns a value retreival function and the current value stored in config
+-- @paramsig value, previousValue = configInteger(key)
+-- @param key Name of the config field being represented.
+local defaultGroup = 'BuffButton'
+local configInteger = function(group, key)
+  return function(self ,display)
+    return floor(tonumber(self:GetValue()) + 0.5)
+  end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
+end
+local configPercent = function(group, key)
+  return function(self, display)
+    local value = self:GetValue()
+    if display then
+      return tostring(floor(value*100+0.5))..' %'
+    else
+      return floor((value*100+0.5))/100
+    end
+  end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
+end
+local configColor = function(group, key)
+  -- table for config, color value list for text
+  return function(self, display)
+    if display then
+      return "|cFFFF4444" .. round(self.rgba[1], 1) .. "|r, |cFF44FF44" .. round(self.rgba[2], 1) .. "|r, |cFF4488FF" ..
+          round(self.rgba[3], 1) .. "|r, " .. round(self.rgba[4], 1)
+    else
+      return self.rgba
+    end
+  end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
+end
+local configCheck = function(group, key)
+  return function(self) return self:GetChecked() end, B.Conf[group ..key] or B.Conf[defaultGroup..key]
+end
+-- initializes the corresponding type of config field
+local frameTypeConv = {
+  Color = 'Button',
+  Font = 'Frame',
+}
+local configTypeParams = {
+  Slider = function(frame, optionInfo)
+    frame:SetMinMaxValues(optionInfo[5], optionInfo[6])
+    frame:SetValueStep(optionInfo[7])
+    frame:SetStepsPerPage(optionInfo[8])
+    print(frame.OptName, '\n  {', optionInfo[5], optionInfo[6], optionInfo[7], optionInfo[8], '}')
+  end,
+  CheckButton = function(frame, optionInfo)
+    frame.SetValue = function(self, ...)
+      self:SetChecked(...)
+      B.Conf[self.OptName] = self:GetChecked()
+      print(self.OptTab)
+      B.UpdateAll()
+    end
+    frame:SetScript("OnClick",function(self)
+      B.Conf[self.OptName] = self:GetChecked()
+      print(B.Conf[self.OptName], self:GetChecked())
+      B.UpdateAll()
+    end)
+  end,
+  Color = function(frame, optionInfo)
+    frame.rgba = { frame.current:GetVertexColor() }
+    local colorPickerCallback = function(restore)
+      local newR, newG, newB, newA
+      if restore then
+        newR, newG, newB, newA = unpack(restore)
+      else
+        newA, newR, newG, newB = OpacitySliderFrame:GetValue(), ColorPickerFrame:GetColorRGB()
+        print('not cancel', newA, newR, newB, newG)
+      end
+      frame:SetValue({newR, newG, newB, newA})
+      B.UpdateBuffs(frame.OptTab)
+    end
+    frame:SetScript("OnClick", function(self)
+      print('got a click')
+      local r, g, b, a = frame.current:GetVertexColor()
+      ColorPickerFrame:SetColorRGB(r, g, b)
+      ColorPickerFrame.hasOpacity =  (a ~= nil)
+      ColorPickerFrame.opacity = a
+      ColorPickerFrame.previousValues = {r,g,b,a}
+      ColorPickerFrame.func, ColorPickerFrame.opacityFunc, ColorPickerFrame.cancelFunc =
+      colorPickerCallback, colorPickerCallback,colorPickerCallback
+      ColorPickerFrame:Hide()
+      ColorPickerFrame:Show()
+    end)
+    frame.SetValue = function(self, rgba)
+      print(rgba)
+      frame.rgba = rgba
+      B.Conf[self.OptName] = rgba
+      frame.current:SetVertexColor(unpack(rgba))
+      frame.fieldvalue:SetText(frame.OptValue(frame, true))
+    end
+  end
+}
+--- configDialog
+-- @usage tinsert(configDialog, {prefix, row, [...] })
+-- Each top level member defines a group of config value handlers, structured as an iterative table where the
+-- first member is a key prefix, the second member is an integer row value, and all following members are treated
+-- as a widget resource, defined initially as a complete sub-table, which can be re-used further down by passing
+-- the string literal widget suffix.
+-- widget table: ... {'suffix', 'description', valueCallback, 'template', [widget parameters]}
+-- widget copy: ... 'suffix', ...
+local configDialog = {
+  {'BuffButton', 1,
+
+    {'Max', 'Max', configInteger, 'Slider',
+      1, _G.BUFF_MAX_DISPLAY, 1, 1}, -- valueMin, valueMax, valueStep, stepsPerPage
+    {'PerRow', 'Per Row', configInteger, 'Slider',
+      1, _G.BUFF_MAX_DISPLAY, 1, 1}, -- valueMin, valueMax, valueStep, stepsPerPage,
+    {'Size', 'Icon Size', configInteger, 'Slider',
+      1, 256, 1, 1},
+    {'Spacing', 'Icon Spacing', configInteger, 'Slider',
+      1, 50, 1, 1},
+    {'DurationSize', 'Duration Text Height', configInteger, 'Slider',
+      1, 72, 1, 1},
+    {'Zoom', 'Icon Zoom', configInteger, 'Slider',
+      0, 100, 1, 1},
+    {'Border', 'Border', configInteger, 'Slider',
+      1, 16, 1, 1},
+    {'Color', 'Default Border', configColor, 'Color'},
+    {'RaidColor', 'RaidBuff Border', configColor, 'Color'},
+    {'PlayerColor', 'Player Buffs', configColor, 'Color'},
+    {'BossColor', 'Encounter Buffs', configColor, 'Color'},
+    {'ShowSelfCast', 'Show name for self-casts', configCheck, 'CheckButton'}
+  },
+  { 'DebuffButton', 1,
+    {'Max', 'Max', configInteger, 'Slider',
+      1, _G.DEBUFF_MAX_DISPLAY, 1, 1 }
+    ,
+    {'PerRow', 'Per Row', configInteger, 'Slider',
+      1, _G.DEBUFF_MAX_DISPLAY, 1, 1 },
+    'Size', 'Spacing', 'DurationSize', 'Zoom', 'Border',
+    'Color', 'RaidColor', 'PlayerColor', 'BossColor',
+  },
+  { 'TempEnchant', 1,
+    {'Max', 'Max', configInteger, 'Slider',
+      1, _G.NUM_TEMP_ENCHANT_FRAMES, 1, 1 },
+    {'PerRow', 'Per Row', configInteger, 'Slider',
+      1, _G.NUM_TEMP_ENCHANT_FRAMES, 1, 1},
+    'Size', 'Spacing', 'DurationSize', 'Zoom', 'Border',
+    'Color', 'RaidColor', 'PlayerColor', 'BossColor',
+  },
+  { 'ConsolidatedBuff', 2,
+    {'Position', 'Slot Position', configInteger, 'Slider',
+    1, _G.BUFF_MAX_DISPLAY, 1, 1 }
+
+  },
+  { 'ConsolidatedBuff', 2,
+    'Size'
+  },
+  { 'Raid', 3,
+    {'ShowMissing', 'Verbose missing raid buffs', configCheck, 'CheckButton'}
+  }
+}
+
+
+
+
+local configFrame
+local optionTemplates = {}
+local configPadding, configSpacing = 3, 3
+
+--- Walks the structure table to generate a pretty config panel
+local InitConfig = function()
+  configInit = true
+  local configWidth = B:GetWidth()
+  local optionWidth = (configWidth - configPadding) / 3 - configSpacing
+  local configHeight = 0
+  local bottom_extent = 0
+  local clusterHeight = 0
+  local clusterOffset = 0
+  local lastCluster
+  local cluster = 1
+  local col = 0
+  for t, taboptions in ipairs(configDialog) do
+    local group = taboptions[1]
+    cluster = taboptions[2]
+    col = col + 1
+
+
+    if not configFrames[t] then
+      configFrames[t] = {}
+    end
+
+
+    if cluster ~= lastCluster then
+      configHeight = configHeight + clusterHeight
+      print('|cFFFF8800## new cluster|r, advancing offset from', clusterOffset, 'to', clusterOffset + clusterHeight)
+      clusterOffset = clusterOffset + clusterHeight
+      col = 1
+      clusterHeight = 0
+      lastCluster = cluster
+    end
+
+    print('processing tab', group)
+    local row = 0
+    for i = 3, #taboptions do
+      row = row + 1
+      local optionInfo = taboptions[i]
+      if type(optionInfo) == 'string' then
+        optionInfo = optionTemplates[optionInfo]
+      end
+      local key, fieldname, valueFuncGenerator, configType = unpack(optionInfo)
+
+      if not optionTemplates[key] then
+        optionTemplates[key] = optionInfo
+      end
+
+      local fullkey = group .. key
+      print(fullkey, fieldname)
+
+      if not configFrames[t][row] then
+        print('building frame', t, group, row)
+        local frameTemplate =  'VeneerConfig'..configType
+        local frameType = frameTypeConv[configType] or configType
+        configFrames[t][row] = CreateFrame(frameType, fullkey, B, frameTemplate)
+        local f = configFrames[t][row]
+        f.OptKey = key
+        f.OptTab = group
+        f.OptName = fullkey
+        local valueFunc, initialValue = valueFuncGenerator(group, key)
+        print('  value getter', fullkey,'->', valueFunc,initialValue)
+        configTypeParams[configType](f, optionInfo)
+        f.OptValue = valueFunc
+
+        --- Enclosing these to
+        -- a) make the panel easy to bring up externally
+        -- b) limit gameplay risk from config frame errors
+        -- c) milk the iterator scope for all its worth
+        f.OnChange = function(self)
+
+          -- holding control; mirror this setting in other categories
+          if IsControlKeyDown() and not (configInit) then
+            configInit = true
+            for optTab, opts in pairs(configFrames) do
+              for _, opt in ipairs(opts) do
+                if opt.OptKey == key then
+                  if optTab ~= group then
+                    print('mapping to', optTab, opt.OptKey)
+                    opt:SetValue(self:GetValue())
+                  end
+
+                end
+              end
+            end
+            configInit = nil
+          end
+          local newValue = valueFunc(self)
+          if newValue ~= B.Conf[fullkey] then
+            print(newValue, fullkey)
+            f.fieldvalue:SetText(valueFunc(self, true))
+            B.Conf[fullkey] = valueFunc(self)
+            -- prepare to update
+            wipe(B.drawn[f.OptTab])
+            B.UpdateBuffs(self.OptTab)
+            B.UpdateConfigLayers()
+          end
+
+        end
+
+        f:SetValue(initialValue)
+        local yBuffer = configPadding
+        if f.fieldname then
+          f.fieldname:SetText(fieldname)
+          yBuffer = yBuffer + f.fieldname:GetHeight()
+        end
+        if f.fieldvalue then
+          f.fieldvalue:SetText(f:OptValue(true))
+        end
+
+        local point, relative, x, y = 'TOPLEFT', 'BOTTOMLEFT', 0, -3
+
+        local base
+        if (row == 1) then
+          bottom_extent = 0
+          base = B.header
+          x = (col-1) * (optionWidth+configSpacing)
+          y = -configPadding
+        else
+          base = configFrames[t][row-1]
+        end
+
+        print('|cFFFF0088'..cluster..'|r |cFF00FF00'.. row..'|r', col, base:GetName(), x, y - clusterOffset)
+
+        if frameType ~= 'CheckButton' then
+          f:SetWidth(optionWidth)
+        end
+
+        f:SetPoint(point, base, relative, x, y-yBuffer-clusterOffset)
+        --print('creating', frameType, fieldname)
+        f:Show()
+
+        bottom_extent = bottom_extent + f:GetHeight() + yBuffer + configSpacing
+
+
+
+        clusterHeight = max(clusterHeight, bottom_extent)
+        --print('y', floor(yBuffer+0.5), 'f:H', floor(f:GetHeight()+0.5), 'hTally', floor(bottom_extent+0.5), 'hMax', floor(configHeight+0.5))
+      end
+    end
+  end
+
+  -- grab the last cluster
+  if lastCluster == cluster then
+    print('|cFF00FF00##scooping up last cluster info')
+    configHeight = configHeight + clusterHeight
+  end
+
+  if not B.configFramesCreated then
+    B.configFramesCreated = true
+    B:SetHeight(B.header:GetStringHeight() + configSpacing*3 + configHeight)
+  end
+  if configInit then configInit = nil end
+end
+
+M.Command = function(enable, editbox)
+  displays = B.displays
+  if type(enable) == 'boolean' then
+    B.Conf.ConfigMode = enable
+  else
+    B.Conf.ConfigMode = (B.Conf.ConfigMode == false) and true or false
+  end
+
+  print('/BUFF', B.Conf.ConfigMode, type(B.Conf.ConfigMode))
+  if B.Conf.ConfigMode  then
+    if not B.configFramesCreated then
+      InitConfig()
+    end
+    print('Veneer config')
+    B:Show()
+  else
+    B:Hide()
+  end
+  B.UpdateAll()
+  B.UpdateConfigLayers()
+end
+
+B.Close = function ()
+  M.Command()
+end
+
+B.ToggleGuides = function(_, self)
+  B.Conf.GuidesMode = (not B.Conf.GuidesMode)
+  if B.Conf.GuidesMode then
+    self:GetNormalTexture():SetTexture(0.94, 0.21, 0.21, 1)
+  else
+    self:GetNormalTexture():SetTexture(0, 0, 0, 1)
+  end
+
+  B.UpdateConfigLayers()
+end
+
+M.OnEnable = function()
+  M.Command(B.Conf.ConfigMode)
+end
+
+M.OnInitialize = function()
+  DEFAULT_CHAT_FRAME:AddMessage("|cFF22D822Veneer|r")
+  SLASH_BUFFALO1, SLASH_BUFFALO2 = "/buffalo", "/buff"
+  SlashCmdList.BUFFALO = M.Command
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Constants.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,347 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/22/2016 3:14 PM
+local _, A = ...
+local B = A.frame
+
+-----------------------
+-- Buff frames metadata
+-----------------------
+local legendAlpha = 0.5
+B.displays.BuffButton = {
+  legendColor = {0, 1, 0, legendAlpha},
+  maxIcons = BUFF_MAX_DISPLAY,
+  actualIcons = function () return _G.BUFF_ACTUAL_DISPLAY end,
+  buffName = 'BuffButton',
+  drawCount = {},
+  filters = 'HELPFUL',
+  anchorTemplate = 'VeneerAnchorTemplate',
+}
+B.displays.DebuffButton = {
+  legendColor = {1, 0, 0, legendAlpha},
+  maxIcons = DEBUFF_MAX_DISPLAY,
+  actualIcons = function () return _G.DEBUFF_ACTUAL_DISPLAY end,
+  buffName = 'DebuffButton',
+  drawCount = {},
+  filters = 'HARMFUL',
+  anchorTemplate = 'VeneerAnchorTemplate',
+}
+B.displays.TempEnchant = {
+  legendColor = {1, 0, 0.5, legendAlpha},
+  maxIcons = NUM_TEMP_ENCHANT_FRAMES,
+  actualIcons = function () return BuffFrame.numEnchants end,
+  buffName = 'TempEnchant',
+  drawCount = {},
+  anchorTemplate = 'VeneerAnchorTemplate',
+}
+B.displays.ConsolidatedBuff = {
+  legendColor = {0.5, 0.5, 0.5, legendAlpha},
+  maxIcons = 9,
+  actualIcons = function() return select(2, GetRaidBuffInfo()) end,
+  buffName = 'ConsolidatedBuff',
+  anchorTemplate = 'VeneerConsolidatedBuffsAnchor',
+  buffTemplate = 'VeneerRaidBuffTemplate',
+  drawCount = {},
+  filters = 'HELPFUL',
+}
+
+-----------------------
+-- RaidBuff visual args
+-----------------------
+B.BuffStyles = {
+  ["active"] = {
+    SetDesaturated = false,
+    Color = {1, 1, 1, 1},
+    SetBlendMode = 'BLEND',
+    TextColor = {1,1,1,1},
+  },
+  ["missing"] = {
+    SetDesaturated = false,
+    Color = {1, 0, 0, 0.5},
+    SetBlendMode = 'ADD',
+    TextColor = {1,0,0,1},
+  },
+  ["available"] = {
+    SetDesaturated = true,
+    Color = {0.35, 1, 0.35, 0.5},
+    SetBlendMode = 'ADD',
+    TextColor = {1, 1, 0, 1},
+  },
+}
+
+--- RaidBuff availability criteria
+-- @field spellID   - UnitAura() == true
+-- @field spec      - test for spec choice
+-- @field auraType  - UnitAura() == true, and no other tests of the same value have returned true prior
+-- @field talent    - test for talent selection
+-- @field petFamily - test pet family
+-- @field [true]    - passive group aura
+B.ClassRaidBuffs = {
+  -- stats
+  [1] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 160206, spellName = 'Lone Wolf: Power of the Primates', auraType = 'lonewolf'},
+      {petFamily = 'Dog'}, -- active pet family
+      {petFamily = 'Gorilla'},
+      {petFamily = 'Shale Spider'},
+      {petFamily = 'Worm'},
+    },
+    ['DRUID'] = {
+      {spellID = 1126, spellName = 'Mark of the Wild'},
+    },
+    ['MONK'] = {
+      {spellID = 115921, spellName = 'Legacy of the Emperor'},
+      {spellID = 116781, spellName = 'Legacy of the White Tiger'} -- windwalker, replaces emperor internally
+    },
+    ['PALADIN'] = {spellID = 20217, spellName = 'Blessing of Kings', auraType = 'blessing'},
+  },
+
+  -- stamina
+  [2] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 160199, spellName = 'Lone Wolf: Fortitude of the Bear', auraType = 'lonewolf'},
+      {petFamily = 'Bear'}, -- active pet family
+      {petFamily = 'Goat'},
+      {petFamily = 'Rylak'},
+      {petFamily = 'Silithid'},
+    },
+    ['PRIEST'] = {
+      {spellID = 21562, 'Power Word: Fortitude'}
+    },
+    ['WARRIOR'] = {
+      {spellID = 469, spellName = 'Commanding Shout', auraType = 'shout'}
+    },
+    ['WARLOCK'] = {
+      {true}
+    }
+  },
+
+  -- attack power
+  [3] = {
+    ['HUNTER'] = {
+      {true},
+    },
+    ['DEATHKNIGHT'] = {
+      {spec = 2},
+      {spec = 3},
+    },
+    ['WARRIOR'] = {
+      {spellName = 'Battle Shout', auraType = 'shout'}
+    }
+  },
+
+  -- HASTE
+  [4] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 160203, spellName = 'Lone Wolf: Haste of the Hyena', auraType = 'lonewolf'},
+      {petFamily = 'Hyena'}, -- active pet family
+      {petFamily = 'Sporebat'},
+      {petFamily = 'Rylak'},
+      {petFamily = 'Wasp'},
+    },
+    ['DEATHKNIGHT'] = {
+      {spec = 2}, -- unholy aura
+      {spec = 3},
+    },
+    ['PRIEST'] = {
+      {spec = 3}, -- mind quickening
+    },
+    ['ROGUE'] = {
+      true -- swiftblade's
+    },
+    ['SHAMAN'] = {
+      true -- grace of air
+    },
+  },
+
+  -- SPELL POWER
+  [5] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 160205, spellName = 'Lone Wolf: Wisdom of the Serpent', auraType = 'lonewolf'},
+      {petFamily = 'Waterstrider'}, -- active pet family
+      {petFamily = 'Serpent'},
+      {petFamily = 'Silithid'},
+    },
+    ['MAGE'] = {
+      {spellID = 1459, spellName = 'Arcane Brilliance'},  -- arcane brilliance
+      {spellID = 61316, spellName = 'Dalaran Brilliance'}, -- dalaran brilliance
+    },
+    ['WARLOCK'] = {
+      {spellID = 109773,spellName = 'Dark Intent' }
+    },
+  },
+
+  -- CRITICAL STRIKE
+  [6] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 160200, spellName = 'Lone Wolf: Ferocity of the Raptor', auraType = 'lonewolf'},
+      {petFamily = 'Devilsaur'}, -- active pet family
+      {petFamily = 'Quilen'},
+      {petFamily = 'Raptor'},
+      {petFamily = 'Shale Spider'},
+      {petFamily = 'Waterstrider'},
+      {petFamily = 'Wolf'},
+    },
+    ['DRUID'] = {
+      {spec = 2, spellID = 17007, auraType = 'druidform'}
+    },
+    ['MAGE'] = {
+      {spellID = 1459, spellName = 'Arcane Brilliance'},  -- arcane brilliance
+      {spellID = 61316, spellName = 'Dalaran Brilliance'}, -- dalaran brilliance
+    },
+    ['MONK'] = {
+      {spellID = 116781, spellName = 'Legacy of the White Tiger', spec = 2} -- windwalker
+    }
+  },
+
+  -- MASTERY
+  [7] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 160198, spellName = 'Lone Wolf: Grace of the Cat', auraType = 'lonewolf'},
+      {petFamily = 'Cat'}, -- active pet family
+      {petFamily = 'Hydra'},
+      {petFamily = 'Spirit Beast'},
+      {petFamily = 'Tallstrider'},
+    },
+    ['DEATHKNIGHT'] = {
+      {spec = 1}
+    },
+    ['DRUID'] = {
+      {spec = 1, spellID = 24907, auraType = 'druidform'},
+    },
+    ['PALADIN'] = {
+      {spec = 1, spellID = 19740, spellName = 'Blessing of Might', auraType = 'blessing'}
+    },
+    ['SHAMAN'] = {true},
+  },
+
+  -- MULTISTRIKE
+  [8] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 172968, spellName = 'Lone Wolf: Quickness of the Dragonhawk', auraType = 'lonewolf'},
+      {petFamily = 'Bat'}, -- active pet family
+      {petFamily = 'Clefthoof'},
+      {petFamily = 'Corehound'},
+      {petFamily = 'Dragonhawk'},
+      {petFamily = 'Wind Serpent'},
+    },
+    ['MONK'] = {
+      {spec = 2 }
+    }, -- Windflurry,
+    ['PRIEST'] = {
+      {spec = 3 }
+    }, -- quickening,
+    ['ROGUE'] = {true}, -- swiftblade's
+    ['WARLOCK'] = {
+      {spellID = 109773,spellName = 'Dark Intent' }
+    },
+  },
+
+  -- VERSATILITY
+  [9] = {
+    ['HUNTER'] = {
+      {talent = {155228}, spellID = 172967, spellName = 'Lone Wolf: Versatility of the Ravager', auraType = 'lonewolf'},
+      {petFamily = 'Ravager'}, -- active pet family
+      {petFamily = 'Boar'},
+      {petFamily = 'Porcupine'},
+      {petFamily = 'Clefthoof'},
+      {petFamily = 'Stag'},
+      {petFamily = 'Worm'},
+      {petFamily = 'Bird of Prey'},
+    },
+    ['DEATH KNIGHT'] = {
+      {spec = 2}, -- unholy aura
+      {spec = 3},
+    },
+    ['DRUID'] = {
+      {spellID = 1126, spellName = 'Mark of the Wild'},
+    },
+    ['PALADIN'] = {
+      {spec = 2}, -- retribution
+    },
+    ['WARRIOR'] = {
+      {spec = 2}, -- arms or fury
+      {spec = 3},
+    },
+  }
+}
+
+-------------------------
+-- Default config values
+-------------------------
+B.ConfDefaults = {
+  -- defaulted to on for first-time setup
+  ConfigMode = true,
+  GuidesMode = true,
+
+  BuffButtonAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -200, -5},
+  BuffButtonMax = 24,
+  BuffButtonPerRow = 10,
+  BuffButtonSize = 50,
+  BuffButtonSpacing = 4,
+  BuffButtonZoom = 15,
+  BuffButtonVertexColor = {},
+  BuffButtonPoint = {'TOPRIGHT', 'TOPRIGHT'},
+  BuffButtonDurationSize = 16,
+  BuffButtonDurationPoint = {'BOTTOM', 'BOTTOM', 0, -1},
+  BuffButtonCountSize = 18,
+  BuffButtonCountPoint = {'TOPRIGHT', 'TOPRIGHT', -3, -3},
+  BuffButtonRelativeX = -1,
+  BuffButtonRelativeY = -1,
+
+  BuffButtonColor = {1, 1, 1, 1},
+  BuffButtonPlayerColor = {1,1,1,1},
+  BuffButtonRaidColor = {0.25,1,0.25,1},
+  BuffButtonBossColor = {1,0.5,0,1},
+  BuffButtonBorder = 1,
+
+  BuffButtonWarningFade = true,
+  BuffButtonShowSelfCast = true,
+
+  DebuffButtonAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -200, -200},
+  DebuffButtonMax = 12,
+  DebuffButtonPerRow = 10,
+  DebuffButtonSize = 50,
+  DebuffButtonSpacing = 4,
+  DebuffButtonDurationSize = 16,
+  DebuffButtonZoom = 15,
+  DebuffButtonVertexColor = {},
+  DebuffButtonPoint = {'TOPRIGHT','TOPRIGHT'},
+  DebuffButtonRelativeX = -1,
+  DebuffButtonRelativeY = -1,
+
+
+  TempEnchantAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -200, -300},
+  TempEnchantMax = 2,
+  TempEnchantPerRow = 10,
+  TempEnchantSize = 50,
+  TempEnchantSpacing = 4,
+  TempEnchantDurationSize = 16,
+  TempEnchantZoom = 15,
+  TempEnchantVertexColor = {},
+  TempEnchantPoint = {'TOPRIGHT', 'TOPRIGHT'},
+  TempEnchantRelativeX = -1,
+  TempEnchantRelativeY = -1,
+  TempEnchantColor = {1,0,0.5,1},
+
+  ConsolidatedBuffAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', 0, 0},
+  ConsolidatedBuffIcon = false,
+  ConsolidatedBuffMax = 9,
+  ConsolidatedBuffSize = 16,
+  ConsolidatedBuffParent = 'BuffButton',
+  ConsolidatedBuffPosition = 1,
+  ConsolidatedBuffSpacing = 1,
+  ConsolidatedBuffBorder = 0,
+  ConsolidatedBuffPerRow = 3,
+  ConsolidatedBuffPoint = {'TOPRIGHT', 'TOPRIGHT'},
+  ConsolidatedBuffRelativeX = -1,
+  ConsolidatedBuffRelativeY = -1,
+  ConsolidatedBuffDurationSize = 0,
+  ConsolidatedBuffDurationPoint = {'BOTTOM', 'BOTTOM', 0, 0},
+  ConsolidatedBuffCountPoint = {'BOTTOM', 'BOTTOM', 0, 0},
+
+  RaidShowMissing = true,
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core.xml	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,477 @@
+<Ui>
+  <Font name="VeneerFont" />
+
+  <Font name="VeneerFont_Small" font="Fonts\FRIZQT__.TTF" outline="NORMAL" height="16" />
+  <Font name="VeneerFont_Large" font="Fonts\FRIZQT__.TTF"  outline="NORMAL" height="24" />
+
+  <Font name="VeneerFontNormal" inherits="VeneerFont_Small">
+    <Color r="1" g="1" b="1" a="1" />
+  </Font>
+
+  <Font name="VeneerFontHighlight" inherits="VeneerFont_Small" outline="NORMAL">
+    <Color r="0" g=".7" b="1" a="1" />
+  </Font>
+  <Font name="VeneerFontHighlightLarge" inherits="VeneerFont_Large">
+    <Color r="0" g=".7" b="1" a="1" />
+  </Font>
+
+  <!-- Defining here so interfaces are easy to spot -->
+  <Frame name="VeneerHandlerTemplate" virtual="true">
+    <KeyValues>
+    </KeyValues>
+  </Frame>
+
+  <!-- Buff-button underlay  -->
+  <Frame name="VeneerDecorTemplate" virtual="true" enableMouse="true" movable="true" frameStrata="BACKGROUND" hidden="true">
+    <Size x="30" y="30" />
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture name="$parentButtonArea" setAllPoints="true" parentKey="background" alphaMode="BLEND">
+          <Color r="1" g="1" b="1" a="1" />
+        </Texture>
+        <Texture name="$parentButtonBackdrop" parentKey="backgroundFill" alphaMode="BLEND">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT" x="1" y="1" relativeKey="$parent.background" />
+            <Anchor point="TOPRIGHT" relativePoint="TOPRIGHT" x="-1" y="-1" relativeKey="$parent.background" />
+          </Anchors>
+          <Color r="0" g="0" b="0" a="1" />
+        </Texture>
+      </Layer>
+    </Layers>
+  </Frame>
+
+  <!-- Buff button overlay, and positioning anchor -->
+  <Frame name="VeneerGuideTemplate" virtual="true" movable="true" frameStrata="LOW">
+    <Scripts>
+      <OnShow>
+        self.mouseover = self:IsMouseOver()
+      </OnShow>
+      <OnUpdate>
+        if self:IsMouseOver() and not self.contains then
+          self.caster:Show()
+        else
+          self.caster:Hide()
+        end
+      </OnUpdate>
+    </Scripts>
+    <Layers>
+      <Layer level="ARTWORK">
+        <Texture name="$parentLegend" parentKey="legend" parentArray="config" setAllPoints="true" hidden="true">
+          <Color a="0.5" r="0" g="1" b="0" />
+        </Texture>
+        <Texture name="$parentCountLegend" parentKey="count" parentArray="config" hidden="true">
+          <Color a="0.75" r="1" g=".5" b="0" />
+        </Texture>
+
+
+        <Texture name="$parentIconArea" parentKey="icon" alphaMode="ADD">
+          <Color r="0" g="0" b="0" a="0" />
+        </Texture>
+        <Texture name="$parentTextLegend" parentKey="duration" parentArray="config" hidden="true" alphaMode="BLEND">
+          <Color a="0.25" r="1" g="1" b="1" />
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <FontString inherits="VeneerFontNormal" parentArray="config" name="$parentID" parentKey="idText" hidden="true" outline="NORMAL">
+          <Anchors>
+            <Anchor point="CENTER" />
+          </Anchors>
+        </FontString>
+        <FontString inherits="VeneerFontNormal" parentKey="caster" outline="NORMAL">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeKey="$parent.icon" />
+          </Anchors>
+        </FontString>
+      </Layer>
+      <Layer level="HIGHLIGHT">
+
+      </Layer>
+    </Layers>
+  </Frame>
+
+  <!-- Anchor frame orientation-setting widget; click handler copies frame anchors over to buff buttons -->
+  <Button name="VeneerAnchorButton" virtual="true" parentArray="anchorButton" hidden="true">
+    <Scripts>
+      <OnClick>
+        self:GetParent():SetChildAnchors(self)
+      </OnClick>
+    </Scripts>
+    <Size x="15" y="15" />
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture setAllPoints="true">
+          <Color r="0" g="0" b="0" a="1" />
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <Texture>
+          <Color r="0" g="1" b="0.5" a="1" />
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" x="1" y="1" />
+            <Anchor point="TOPRIGHT" x="-1" y="-1" />
+          </Anchors>
+        </Texture>
+      </Layer>
+    </Layers>
+  </Button>
+
+  <Frame name="VeneerAnchorTemplate" virtual="true" enableMouse="false" movable="true" sizable="true" clampedToScreen="true">
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture name="$parentBackground" setAllPoints="true" parentArray="config" hidden="true">
+          <Color r="0" g="0.2" b="1" a="0.2" />
+        </Texture>
+        <FontString name="$parentHeading" inherits="VeneerFontHighlight" parentArray="config" parentKey="heading" hidden="true">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" />
+          </Anchors>
+        </FontString>
+        <FontString name="$parentDebug" inherits="VeneerFontNormal" parentArray="debug" parentKey="debug">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" />
+          </Anchors>
+        </FontString>
+      </Layer>
+      <Layer level="OVERLAY">
+
+        <Texture name="$parentCutJoint" parentKey="alignedJoint" hidden="true">
+          <Size x="4" y="4" />
+          <Color r="1" g="0" b="0" a="1" />
+        </Texture>
+        <Texture name="$parentCutY" parentKey="cuttingJointX" hidden="true">
+          <Size x="4" y="48" />
+          <Color r="1" g="1" b="0" a="1" />
+        </Texture>
+        <Texture name="$parentCutX" parentKey="cuttingJointY" hidden="true">
+          <Size x="48" y="4" />
+          <Color r="1" g="1" b="0" a="1" />
+        </Texture>
+        <Texture name="$parentPoppedY" parentKey="poppingJointX" hidden="true">
+          <Size x="4" y="48" />
+          <Color r="0" g="1" b="1" a="1" />
+        </Texture>
+        <Texture name="$parentPoppedX" parentKey="poppingJointY" hidden="true">
+          <Size x="48" y="4" />
+          <Color r="0" g="1" b="1" a="1" />
+        </Texture>
+        <Texture name="$parentChildSpace" parentKey="childSpace" hidden="true">
+          <Color r="0" g=".5" b="1" a="0.5" />
+        </Texture>
+      </Layer>
+      <Layer level="HIGHLIGHT">
+        <Texture name="$parentHighlight" setAllPoints="true" parentArray="config" hidden="true">
+          <Color r="1" g="1" b="0" a="0.2" />
+        </Texture>
+      </Layer>
+    </Layers>
+    <Frames>
+      <Button name="$parentAnchorUL" inherits="VeneerAnchorButton">
+        <Anchors>
+          <Anchor point="TOPLEFT" />
+        </Anchors>
+      </Button>
+      <Button name="$parentAnchorUR" inherits="VeneerAnchorButton">
+        <Anchors>
+          <Anchor point="TOPRIGHT" />
+        </Anchors>
+      </Button>
+      <Button name="$parentAnchorUR" inherits="VeneerAnchorButton">
+        <Anchors>
+          <Anchor point="BOTTOMRIGHT" />
+        </Anchors>
+      </Button>
+      <Button name="$parentAnchorUR" inherits="VeneerAnchorButton">
+        <Anchors>
+          <Anchor point="BOTTOMLEFT" />
+        </Anchors>
+      </Button>
+    </Frames>
+  </Frame>
+
+  <Frame name="VeneerConsolidatedBuffsAnchor" inherits="VeneerAnchorTemplate" virtual="true">
+    <Layers>
+      <Layer level="OVERLAY">
+        <!-- need to make our own number label since the original is buried under secure layer -->
+        <FontString inherits="VeneerFontNormal" name="$parentLabel" parentKey="label">
+          <Anchors>
+            <Anchor point="TOP" relativePoint="BOTTOM" x="0" y="-2" />
+          </Anchors>
+        </FontString>
+        <!--
+        <Texture name="$parentBackdrop" parentKey="background" setAllPoints="true" alphaMode="BLEND">
+          <Color r="0" g="0" b="0" a="1" />
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" x="1" y="1" />
+            <Anchor point="TOPRIGHT" x="-1" y="-1" />
+          </Anchors>
+        </Texture>
+        <Texture name="$parentIcon" parentKey="border" setAllPoints="true" alphaMode="BLEND">
+          <Color r="1" g="1" b="1" a="1" />
+        </Texture>
+        -->
+      </Layer>
+    </Layers>
+  </Frame>
+
+  <Frame name="VeneerRaidBuffTemplate" virtual="true" enableMouse="false">
+    <Layers>
+      <Layer level="ARTWORK">
+        <Texture name="$parentLegend" parentKey="legend" parentArray="config" setAllPoints="true" hidden="true">
+          <Color a="0.5" r="0" g="1" b="0" />
+        </Texture>
+        <Texture name="$parentCountLegend" parentKey="count" parentArray="config" hidden="true">
+          <Color a="0.75" r="1" g=".5" b="0" />
+        </Texture>
+
+
+        <Texture name="$parentIconArea" parentKey="icon" alphaMode="ADD">
+          <Color r="0" g="0" b="0" a="0" />
+        </Texture>
+        <Texture name="$parentTextLegend" parentKey="duration" parentArray="config" hidden="true" alphaMode="BLEND">
+          <Color a="0.25" r="1" g="1" b="1" />
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <FontString inherits="VeneerFontNormal" parentArray="config" name="$parentSymbol" parentKey="symbol">
+          <Anchors>
+            <Anchor point="TOP" />
+          </Anchors>
+        </FontString>
+        <FontString inherits="VeneerFontNormal" parentArray="config" name="$parentID" parentKey="idText" hidden="true">
+          <Anchors>
+            <Anchor point="BOTTOM" />
+          </Anchors>
+        </FontString>
+      </Layer>
+    </Layers>
+  </Frame>
+
+  <Button name="VeneerMissingBuffTemplate" virtual="true">
+    <Scripts>
+      <OnClick>
+        if self.spell and not InCombatLockdown() then
+          CastSpellByID(self.spell)
+        end
+      </OnClick>
+    </Scripts>
+    <Layers>
+      <Layer level="BORDER">
+        <Texture setAllPoints="true">
+          <Color r="1" g="1" b="1" a="0.25" />
+        </Texture>
+      </Layer>
+      <Layer level="ARTWORK">
+        <Texture name="$parentIcon" parentKey="icon">
+          <Size x="20" y="20" />
+          <Anchors>
+            <Anchor point="LEFT" />
+          </Anchors>
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <FontString name="$parentLabel" parentKey="label" inherits="VeneerFontNormal" justifyH="LEFT">
+          <Anchors>
+            <Anchor point="LEFT" relativePoint="RIGHT" relativeKey="icon" />
+          </Anchors>
+        </FontString>
+      </Layer>
+    </Layers>
+  </Button>
+
+  <FontString virtual="true" name="VeneerFieldName" parentKey="fieldname" inherits="VeneerFontHighlight" justifyV="TOP" justifyH="LEFT" />
+  <FontString virtual="true" name="VeneerFieldValue" parentKey="fieldvalue" inherits="VeneerFontNormal" justifyV="TOP" justifyH="LEFT" />
+  <Slider virtual="true" orientation="HORIZONTAL" name="VeneerConfigSlider">
+    <Size x="250" y="18" />
+    <Thumbtexture name="$parentThumb" alphaMode="BLEND" parentKey="thumb">
+      <Size x="12" y="18" />
+      <Color r="0.25" g="0.25" b="0.25" a="1" />
+    </Thumbtexture>
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture>
+          <Anchors>
+            <Anchor point="LEFT" />
+            <Anchor point="RIGHT" />
+          </Anchors>
+          <Size y="7" />
+          <Color r="0" g="0" b="0" a="1" />
+        </Texture>
+
+      </Layer>
+      <Layer level="OVERLAY">
+
+
+        <FontString name="$parentOptText" inherits="VeneerFieldName">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" />
+          </Anchors>
+        </FontString>
+
+        <FontString name="$parentOptText" inherits="VeneerFieldValue">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT" x="0" y="0" />
+          </Anchors>
+        </FontString>
+      </Layer>
+    </Layers>
+    <Scripts>
+      <OnValueChanged>
+        self:OnChange()
+      </OnValueChanged>
+    </Scripts>
+  </Slider>
+
+  <CheckButton virtual="true" orientation="HORIZONTAL" name="VeneerConfigCheckButton">
+    <Size x="24" y="24" />
+    <NormalTexture file="Interface\Buttons\UI-CheckBox-Up"/>
+    <PushedTexture file="Interface\Buttons\UI-CheckBox-Down"/>
+    <HighlightTexture file="Interface\Buttons\UI-CheckBox-Highlight" alphaMode="ADD"/>
+    <CheckedTexture file="Interface\Buttons\UI-CheckBox-Check"/>
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture setAllPoints="true">
+          <Size y="24" />
+          <Color r="0" g="0.7" b="1" a="1" />
+        </Texture>
+
+        <FontString name="$parentOptText" inherits="VeneerFieldName" >
+          <Anchors>
+            <Anchor point="LEFT" relativePoint="LEFT" x="24" y="0" />
+          </Anchors>
+        </FontString>
+
+      </Layer>
+    </Layers>
+    <Scripts>
+      <OnValueChanged>
+        self:OnChange()
+      </OnValueChanged>
+    </Scripts>
+  </CheckButton>
+
+
+  <Button virtual="true" name="VeneerConfigColor">
+    <Size x="400" y="20" />
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture setAllPoints="true">
+          <Color r="0.15" g="0.15" b="0.15" a="0.5" />
+        </Texture>
+        <Texture>
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" x="0" y="0" />
+          </Anchors>
+          <Size x="18" y="18" />
+          <Color r="0" g="0" b="0" a="1" />
+        </Texture>
+      </Layer>
+      <Layer level="ARTWORK">
+        <Texture name="$parentCurrentColor" parentKey="current">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" x="1" y="1" />
+          </Anchors>
+          <Size x="16" y="16" />
+          <Color r="1" g="1" b="1" a="1" />
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+
+        <FontString name="$parentOptText" inherits="VeneerFieldName">
+          <Anchors>
+            <Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" x="0" y="0" />
+          </Anchors>
+        </FontString>
+
+        <FontString parentKey="fieldvalue" name="$parentOptText" inherits="VeneerFontNormal" text="">
+          <Anchors>
+            <Anchor point="CENTER" relativePoint="CENTER" relativeKey="$thumb" x="0" y="0" />
+          </Anchors>
+        </FontString>
+
+      </Layer>
+    </Layers>
+  </Button>
+
+
+  <Frame name="Veneer" hidden="true" enableMouse="true" movable="true" parent="UIParent">
+    <Size x="400" y="400" />
+    <Anchors>
+      <Anchor point="CENTER" relativePoint="CENTER" x="0" y="0" />
+    </Anchors>
+    <Scripts>
+      <OnLoad>
+        self:RegisterForDrag('LeftButton')
+      </OnLoad>
+      <OnDragStart>
+        self:StartMoving()
+      </OnDragStart>
+      <OnDragStop>
+        self:StopMovingOrSizing()
+      </OnDragStop>
+    </Scripts>
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture setAllPoints="true">
+          <Color r="0" g="0" b="0" a="0.7" />
+        </Texture>
+      </Layer>
+      <Layer level="ARTWORK">
+        <FontString name="$parentHeader" parentKey="header" inherits="VeneerFontHighlightLarge" text="Veneer">
+          <Anchors>
+            <Anchor point="TOPLEFT" x="3" y="-4" />
+          </Anchors>
+        </FontString>
+      </Layer>
+    </Layers>
+    <Frames>
+      <Button name="$parentCloseButton" parentKey="close" text="X">
+        <ButtonText inherits="SystemFont_Small" />
+        <Scripts>
+          <OnClick>
+            self:GetParent():Close()
+          </OnClick>
+        </Scripts>
+        <Size x="24" y="24" />
+        <Anchors>
+          <Anchor point="TOPRIGHT" x="-5" y="-5" />
+        </Anchors>
+        <NormalTexture parentKey="normal" setAllPoints="true">
+          <Color a="1" r="0" g="0" b="0" />
+        </NormalTexture>
+        <PushedTexture setAllPoints="true">
+          <Color a="1" r="1" g="0" b="0" />
+        </PushedTexture>
+        <HighlightTexture setAllPoints="true" alphaMode="ADD">
+          <Color a=".5" r="1" g=".7" b="0.5" />
+        </HighlightTexture>
+      </Button>
+      <Button name="$parentGuidesButton" parentKey="guides" text="Guides">
+        <ButtonText inherits="SystemFont_Small" />
+        <Scripts>
+          <OnClick>
+            self:GetParent():ToggleGuides(self)
+          </OnClick>
+        </Scripts>
+        <Size x="36" y="24" />
+        <Anchors>
+          <Anchor point="RIGHT" relativePoint="LEFT" relativeTo="$parentCloseButton" x="-5" y="0" />
+        </Anchors>
+        <NormalTexture parentKey="normal" setAllPoints="true">
+          <Color a="1" r="0" g="0" b="0" />
+        </NormalTexture>
+        <PushedTexture setAllPoints="true">
+          <Color a="1" r="1" g="0" b="0" />
+        </PushedTexture>
+        <HighlightTexture setAllPoints="true" alphaMode="ADD">
+          <Color a=".5" r="1" g=".7" b="0.5" />
+        </HighlightTexture>
+      </Button>
+    </Frames>
+  </Frame>
+
+
+  <Script file="Init.lua" />
+  <Script file="Constants.lua" />
+  <Script file="Config.lua" />
+
+</Ui>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Init.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,371 @@
+--- Modulizer framework
+-- OnInitialize
+-- OnUpdate
+-- OnEnable     -- run when GetSpecialization() returns true
+
+local ADDON, A = ...
+Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent)
+local B = Veneer
+local wipe, min, max, random, tinsert = table.wipe, math.min, math.max, math.random, table.insert
+local pairs, ipairs, select, unpack, _G = pairs, ipairs, select, unpack, _G
+local type, tostring, format = type, tostring, string.format
+A.frame = B
+
+--- Cache tables
+local initOnced
+local modules = {}
+local queuedModules = {}
+local moduleStack = {
+}
+
+--- Various region categories
+B.displays = {}
+B.configLayers = {}
+B.configLayersRef = {}
+
+--@debug@
+--- Generates a print handler pointing to a static channel signature
+-- @usage func = B.print(sig)
+-- @param sig channel name or number
+local printfuncs = {}
+B.print = function(pref, ...)
+  if Devian and Devian.InWorkspace() then
+      printfuncs[pref] = printfuncs[pref] or function(...) print(pref,  ...) end
+
+    return printfuncs[pref]
+  else
+   return function () end
+  end
+end
+
+local rgb = {}
+local getcolor = function()
+  local n, p = 0, 4
+  for i = 1, 3 do
+    rgb[i] = min(random(n,p) * 64, 255)
+    if rgb[i] == 255 then
+      p = 4
+    elseif rgb[i] > 0 then
+      n = 2
+    end
+  end
+  return unpack(rgb)
+end
+
+local color = {}
+local fprints = {}
+B.fprint = function()
+  if not (Devian and Devian.InWorkspace()) then
+    return function() end
+  end
+
+
+  local sig = debugstack(2,1)
+  if fprints[sig] then
+    return fprints[sig]
+  end
+
+  local func = sig:match("%`(%a+)%'")
+  if not func then
+    func = sig:match("<(.-)>")
+  end
+  func = func:gsub('(%l+)(%u)', function(a, b) return a:sub(0,2) .. b  end, 1)
+  func = func:gsub('^.+%\\', '')
+  if not func then
+    func = 'noname'
+  end
+
+  local r, g, b = getcolor()
+  color[sig] = color[sig] or format('|cFF%02X%02X%02X%s|r', r, g, b, func)
+
+  --print(color[func] .. ' ( ' .. table.concat(args, ', ')..' )' )
+  func = B.print(func)
+  fprints[sig] = func
+  return func
+end
+
+--@end-debug@
+--[=[@non-debug@
+B.print = function() end
+--@end-non-debug@]=]
+
+-- for the Mikk script
+-- GLOBALS: NUM_LE_RAID_BUFF_TYPES
+-- GLOBALS: BUFF_FLASH_TIME_ON, BUFF_FLASH_TIME_OFF, BUFF_MIN_ALPHA, BUFF_WARNING_TIME, BUFF_DURATION_WARNING_TIME
+-- GLOBALS: BUFFS_PER_ROW, BUFF_MAX_DISPLAY, BUFF_ACTUAL_DISPLAY, DEBUFF_MAX_DISPLAY, DEBUFF_ACTUAL_DISPLAY, BUFF_ROW_SPACING
+-- GLOBALS: CONSOLIDATED_BUFFS_PER_ROW, CONSOLIDATED_BUFF_ROW_HEIGHT, NUM_TEMP_ENCHANT_FRAMES
+-- GLOBALS: BUFF_BUTTON_HEIGHT, BUFF_FRAME_BASE_EXTENT, BUFF_HORIZ_SPACING
+
+local print = B.print('Bfl')
+
+--- Template for making perpendicular traversals of the displays structure; also makes sure the table is there
+B.Abstract = function(dest, key, table)
+  if table then
+    for _, v in pairs(dest) do
+      v[key] = {}
+    end
+  end
+  B[key] = setmetatable({}, {
+    __index = function(t, k)
+      return dest[k][key]
+    end,
+    __newindex = function(_, k, v)
+      print('abstract write ('..key..'):', k)
+      dest[k][key] = v
+    end,
+    __tostring = function() return 'Abstract:'..key..'' end
+  })
+
+
+  return B[key]
+end
+
+
+--- localize for speed
+local layers, refs, displays = B.configLayers, B.configLayersRef, B.displays
+
+local ModulesCall = function(func)
+
+  local n = 0
+  for i = 1, #moduleStack do
+    print('calling level '..i)
+    local stackset = moduleStack[i]
+
+    for name, module in pairs(stackset) do
+      n = n + 1
+      print(n..'  '..name..'.'..func..'()')
+
+
+      if module[func] then
+        module[func](module)
+      end
+    end
+  end
+end
+
+
+local Enable = function()
+end
+
+--- The things that happen repeatedly
+local Init = function ()
+end
+
+
+--- Things that happen immediately upon entering world
+local InitOnce = function()
+  print('entering world first time')
+  local defaults = B.ConfDefaults
+  print('|cFFFFFF00Veneer|r')
+  if not VeneerData then
+    VeneerData = {}
+    for k,v in pairs(defaults) do
+      VeneerData[k] = v
+    end
+    print('Veneer defaults being used.')
+  end
+
+  B.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] end})
+
+  -- suffix tables
+  for name, display in pairs(displays) do
+    display.conf = setmetatable({}, {
+      __index = function(_, k)
+        --print('config check '.. name .. k)
+        return B.Conf[name .. k] or B.Conf['BuffButton' .. k]
+      end,
+      __newindex = function(_, k , v)
+        B.Conf[name..k] = v
+      end,
+    })
+  end
+
+  -- To ensure that modules are run in controlled order, walk the dependency list; if the dep shows up
+  -- in the loaded manifest, remove the value. If the dep list isn't empty, move that module to the next
+  -- layer.
+  local loaded = {}
+  local stackLevels = #moduleStack
+  local i = 1
+  moduleStack[1] = modules
+  repeat
+    print('setting init level '.. i)
+    local queue = moduleStack[i]
+    for name, module in pairs(queue) do
+
+      if queuedModules[name] and #queuedModules[name] > 0 then
+        local p = #queuedModules[name]
+        for j = 1, p do
+          local dep = queuedModules[name][j]
+
+          if loaded[dep] then
+            print( '    ' .. dep .. ' OK')
+            queuedModules[name][j] = nil
+            for k = j, p do
+              print('   shift ' .. (k+1)  .. ' ('..tostring(queuedModules[name][k+1])..') to ' .. k ..'')
+              queuedModules[name][k] = queuedModules[name][k+1]
+            end
+          end
+        end
+
+        if #queuedModules[name] == 0 then
+          queuedModules[name] = nil
+          print('  |cFF00FFFF'.. name ..'|r deps OK')
+          loaded[name] = true
+        else
+
+          print('  |cFFFF8800' .. name ..'|r pending')
+          local next = i+1
+          if not  moduleStack[next] then
+            moduleStack[next] = {}
+          end
+          stackLevels = next
+          moduleStack[next][name] = module
+          queue[name] = nil
+        end
+
+      else
+        print('  |cFF00FF00'.. name ..'|r no deps')
+        loaded[name] = true
+      end
+   end
+    i = i + 1
+  until i > stackLevels
+
+
+  for level, batch in ipairs(moduleStack) do
+    print('config level', level)
+    for name, module in pairs(batch) do
+      print('integrity check', name)
+
+      --[===[@non-debug@
+      if module.defaults and not VeneerData[name] then
+      --@end-non-debug@]===]
+        print('Adding defaults from module ', name)
+        VeneerData[name] = module.default
+      --[===[@non-debug@
+      end
+      --@end-non-debug@]===]
+    end
+  end
+  -- remove from existing
+end
+
+--- Fires an update to all modules
+local lastUpdate
+function B.UpdateAll(...)
+  lastUpdate = GetTime()
+  ModulesCall('OnUpdate', lastUpdate)
+end
+
+B:RegisterEvent('PLAYER_ENTERING_WORLD')
+B:SetScript('OnEvent', function(self, event)
+  if event == 'PLAYER_ENTERING_WORLD' then
+    if not initOnced then
+      InitOnce()
+      ModulesCall('OnInitialize')
+      initOnced = true
+      C_Timer.After(1, function()
+        if GetSpecialization() then
+          print(GetSpecialization(), 'enabling')
+          ModulesCall('OnEnable')
+          B:SetScript('OnUpdate', nil)
+        end
+
+      end)
+    end
+
+  end
+
+  B.UpdateAll()
+end)
+
+--- Modulizer method
+--
+function B:RegisterModule (name, module, ...)
+  if modules[name] then
+    print('pulling modules[|cFFFF8800'.. tostring(name) ..'|r]')
+    return modules[name]
+  end
+
+  print('new module |cFF00BBFF'.. tostring(name) ..'|r')
+  if module then
+    if modules[name] then
+      error("Module table for '"..tostring(name).."' already exists.")
+    end
+  else
+    module = CreateFrame('Frame', 'Veneer' .. tostring(name) .. 'Handler', B, 'VeneerHandlerTemplate')
+  end
+  modules[name] = module
+  if select('#', ...) >= 1 then
+    local numDeps = select('#', ...)
+    print('  '..numDeps..' deps detected')
+    for i = 1, numDeps do
+      local dep = select(i, ...)
+        -- means that init/enable funcs are ordered to run after deps do their things
+      queuedModules[name] = queuedModules[name]  or {}
+      tinsert(queuedModules[name], dep)
+      print('  needs '..dep)
+    end
+  end
+  return module
+end
+
+
+B.SetConfigLayers =  function(frame)
+  local print = B.fprint()
+  if not frame.config then
+    print(frame:GetName(), 'has no config layers')
+    return
+  end
+  print('Registering config layers from', frame:GetName())
+
+  for i, subframe in ipairs(frame.config) do
+    -- make sure there are no duplicates
+    if not refs[subframe] then
+      local key = #layers+1
+      layers[key] = subframe
+      refs[subframe] = key
+    end
+    print(' ', i, subframe:GetName())
+  end
+end
+
+B.RemoveConfigLayers = function(frame)
+  local print = B.fprint()
+  print('|cFFFF0000RemoveConfigLayers', frame:GetName())
+  for i, subframe in pairs(layers) do
+    if subframe:GetParent() == frame then
+      print('|cFFFF8800  ', subframe:GetParent():GetName(), '|cFFFFFF00', subframe:GetName())
+      layers[i]:Hide()
+      layers[i] = nil
+      refs[subframe] = nil
+    end
+  end
+end
+
+B.UpdateConfigLayers = function()
+  local print = B.fprint()
+  local func = B.Conf.GuidesMode and 'Show' or 'Hide'
+  local numAnchors = 0
+  for name, display in pairs(displays) do
+    numAnchors = numAnchors + 1
+    display.anchor:EnableMouse(B.Conf.GuidesMode)
+    if B.Conf.GuidesMode then
+      display.anchor:SetScript('OnUpdate', display.anchor.OnUpdate)
+    else
+      display.anchor:SetScript('OnUpdate', nil)
+
+      for i, anchorButton in ipairs(display.anchor.anchorButton) do
+        anchorButton:Hide()
+      end
+
+    end
+
+  end
+  for id, region in pairs(layers) do
+    print(id, region:GetName(), func)
+    region[func](region)
+  end
+
+  print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames')
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveInfo.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,135 @@
+local B = select(2,...).frame
+local wipe, pairs, ipairs, min, max, unpack = table.wipe, pairs, ipairs, min, max, unpack
+local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo
+local GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo
+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
+--------------------------------------------------------------------
+--- Tracker-specific data retrieval functions
+--------------------------------------------------------------------
+
+Quest.GetNumWatched = function()
+  return GetNumQuestWatches ()
+end
+Quest.GetInfo = function (self, watchIndex)
+  print('|cFF00DDFFQuest|r.|cFF0088FFGetInfo(|r'.. tostring(watchIndex)..'|r)')
+  local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete,
+  startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
+print(GetQuestWatchInfo(watchIndex))
+  if not questID then
+    return
+  end
+  print(self.Info)
+  self.Info[questID] = self.Info[questID] or {}
+
+  local q = self.Info[questID]
+  q.watchIndex = watchIndex
+  q.type = 'Quest'
+  q.questID = questID
+  q.title = title
+  q.questLogIndex = questLogIndex
+  q.numObjectives = numObjectives
+  q.requiredMoney = requiredMoney
+  q.isComplete = isComplete
+  q.startEvent = startEvent
+  q.isAutoComplete = isAutoComplete
+  q.failureTime = failureTime
+  q.timeElapsed = timeElapsed
+  q.questType = questType
+  q.isTask = isTask
+  q.isStory = isStory
+  q.isOnMap = isOnMap
+  q.hasLocalPOI = hasLocalPOI
+
+  --- Start QuestLogEntry calls
+  -----------------------------------------
+  SelectQuestLogEntry(questLogIndex)
+  q.greenRange = GetQuestGreenRange()
+  q.isDaily = QuestIsDaily()
+  q.isWeekly = QuestIsWeekly()
+  -----------------------------------------
+
+  --- End QuestLogEntry calls
+  print('   |cFF0088FF', q.isDaily, q.isWeekly)
+
+  q.isComplete = IsQuestComplete(questID)
+  q.isBreadCrumb = IsBreadcrumbQuest(questID)
+  q.isStoryQuest = IsStoryQuest(questID)
+  q.completionText= GetQuestLogCompletionText(questLogIndex)
+  q.trackingID = questID
+  q.superTracked =  (questID == GetSuperTrackedQuestID()) -- call directly so artifact data doesn't become an issue
+  q.numObjectives = GetNumQuestLeaderBoards(questLogIndex)
+  q.objectives = {}
+  for i = 1, q.numObjectives do
+    local text, type, finished = GetQuestLogLeaderBoard(i, questLogIndex)
+    q.objectives[i] = {
+      type = type,
+      text = text,
+      finished = finished
+    }
+    if type == 'event' then
+    elseif type == 'monster' then
+    elseif type == 'object' then
+    elseif type == 'reputation' then
+    elseif type == 'item' then
+    end
+  end
+
+  local link, icon, charges = GetQuestLogSpecialItemInfo(questLogIndex)
+  local start, duration, enable = GetQuestLogSpecialItemCooldown(questLogIndex)
+  if link or icon or charges then
+    q.specialItem = {
+      link = link,
+      charges = charges,
+      icon = icon,
+      start = start,
+      duration = duration,
+      enable = enable,
+    }
+  end
+
+  self.LogInfo[questLogIndex] = q
+  print('|cFF0088FFGetQuestInfo('..questID..')|r', questLogIndex, title)
+  return q
+end
+
+Cheevs.GetNumWatched = function(self)
+  Cheevs.trackedCheevs = {GetTrackedAchievements()}
+  return GetNumTrackedAchievements()
+end
+Cheevs.GetInfo = function(self, index)
+  local cheevID = Cheevs.trackedCheevs[index]
+  local id, name, points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy = GetAchievementInfo(cheevID)
+
+  print('|cFF00FF00', GetAchievementNumCriteria(cheevID))
+  self.Info[cheevID] = {}
+  local c = self.Info[cheevID]
+  c.type = 'Cheevs'
+  c.watchIndex = index
+  c.cheevID = cheevID
+  c.title = name
+  c.points, c.completed, c.month, c.day, c.year, c.description, c.flags, c.icon, c.rewardText, c.isGuildAch, c.wasEarnedByMe, c.earnedBy =
+  points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy
+  c.numObjectives = GetAchievementNumCriteria(cheevID)
+  c.objectives = {}
+  for i = 1, c.numObjectives do
+    local description, type, completed, quantity, requiredQuantity, characterName, flags, assetID, quantityString, criteriaID = GetAchievementCriteriaInfo(cheevID, i)
+    c.objectives[i] = {
+      text = description,
+      type = type,
+      finished = completed,
+      quantity = quantity,
+      requiredQuantity = requiredQuantity,
+      characterName = characterName,
+      flags = flags,
+      assetID = assetID,
+      quantityString = quantityString,
+      criteriaID = criteriaID,
+    }
+  end
+
+  self.WatchInfo[index] = c
+  return self.Info[cheevID]
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveTracker.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,249 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/26/2016 1:51 AM
+local B = select(2,...).frame
+local wipe, pairs, ipairs, min, max, unpack = table.wipe, pairs, ipairs, min, max, unpack
+local setmetatable, type = setmetatable, type
+local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo
+local GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo
+local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
+local print = B.print('Objectives')
+local ObjectiveTrackerFrame = ObjectiveTrackerFrame
+
+--[[
+  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
+
+]]
+--- Global Frames
+local Wrapper = _G.VeneerObjectiveWrapper
+local Scroller = Wrapper.scrollArea
+local Scroll = _G.VeneerObjectiveScroll
+
+--- list used to make things happen
+mod.orderedNames = {[1] = 'AutoQuest',  [2] = 'Quest', [3] = 'Cheevs'}
+
+--- ipairs() list of handlers for wrapper update
+mod.orderedHandlers = {}
+mod.orderedTrackers = {}
+mod.indexedTrackers = {}
+--- pairs() list of handler frames for tracker updates
+mod.namedTrackers = {}
+
+--- Handler stubs
+mod.AutoQuest = {
+  name = "AutoQuest"
+}
+mod.Quest = {
+  name = "Quest"
+}
+mod.Cheevs = {
+  name = "Cheevs"
+}
+
+
+--- Temp values set during updates
+local wrapperWidth, wrapperHeight
+local scrollWidth, scrollHeight
+local previousBlock
+local currentBlock
+
+local frame_guide_init = function(self)
+  self.testU = self.testU or self:CreateTexture('TestU', 'OVERLAY', 'VnTestLine')
+  self.testB = self.testB or self:CreateTexture('TestB', 'OVERLAY', 'VnTestLine')
+  self.testL = self.testL or self:CreateTexture('TestL', 'OVERLAY', 'VnTestLine')
+  self.testR = self.testR or self:CreateTexture('TestR', 'OVERLAY', 'VnTestLine')
+end
+local frame_guide = function(self, target)
+  if not target then return end
+  if target:IsDragging() then return end
+  local thickness = 1
+  local midX, midY = target:GetCenter()
+  local width, height = target:GetWidth() * 1.5, target:GetHeight() * 1.5
+  --print('frame', target:GetLeft(), target:GetTop(), target:GetRight(), target:GetBottom())
+  self.testB:ClearAllPoints()
+  self.testB:SetPoint('TOP', UIParent, 'BOTTOMLEFT', midX, target:GetBottom())
+  self.testB:SetSize(width,thickness)
+
+  self.testU:ClearAllPoints()
+  self.testU:SetPoint('BOTTOM', UIParent, 'BOTTOMLEFT', midX, target:GetTop())
+  self.testU:SetSize(width,thickness)
+
+  self.testL:ClearAllPoints()
+  self.testL:SetPoint('RIGHT', UIParent, 'BOTTOMLEFT', target:GetLeft(), midY)
+  self.testL:SetSize(thickness,height)
+
+  self.testR:ClearAllPoints()
+  self.testR:SetPoint('LEFT', UIParent, 'BOTTOMLEFT', target:GetRight(), midY)
+  self.testR:SetSize(thickness,height)
+end
+
+--- Handler template
+local CreateHandler = function (self, name, index)
+  print(self, name)
+  local handler = setmetatable({}, {
+    __tostring = function() return name end,
+    __call = function (self) mod.UpdateTracker(self) end
+  })
+  if type(mod.orderedHandlers[index]) == 'table' then
+    return mod.orderedHandlers[index]
+  end
+
+  print('take up locals first')
+  local preset = {}
+  for k,v in pairs(mod[name]) do
+    preset[k] = true
+    if type(v) == 'table' then
+      handler[k] = {}
+    else
+      handler[k] = v
+    end
+  end
+
+  print('resulting handler contents')
+  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]
+      end
+    else
+      print(name, 'has its own', k)
+    end
+  end
+  print('|cFFFF4400'..tostring(name)..'|r:')
+  for k, v in pairs(handler) do
+    print(string.format("%24s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v)))
+  end
+  mod[name] = handler
+  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.LogInfo = {}     -- find by log ID (quest log mainly)
+Tracker.WatchBlock = {}
+Tracker.LogBlock = {}
+
+
+
+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
+    else
+      block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, Scroll, 'VeneerTrackerBlock')
+      block.SetStyle = mod.SetBlockStyle
+      block:ClearAllPoints() -- making sure the anchors are clear in case they get added for some other template usage
+    end
+
+    handler.usedBlocks[blockIndex] = block
+  end
+  return handler.usedBlocks[blockIndex]
+end
+local SmallEvents = {
+  QUEST_ACCEPTED = 'OnQuestAccepted'
+}
+
+local HandlerEvents = {
+  QUEST_ACCEPTED = mod.Quest,
+  QUEST_WATCH_LIST_CHANGED = mod.Quest,
+  SUPER_TRACKED_QUEST_CHANGED = mod.Quest,
+  QUEST_LOG_UPDATE = mod.Quest,
+  TRACKED_ACHIEVEMENT_LIST_CHANGED = mod.Cheevs,
+  TRACKED_ACHIEVEMENT_UPDATE = mod.Cheevs
+}
+
+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()
+    isHandled = true
+  end
+  if not isHandled then
+    print('|cFFFF4400'..event..'|r', ...)
+  end
+  --@debug@
+  if Devian and Devian.InWorkspace() then
+    frame_guide_init(Scroller)
+    frame_guide(Scroller, Scroller)
+  end
+end
+
+function mod:OnInitialize()
+
+  self.InitializeTrackers()
+  for event, _ in pairs(SmallEvents) do
+    self:RegisterEvent(event)
+  end
+  for event, _ in pairs(HandlerEvents) do
+    self:RegisterEvent(event)
+  end
+  self:SetScript('OnEvent', mod.OnEvent)
+
+  ObjectiveTrackerFrame:UnregisterAllEvents()
+  ObjectiveTrackerFrame:Hide()
+end
+
+--[[
+QUESTLINE_UPDATE	This event is not yet documented
+QUESTTASK_UPDATE	This event is not yet documented
+QUEST_ACCEPTED	Fires when a new quest is added to the player's quest log (which is what happens after a player accepts a quest).
+QUEST_ACCEPT_CONFIRM	Fires when certain kinds of quests (e.g. NPC escort quests) are started by another member of the player's group
+QUEST_AUTOCOMPLETE	Fires when a quest is automatically completed (remote handin available)
+QUEST_BOSS_EMOTE	This event is not yet documented
+QUEST_CHOICE_CLOSE	This event is not yet documented
+QUEST_CHOICE_UPDATE	This event is not yet documented
+QUEST_COMPLETE	Fires when the player is looking at the "Complete" page for a quest, at a questgiver.
+QUEST_DETAIL	Fires when details of an available quest are presented by a questgiver
+QUEST_FINISHED	Fires when the player ends interaction with a questgiver or ends a stage of the questgiver dialog
+QUEST_GREETING	Fires when a questgiver presents a greeting along with a list of active or available quests
+QUEST_ITEM_UPDATE	Fires when information about items in a questgiver dialog is updated
+QUEST_LOG_UPDATE	Fires when the game client receives updates relating to the player's quest log (this event is not just related to the quests inside it)
+QUEST_POI_UPDATE	This event is not yet documented
+QUEST_PROGRESS	Fires when interacting with a questgiver about an active quest
+QUEST_REMOVED	This event is not yet documented
+QUEST_TURNED_IN	Fired when a quest is turned in
+QUEST_WATCH_LIST_CHANGED	This event is not yet documented
+QUEST_WATCH_OBJECTIVES_CHANGED	This event is not yet documented
+QUEST_WATCH_UPDATE	Fires when the player's status regarding a quest's objectives changes, for instance picking up a required object or killing a mob for that quest. All forms of (quest objective) progress changes will trigger this event.]
+
+TRACKED_ACHIEVEMENT_LIST_CHANGED	This event is not yet documented
+TRACKED_ACHIEVEMENT_UPDATE	Fires when the player's progress changes on an achievement marked for watching in the objectives tracker
+ ]]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveTracker.xml	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,237 @@
+<Ui>
+
+
+  <Texture name="VnTestLine" virtual="true">
+    <Color r="1" g="1" b="0" a="1" />
+  </Texture>
+
+  <Frame name="VeneerObjectiveWrapper" parent="UIParent" movable="true" enableMouse="true">
+    <Scripts>
+      <OnLoad>
+        self.toggle = true
+        self:RegisterForDrag('LeftButton')
+      </OnLoad>
+      <OnShow>
+      </OnShow>
+      <OnDragStart>
+        self:StartMoving()
+      </OnDragStart>
+      <OnDragStop>
+        self:StopMovingOrSizing()
+      </OnDragStop>
+      <!--@debug@-->
+      <!--@end-debug@-->
+    </Scripts>
+    <Anchors>
+      <Anchor point="TOPRIGHT" x="-60" y="-240" />
+    </Anchors>
+    <Layers>
+
+      <Layer level="ARTWORK">
+        <Texture parentKey="headerbg" />
+        <Texture parentKey="Background" hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false">
+          <Size y="84" x="210" />
+          <TexCoords up="0" down="1" left="0" right="0.7" />
+          <Anchors>
+            <Anchor point="TOPLEFT" x="-30" y="12"/>
+          </Anchors>
+        </Texture>
+        <Texture parentKey="BackgroundR" hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false">
+          <Size y="84" x="210" />
+          <TexCoords up="0" down="1" left="0.3" right="1" />
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeKey="$parent.Background" />
+            <Anchor point="RIGHT" relativePoint="RIGHT" x="24" />
+          </Anchors>
+        </Texture>
+        <!--<Texture desatuated="true" parentKey="LineGlow" hidden="false" alpha="0" alphaMode="ADD" atlas="OBJFX_LineGlow" useAtlasSize="true">
+          <Anchors>
+            <Anchor point="LEFT" relativeKey="$parent.Background" x="-21" y="18"/>
+          </Anchors>
+        </Texture>
+        <Texture parentKey="SoftGlow" hidden="false" alpha="0" alphaMode="ADD" atlas="OBJFX_Glow" useAtlasSize="true">
+          <Anchors>
+            <Anchor point="CENTER" relativeKey="$parent.Background" relativePoint="LEFT" x="49" y="20"/>
+          </Anchors>
+        </Texture>
+        <Texture parentKey="StarBurst" hidden="false" alpha="0" alphaMode="ADD" atlas="OBJFX_StarBurst" useAtlasSize="true">
+          <Anchors>
+            <Anchor point="CENTER" relativeKey="$parent.SoftGlow" x="29"/>
+          </Anchors>
+        </Texture>
+        <Texture parentKey="LineSheen" hidden="false" alpha="0" alphaMode="ADD" atlas="OBJFX_LineBurst">
+          <Size x="60" y="15"/>
+          <Anchors>
+            <Anchor point="CENTER" relativeKey="$parent.SoftGlow" x="29" y="-13"/>
+          </Anchors>
+        </Texture>-->
+      </Layer>
+      <Layer level="OVERLAY">
+
+      </Layer>
+    </Layers>
+    <Frames>
+
+      <Button name="$parentClose" parentKey="close" inherits="UIPanelCloseButtonNoScripts">
+        <Size x="25" y="20" />
+        <Anchors>
+          <Anchor point="TOPRIGHT" x="-4" y="-2" />
+        </Anchors>
+      </Button>
+
+      <ScrollFrame name="$parentScrollFrame" enableMouseWheel="true" parentKey="scrollArea">
+        <Layers>
+          <Layer level="BACKGROUND">
+            <Texture setAllPoints="true">
+              <Color r="0.15" g=".3" b=".3" a="0" />
+            </Texture>
+          </Layer>
+        </Layers>
+        <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>
+            <Layers>
+              <Layer level="BACKGROUND">
+                <Texture setAllPoints="true">
+                  <Color r="1" g="0" b="0" a=".5" />
+                </Texture>
+              </Layer>
+            </Layers>
+          </Slider>
+          -->
+        </Frames>
+      </ScrollFrame>
+    </Frames>
+  </Frame>
+
+  <Frame name="VeneerObjectiveScroll" parent="VeneerObjectiveWrapperScrollFrame">
+    <Anchors>
+      <Anchor point="TOPLEFT" />
+    </Anchors>
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture setAllPoints="true">
+          <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>
+      <Layer level="BACKGROUND">
+        <Texture name="$parentHeaderBG" parentKey="headerbg">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPLEFT" />
+          </Anchors>
+          <Color r="1" g="1" b="1" a="1" />
+          <Gradient orientation="HORIZONTAL">
+            <MinColor r="0" g="0" b="0" a="0.1" />
+            <MaxColor r="0" g="0" b="0" a="0" />
+          </Gradient>
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <FontString name="$parentHeader" inherits="VeneerFontHighlight" text="OBJ" parentKey="header">
+          <Anchors>
+            <Anchor point="TOPLEFT" />
+          </Anchors>
+        </FontString>
+
+
+      </Layer>
+    </Layers>
+  </Frame>
+
+
+  <Frame name="VeneerTrackerBlock" parent="VeneerObjectiveScroll" virtual="true" enableMouse="true">
+    <Layers>
+      <Layer level="BACKGROUND">
+      </Layer>
+      <Layer level="ARTWORK">
+        <Texture name="$parentTitleBackground" parentKey="titlebg">
+          <Color r="1" g="1" b="1" a="1" />
+          <Anchors>
+            <Anchor point="TOPLEFT" />
+          </Anchors>
+        </Texture>
+        <Texture name="$parentBackground" parentKey="bg">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeKey="$parent.titlebg" />
+          </Anchors>
+          <Color r="1" g="1" b="1" a="1" />
+          <Gradient orientation="HORIZONTAL">
+            <MinColor r="0" g="0" b="0" a=".15" />
+            <MaxColor r="0" g="0" b="0" a=".35" />
+          </Gradient>
+        </Texture>
+        <Texture name="$parentItemTile" parentKey="icon" hidden="true">
+          <Size x="24" y="24" />
+          <Anchors>
+            <Anchor point="TOPRIGHT" x="-1" y="-1" />
+          </Anchors>
+        </Texture>
+        <Texture name="$parentMoneyTile" parentKey="money" hidden="true" />
+      </Layer>
+      <Layer level="HIGHLIGHT">
+        <Texture name="$parentHighLight" parentKey="highlight">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeKey="$parent.titlebg" />
+            <Anchor point="BOTTOM" relativePoint="TOP" relativeKey="$parent.titlebg" x="0" y="-4"/>
+            <Anchor point="RIGHT" relativePoint="RIGHT" />
+          </Anchors>
+          <Color r="1" g="1" b="1" a="1" />
+          <Gradient orientation="VERTICAL">
+            <MaxColor r="1" g="1" b="1" a=".15" />
+            <MinColor r="1" g="1" b="1" a="0" />
+          </Gradient>
+        </Texture>
+        <Texture name="$parentLowLight" parentKey="highlight2">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeKey="$parent.bg" x="0" y="14" />
+            <Anchor point="BOTTOM" relativePoint="BOTTOM" relativeKey="$parent.bg" x="0" y="0"/>
+            <Anchor point="RIGHT" relativePoint="RIGHT" relativeKey="$parent" />
+          </Anchors>
+          <Color r="1" g="1" b="1" a="1" />
+          <Gradient orientation="VERTICAL">
+            <MaxColor r="1" g="1" b="1" a="0" />
+            <MinColor r="1" g="1" b="1" a="0.15" />
+          </Gradient>
+        </Texture>
+      </Layer>
+      <Layer level="OVERLAY">
+        <FontString name="$parentTitle" parentKey="title" inherits="VeneerFontHighlight" justifyH="LEFT" justifyV="MIDDLE">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeKey="$parent.titlebg" />
+          </Anchors>
+        </FontString>
+        <FontString name="$parentLeaderBoard" parentKey="objectives" inherits="VeneerFontNormal" justifyH="LEFT" justifyV="MIDDLE" wordwrap="true">
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeKey="$parent.bg" x="5" y="0" />
+            <Anchor point="RIGHT" relativeKey="$parent" />
+          </Anchors>
+        </FontString>
+      </Layer>
+    </Layers>
+  </Frame>
+
+  <Button name="VeneerItemButton" inherits="SecureActionButtonTemplate">
+    
+  </Button>
+
+  <Script file="ObjectiveTracker.lua" />
+  <Script file="ObjectiveInfo.lua" />
+  <Script file="ObjectiveUI.lua" />
+  <Script file="ObjectiveFrame.lua" />
+  <Script file="ObjectiveEvents.lua" />
+</Ui>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveUI.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,64 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/29/2016 7:07 PM
+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
+
+--------------------------------------------------------------------
+--- Tracker-specific widget functions
+--------------------------------------------------------------------
+
+Tracker.Select = function(self) end
+Tracker.Open = function(self) end
+Tracker.Remove = function(self) end
+Tracker.Report = function(self)
+  print('Stats:', self.numWatched,'items tracked,', self.numBlocks,'blocks assigned.')
+end
+
+Tracker.OnMouseUp = function(self, button)
+  if button == 'LeftButton' then
+    self:Select()
+    mod.UpdateWrapper()
+  elseif button == 'RightButton' then
+    self:Open()
+  end
+  print('|cFFFF8800'..tostring(self:GetName())..':MouseUp()|r ->',self.info.trackingID)
+end
+
+Tracker.OnMouseDown = function(self, button)
+  if button == 'LeftButton' then
+    self:SetStyle('Active')
+  end
+  print(self.info.title)
+end
+
+-----------------------------
+--- AUTO_QUEST
+AutoQuest.name = "Remote Quests"
+AutoQuest.GetNumWatched = GetNumAutoQuestPopUps
+
+-----------------------------
+--- QUEST
+Quest.name = "Quests"
+Quest.Select = function(self)
+  SetSuperTrackedQuestID(self.info.questID)
+end
+Quest.Open = function(self)
+  print('something something quest log')
+  QuestMapFrame_ShowQuestDetails(self.info.questID)
+  ToggleQuestLog()
+end
+
+
+-----------------------------
+--- CHEEVS
+Cheevs.Select = function(self)
+end
+
+Cheevs.Open = function(self)
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RaidBuffTray.lua	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,354 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/20/2016 10:00 PM
+
+local _, A = ...
+local B = A.frame
+local MODULE = 'BuffFrame'
+local M = B:RegisterModule(MODULE)
+local displays = B.displays
+
+local parentAnchor, parentFrame, raidbuffsFrame
+local band, lshift, CreateFrame = bit.band, bit.lshift, CreateFrame
+local raidBuffs = {}
+local raidBuffSymbols = {'St', 'HP', 'AP', 'Ha', 'SP', 'Cr', 'Ma', 'MS', 'V' }
+local missingBuffs = {}
+local playerBuffing, playerCurrentBuff
+local playerBuffs = {}
+local c, ac, frameSize, frameSpacing, framePosition
+local fprint = B.fprint
+local NUM_LE_MISSING_RAID_BUFFS = 0
+local missingBuffsAnchor
+
+
+--- Takes a given icon texture and calls the pre-defined function set
+M.UpdateBuffStyle = function(buff, style, path)
+  local print = fprint()
+  local icon = buff.icon
+  local symbol = buff.symbol
+  path = path or icon.iconPath
+  --print(style,  icon.iconStyle)
+
+  if style ~= buff.iconStyle or path ~= buff.iconPath then
+    print('|cFF0088FFUpdateBuffStyle(|r',  icon:GetName(), style, path)
+    icon.iconStyle = style
+    icon.iconPath = path
+  else
+    --print('|cFF00FF88UpdateBuffStyle(|r',  icon:GetName(), style, path, ') same values, ignore')
+    return
+  end
+  local styleset = B.BuffStyles[style]
+  if not path or path == '' then
+    print('path is nil/empty')
+    icon:SetTexture(1, 1, 1, 1)
+    icon:SetVertexColor(unpack(styleset.Color))
+  else
+    icon:SetTexture(path or icon:GetTexture())
+    icon:SetVertexColor(unpack(styleset.Color))
+  end
+
+  if symbol and symbol.GetText then
+    symbol:SetTextColor(unpack(styleset.TextColor))
+    symbol:SetText(buff.symbolName or 'NaW')
+  end
+
+  icon:SetBlendMode(styleset.SetBlendMode)
+  icon:SetDesaturated(styleset.SetDesaturated)
+end
+
+--- Populates a list of targets needing a buff, fired by a handler
+local PlayerBuffTodo ={}
+M.UpdateBuffStatus = function(aura, filters)
+  if not PlayerBuffStatus[aura] then
+    PlayerBuffStatus[aura] = {}
+  end
+
+
+  print(UnitClass('player'))
+  if IsInGroup() then
+    local numBuffed = 0
+    local partySize = GetNumGroupMembers()
+    local missing = {}
+    for i = 1, partySize do
+      local unit = 'raid'..i
+      if UnitAura(unit, aura, nil, filters) then
+        numBuffed = numBuffed + 1
+      else
+        tinsert(missing, unit)
+      end
+    end
+
+    PlayerBuffTodo[aura] = missing
+
+  end
+end
+
+--- Evaluates buff availability criteria
+-- Uses hard returns to avoid over-iterating conditionals, particularly pet family
+local function IsBuffAvailable(criteria)
+  local available, active = false, false
+  local result
+  for _, test in ipairs(criteria) do
+    if test == true then
+      -- it's a passive effect that is always on
+      return true, true
+    else
+      if c.spec then
+        if not (result and c.spec == B.PlayerSpec) then
+          return false
+        end
+      end
+
+      if c.talent then
+        local talentID, name, texture, selected, available = GetTalentInfoByID(c.talent, GetActiveSpecGroup())
+        if not (result and selected) then
+          return false
+        end
+      end
+
+      if c.petFamily then
+        local lim = min(5, NUM_PET_STABLE_SLOTS) -- to avoid volatile loop condition
+        for p = 1, lim do
+          local hasPet = false
+          local icon, name, level, family, talent = GetStablePetInfo(p)
+          if family == c.petFamily then
+            hasPet = true
+          end
+          if not (result and hasPet) then
+            return false
+          end
+        end
+      end
+
+    end
+  end
+  return true, false
+end
+
+--- events: PLAYER_SPECIALIZATION_CHANGED
+function M:UpdateBuffsTodo (unit)
+  -- buffs vs. auras
+  if unit ~= 'player' then
+    -- look for changes in the GIST manifest and sort them out
+    return
+  end
+
+  local class = UnitClass('player')
+  local spec = GetSpecialization()
+  if not class or
+      not spec or
+      not IsInGroup() or
+      not B.PlayerBuffStatus[class] then
+    -- if just logging in, info won't be available for several seconds
+    -- if not grouped, don't calc
+    -- hide frame
+      B.PlayerBuffsActive = function() return false end
+    return
+  end
+
+  -- verify change
+  if B.PlayerCurrentSpec == spec or B.PlayerClass == class then
+    return
+  end
+  B.PlayerCurrentSpec = spec
+  B.PlayerClass = class
+
+  local test = B.ClassRaidBuffs
+  local buffTypes = {}
+  local auraTypes = {}
+  for i = 1, NUM_LE_RAID_BUFF_TYPES do
+    local name, filters
+    if test[i] and test[i][class] then
+      playerBuffs[i], name, filters = IsBuffAvailable(test[i][class])
+    else
+      playerBuffs[i] = nil
+    end
+
+    if name then
+      B.UpdateBuffStatus(name, filters)
+    end
+  end
+end
+
+-- Called once to setup the ConsolidatedBuffs stencil
+local consolidatedBuffsLoaded
+M.SetConsolidatedBuffs = function()
+  local print = fprint()
+  c = displays.ConsolidatedBuff.conf
+  parentFrame = B.guides[c.Parent][c.Position]
+  raidbuffsFrame = B.anchor.ConsolidatedBuff
+
+  B.SetConfigLayers(raidbuffsFrame)
+  consolidatedBuffsLoaded = true
+  ConsolidatedBuffs:ClearAllPoints()
+  ConsolidatedBuffs:SetAllPoints(parentFrame.icon)
+  if c.Icon then
+    ConsolidatedBuffsIcon:SetAllPoints(parentFrame.icon)
+    ConsolidatedBuffsIcon:SetTexCoord(0.609,0.89,0.215,0.78)
+  else
+    ConsolidatedBuffsIcon:Hide()
+  end
+
+  ConsolidatedBuffsCount:Hide()
+end
+
+local missingTypes = {}
+local raidBuffsInitialized
+M.UpdateRaidBuffs = function()
+  local print = fprint()
+  if not consolidatedBuffsLoaded then
+    M.SetConsolidatedBuffs()
+  end
+
+  if not M.ShowConsolidated or not parentFrame.contains then
+    print('  hiding raid buffs square')
+    if raidBuffsInitialized then
+      for i = 1, 9 do
+        if raidBuffs[i] then
+          raidBuffs[i]:Hide()
+        end
+      end
+      raidBuffsInitialized = nil
+    end
+    if parentFrame then
+      print(c.Parent, c.Position)
+      print('de-flagging parent')
+      parentFrame.contains = nil
+    end
+    raidbuffsFrame:Hide()
+    return
+  end
+
+  local c = B.displays.ConsolidatedBuff.conf
+  if parentFrame and not parentFrame.contains then
+    raidBuffsInitialized = true
+    print('re-flagging parent', parentFrame:GetName())
+    parentFrame.contains = parentFrame
+    B.decors[c.Parent][c.Position]:Hide()
+    raidbuffsFrame:Show()
+
+    -- make sure parent icon is updated
+    local w = c.Size*c.PerRow+c.Spacing*(c.PerRow-1)+c.Border*2
+    parentFrame:SetSize(w, w)
+    parentFrame.icon:SetSize(w - c.Border*2, w - c.Border*2)
+    parentFrame.contains = raidbuffsFrame
+
+    M.UpdateBuffs(c.Parent)
+  end
+
+  -- have to loop again due to tainting restrictions
+  -- could compare the tooltip font object pointers, but that may change
+  local buffStack = GetRaidBuffInfo()
+  print(GetRaidBuffInfo())
+  local guides = B.guides.ConsolidatedBuff
+  local numBuffs = 0
+  local numAvailable = 0
+  local mask = 1
+  if buffStack == nil then
+    return -- discard
+  end
+
+
+  for i = 1, NUM_LE_RAID_BUFF_TYPES do
+    local available = (band(buffStack, mask) > 0)
+    local name, _, icon, start, duration, spellID, slot = GetRaidBuffTrayAuraInfo(i)
+    print(i, name, icon, available)
+
+    raidBuffs[i] = raidBuffs[i] or CreateFrame('Frame', 'VeneerRaidBuff' .. i, raidbuffsFrame, 'VeneerRaidBuffTemplate')
+    local buff = raidBuffs[i]
+    if not raidBuffs[i].stylized then
+      print('  setting style', i)
+      buff.stylized = true
+      buff.symbol:SetText(raidBuffSymbols[i])
+      buff.symbol:SetFont("Fonts\\FRIZQT__.TTF", 10, 'OUTLINE')
+      buff:SetSize(parentFrame.icon:GetWidth()/c.PerRow,parentFrame.icon:GetWidth()/c.PerRow)
+      buff.symbolName = raidBuffSymbols[i]
+
+      buff.icon:SetAllPoints(guides[i].icon)
+      buff:SetAllPoints(guides[i])
+      raidbuffsFrame.Zoom(buff.icon)
+    end
+
+    buff:Show()
+    local buffStyle = 'missing'
+    if name then
+      buff:Show()
+      buff.symbol:Hide()
+      missingTypes[i] = nil
+      numBuffs = numBuffs + 1
+      numAvailable = numAvailable + 1
+      buffStyle = 'active'
+    else
+      buff.symbol:Show()
+      if band(buffStack, mask) > 0 then
+        buffStyle = 'available'
+        numAvailable = numAvailable + 1
+      else
+        buffStyle = 'missing'
+        icon = ''
+      end
+    end
+    mask = lshift(mask, 1)
+
+    M.UpdateBuffStyle(buff, buffStyle, icon)
+  end
+
+  -- todo: filter by castable and suppress for non-overlapping auras
+
+  raidbuffsFrame.label:SetText(numBuffs..'/'..numAvailable)
+  print(parentFrame:GetName(), parentFrame:GetSize())
+
+  if B.ShowMissingBuffs then
+      B.UpdateMissingBuffs()
+  elseif missingBuffsAnchor and missingBuffsAnchor:IsVisible() then
+    for i = 1, NUM_LE_MISSING_RAID_BUFFS do
+      missingBuffs[i]:Hide()
+    end
+  end
+end
+
+B.UpdateMissingBuffs = function()
+  local print = B.fprint()
+  local numMissing = 0
+
+  local firstMissing, lastMissing
+  for i = 1, NUM_LE_RAID_BUFF_TYPES do
+    local name, _, icon, start, duration, spellID, slot = GetRaidBuffTrayAuraInfo(i)
+
+    if not name then
+      numMissing = numMissing + 1
+
+      print('missing buff', i, numMissing)
+      B.UpdateBuffStyle(raidBuffs[i].icon, 'missing', "")
+
+      missingBuffs[numMissing] = missingBuffs[numMissing] or CreateFrame('Button', 'VeneerMissingBuff' .. numMissing, raidbuffsFrame, 'VeneerMissingBuffTemplate')
+
+      local missing = missingBuffs[numMissing]
+
+      missing:Show()
+      missing:SetSize(c.Size*c.PerRow, c.Size)
+      if numMissing == 1 then
+        firstMissing = missing
+      else
+        missing:SetPoint('TOP', lastMissing, 'BOTTOM', 0, -c.Spacing)
+      end
+
+      missing.label:SetText(_G['RAID_BUFF_'.. i])
+      lastMissing = missing
+
+    end
+  end
+
+  if firstMissing then
+    print(firstMissing:GetName(), raidbuffsFrame)
+    firstMissing:SetPoint('TOPRIGHT', raidbuffsFrame.label, 'BOTTOMRIGHT', 0, c.Spacing)
+    missingBuffsAnchor = firstMissing
+  end
+
+  for i = numMissing +1, NUM_LE_MISSING_RAID_BUFFS do
+    missingBuffs[i]:Hide()
+  end
+  NUM_LE_MISSING_RAID_BUFFS = numMissing
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Veneer.toc	Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,13 @@
+## Interface: 60200
+## Title: Veneer
+## Notes: Buff button management
+## Author: Krakyn
+## Version: 1.0-@project-revision@
+## SavedVariables: VeneerData
+## X-Category: Interface Enhancements
+## DefaultState: Enabled
+## LoadOnDemand: 0
+## OptionalDeps: Devian
+Core.xml
+BuffFrame.xml
+ObjectiveTracker.xml
\ No newline at end of file