Quantcast

added a little LDB - this is more for DPS tracking since I don't use a DPS meter anymore.

moonwitch [01-04-15 - 15:33]
added a little LDB - this is more for DPS tracking since I don't use a DPS meter anymore.
Filename
LookInTehCorner.toc
ldb.lua
libs/CallbackHandler-1.0.lua
libs/LibCargoShip-2.1.lua
libs/LibDataBroker-1.1.lua
libs/LibStub.lua
diff --git a/LookInTehCorner.toc b/LookInTehCorner.toc
index a7aa9dc..4885e55 100755
--- a/LookInTehCorner.toc
+++ b/LookInTehCorner.toc
@@ -9,9 +9,14 @@
 ## X-Category: Map
 ## OptionalDeps: Blizzard_TimeManager

+libs\LibStub.lua
+libs\CallbackHandler-1.0.lua
+libs\LibDataBroker-1.1.lua
+libs\LibCargoShip-2.1.lua
+
 core.lua
 clock.lua
-compass.lua
+ldb.lua
 coordinates.lua
 #tooltip.lua
 rightclick.lua
diff --git a/ldb.lua b/ldb.lua
new file mode 100755
index 0000000..23b1857
--- /dev/null
+++ b/ldb.lua
@@ -0,0 +1,15 @@
+------------------------------------------------------------------------
+-- Simple DataBroker frame at the bottom of the minimap
+------------------------------------------------------------------------
+local brokerwidth = Minimap:GetWidth()
+
+local LCS = LibStub("LibCargoShip-2.1")
+local block = LCS:CreateBlock{
+    width = brokerwidth,
+    parent = Minimap,
+    noIcon = false,
+    scale = 1,
+    fontSize = 11
+}
+block:SetDataObject("DPS")
+block:SetPoint("TOP", Minimap, "BOTTOM", 0, 0)
\ No newline at end of file
diff --git a/libs/CallbackHandler-1.0.lua b/libs/CallbackHandler-1.0.lua
new file mode 100755
index 0000000..bc311d9
--- /dev/null
+++ b/libs/CallbackHandler-1.0.lua
@@ -0,0 +1,240 @@
+--[[ $Id: CallbackHandler-1.0.lua 965 2010-08-09 00:47:52Z mikk $ ]]
+local MAJOR, MINOR = "CallbackHandler-1.0", 6
+local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not CallbackHandler then return end -- No upgrade needed
+
+local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
+
+-- Lua APIs
+local tconcat = table.concat
+local assert, error, loadstring = assert, error, loadstring
+local setmetatable, rawset, rawget = setmetatable, rawset, rawget
+local next, select, pairs, type, tostring = next, select, pairs, type, tostring
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: geterrorhandler
+
+local xpcall = xpcall
+
+local function errorhandler(err)
+	return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+	local code = [[
+	local next, xpcall, eh = ...
+
+	local method, ARGS
+	local function call() method(ARGS) end
+
+	local function dispatch(handlers, ...)
+		local index
+		index, method = next(handlers)
+		if not method then return end
+		local OLD_ARGS = ARGS
+		ARGS = ...
+		repeat
+			xpcall(call, eh)
+			index, method = next(handlers, index)
+		until not method
+		ARGS = OLD_ARGS
+	end
+
+	return dispatch
+	]]
+
+	local ARGS, OLD_ARGS = {}, {}
+	for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
+	code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", "))
+	return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+	local dispatcher = CreateDispatcher(argCount)
+	rawset(self, argCount, dispatcher)
+	return dispatcher
+end})
+
+--------------------------------------------------------------------------
+-- CallbackHandler:New
+--
+--   target            - target object to embed public APIs in
+--   RegisterName      - name of the callback registration API, default "RegisterCallback"
+--   UnregisterName    - name of the callback unregistration API, default "UnregisterCallback"
+--   UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
+
+function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
+	-- TODO: Remove this after beta has gone out
+	assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
+
+	RegisterName = RegisterName or "RegisterCallback"
+	UnregisterName = UnregisterName or "UnregisterCallback"
+	if UnregisterAllName==nil then	-- false is used to indicate "don't want this method"
+		UnregisterAllName = "UnregisterAllCallbacks"
+	end
+
+	-- we declare all objects and exported APIs inside this closure to quickly gain access
+	-- to e.g. function names, the "target" parameter, etc
+
+
+	-- Create the registry object
+	local events = setmetatable({}, meta)
+	local registry = { recurse=0, events=events }
+
+	-- registry:Fire() - fires the given event/message into the registry
+	function registry:Fire(eventname, ...)
+		if not rawget(events, eventname) or not next(events[eventname]) then return end
+		local oldrecurse = registry.recurse
+		registry.recurse = oldrecurse + 1
+
+		Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
+
+		registry.recurse = oldrecurse
+
+		if registry.insertQueue and oldrecurse==0 then
+			-- Something in one of our callbacks wanted to register more callbacks; they got queued
+			for eventname,callbacks in pairs(registry.insertQueue) do
+				local first = not rawget(events, eventname) or not next(events[eventname])	-- test for empty before. not test for one member after. that one member may have been overwritten.
+				for self,func in pairs(callbacks) do
+					events[eventname][self] = func
+					-- fire OnUsed callback?
+					if first and registry.OnUsed then
+						registry.OnUsed(registry, target, eventname)
+						first = nil
+					end
+				end
+			end
+			registry.insertQueue = nil
+		end
+	end
+
+	-- Registration of a callback, handles:
+	--   self["method"], leads to self["method"](self, ...)
+	--   self with function ref, leads to functionref(...)
+	--   "addonId" (instead of self) with function ref, leads to functionref(...)
+	-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
+	target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
+		if type(eventname) ~= "string" then
+			error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
+		end
+
+		method = method or eventname
+
+		local first = not rawget(events, eventname) or not next(events[eventname])	-- test for empty before. not test for one member after. that one member may have been overwritten.
+
+		if type(method) ~= "string" and type(method) ~= "function" then
+			error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
+		end
+
+		local regfunc
+
+		if type(method) == "string" then
+			-- self["method"] calling style
+			if type(self) ~= "table" then
+				error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
+			elseif self==target then
+				error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
+			elseif type(self[method]) ~= "function" then
+				error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
+			end
+
+			if select("#",...)>=1 then	-- this is not the same as testing for arg==nil!
+				local arg=select(1,...)
+				regfunc = function(...) self[method](self,arg,...) end
+			else
+				regfunc = function(...) self[method](self,...) end
+			end
+		else
+			-- function ref with self=object or self="addonId" or self=thread
+			if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
+				error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
+			end
+
+			if select("#",...)>=1 then	-- this is not the same as testing for arg==nil!
+				local arg=select(1,...)
+				regfunc = function(...) method(arg,...) end
+			else
+				regfunc = method
+			end
+		end
+
+
+		if events[eventname][self] or registry.recurse<1 then
+		-- if registry.recurse<1 then
+			-- we're overwriting an existing entry, or not currently recursing. just set it.
+			events[eventname][self] = regfunc
+			-- fire OnUsed callback?
+			if registry.OnUsed and first then
+				registry.OnUsed(registry, target, eventname)
+			end
+		else
+			-- we're currently processing a callback in this registry, so delay the registration of this new entry!
+			-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
+			registry.insertQueue = registry.insertQueue or setmetatable({},meta)
+			registry.insertQueue[eventname][self] = regfunc
+		end
+	end
+
+	-- Unregister a callback
+	target[UnregisterName] = function(self, eventname)
+		if not self or self==target then
+			error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
+		end
+		if type(eventname) ~= "string" then
+			error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
+		end
+		if rawget(events, eventname) and events[eventname][self] then
+			events[eventname][self] = nil
+			-- Fire OnUnused callback?
+			if registry.OnUnused and not next(events[eventname]) then
+				registry.OnUnused(registry, target, eventname)
+			end
+		end
+		if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
+			registry.insertQueue[eventname][self] = nil
+		end
+	end
+
+	-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
+	if UnregisterAllName then
+		target[UnregisterAllName] = function(...)
+			if select("#",...)<1 then
+				error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
+			end
+			if select("#",...)==1 and ...==target then
+				error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
+			end
+
+
+			for i=1,select("#",...) do
+				local self = select(i,...)
+				if registry.insertQueue then
+					for eventname, callbacks in pairs(registry.insertQueue) do
+						if callbacks[self] then
+							callbacks[self] = nil
+						end
+					end
+				end
+				for eventname, callbacks in pairs(events) do
+					if callbacks[self] then
+						callbacks[self] = nil
+						-- Fire OnUnused callback?
+						if registry.OnUnused and not next(callbacks) then
+							registry.OnUnused(registry, target, eventname)
+						end
+					end
+				end
+			end
+		end
+	end
+
+	return registry
+end
+
+
+-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
+-- try to upgrade old implicit embeds since the system is selfcontained and
+-- relies on closures to work.
+
diff --git a/libs/LibCargoShip-2.1.lua b/libs/LibCargoShip-2.1.lua
new file mode 100755
index 0000000..9332845
--- /dev/null
+++ b/libs/LibCargoShip-2.1.lua
@@ -0,0 +1,323 @@
+--[[
+Name: LibCargoShip-2.1
+Author: Cargor (xconstruct@gmail.com)
+Dependencies: LibStub, LibDataBroker-1.1
+License: GPL 2
+Description: LibDataBroker block display library
+]]
+
+assert(LibStub, "LibCargoShip-2.1 requires LibStub")
+local LDB = LibStub:GetLibrary("LibDataBroker-1.1")
+local lib, oldminor = LibStub:NewLibrary("LibCargoShip-2.1", 5)
+if(not lib) then return end
+
+local defaults = {__index={
+	parent = UIParent,
+	width = 70,
+	height = 12,
+	scale = 1,
+	alpha = 1,
+
+	fontObject = nil,
+	font = "Fonts\\FRIZQT__.TTF",
+	fontSize = 10,
+	fontStyle = nil,
+	textColor = {1, 1, 1, 1},
+
+	noShadow = nil,
+	shadowX = 1,
+	shadowY = -1,
+
+	noIcon = nil,
+	noText = nil,
+}}
+
+local getDataObject
+local objects = {}
+local updateFunctions = {}
+local assertf = function(cond, ...) return assert(cond, format(...)) end
+local Prototype = CreateFrame"Button"
+local mt_prototype = {__index = Prototype}
+lib.Prototype = {__index = Prototype}
+lib.Objects = objects
+
+--[[*****************************
+	lib:CreateBlock([name] [, options])
+		Creates a new block from the DataObject of the same name
+		The name can either be delivered as arg #1, making the options-table optional,
+		or defined in options.name, where options is passed as arg #1
+*******************************]]
+function lib:CreateBlock(name, opt)
+	if(type(name) == "table" and not opt) then
+		opt, name = name, name.name
+	end
+	opt = setmetatable(opt or {}, defaults)
+
+	local object = setmetatable(CreateFrame("Button", nil, opt.parent), self.Prototype)
+	object:RegisterForClicks("anyUp")
+	object:Hide()
+	object.tagString = opt.tagString
+	object.UpdateFunctions = opt.updateFunctions
+
+	if(opt.style) then
+		opt.style(object, opt)
+	else
+		object:Style(opt)
+	end
+
+	return object, object:SetDataObject(name)
+end
+setmetatable(lib, {__call = lib.CreateBlock})
+
+--[[*****************************
+	lib:Get(dataObject)
+		Return a table of all current blocks using the defined dataObject
+*******************************]]
+function lib:Get(arg1)
+	local name = getDataObject(arg1)
+	return name and objects[name]
+end
+
+--[[*****************************
+	lib:GetFirst(dataObject)
+		Convenience function, get the first block using the dataObject
+*******************************]]
+function lib:GetFirst(arg1)
+	local name = getDataObject(arg1)
+	return name and objects[name] and next(objects[name])
+end
+
+--[[*****************************
+	lib:GetUnused(verbose)
+		Return a table of all unused dataobjects and (optionally) prints them to the chat
+*******************************]]
+local unused
+function lib:GetUnused(verbose)
+	unused = unused or {}
+	if(verbose) then print("Unused LDB objects:") end
+	for name, dataobj in LDB:DataObjectIterator() do
+		unused[name] = not objects[name] and dataobj
+		if(verbose and unused[name]) then
+			print(name)
+		end
+	end
+	return unused
+end
+
+--[[*****************************
+	lib:Embed(target)
+		Embeds the library functions in your own frame/table
+*******************************]]
+function lib:Embed(target)
+	for k,v in pairs(lib) do
+		target[k] = v
+	end
+end
+
+LDB.RegisterCallback(lib, "LibDataBroker_DataObjectCreated", function (event, name, dataobj)
+	if(not objects[name]) then return end
+	for object in pairs(objects[name]) do
+		object:SetDataObject(dataobj)
+	end
+end)
+
+--[[##################################
+	Block Prototype Functions
+###################################]]
+
+Prototype.UpdateFunctions = updateFunctions
+
+--[[*****************************
+	Prototype:SetDataObject([dataObject])
+		Sets the prototype's displayed dataObject
+	Returns:
+		true: dataObject set
+		false: waiting for dataobject to be created
+		nil: no dataObject set
+*******************************]]
+function Prototype:SetDataObject(arg1)
+	if(self.DataObject) then
+		self.DataObject = nil
+		LDB.UnregisterCallback(self, "LibDataBroker_AttributeChanged_"..self.name)
+		objects[self.name][self] = nil
+		self:Hide()
+	end
+
+	if(not arg1) then return end
+
+	local name, dataobj = getDataObject(arg1)
+
+	self.name = name
+	objects[name] = objects[name] or {}
+	objects[name][self] = true
+
+	if(not dataobj) then return false end
+	self.DataObject = dataobj
+	LDB.RegisterCallback(self, "LibDataBroker_AttributeChanged_"..name, self.AttributeChanged, self)
+	self:Update()
+	self:Show()
+	return true
+end
+
+--[[*****************************
+	Prototype:Update("attribute" or nil)
+		Update one or all attributes from the dataobject
+*******************************]]
+function Prototype:Update(attr)
+	if(attr) then
+		if(self.UpdateFunctions and self.UpdateFunctions[attr]) then
+			self.UpdateFunctions[attr](self, attr, self.DataObject)
+		end
+	else
+		self:Update("icon")
+		self:Update("text")
+		self:Update("tooltip")
+		self:Update("OnClick")
+	end
+end
+
+function Prototype:AttributeChanged(event, name, attr, value, dataobj)
+	self:Update(attr, dataobj)
+end
+
+--[[*****************************
+	Prototype:Style(optionsTable)
+		Callback to initialize and style the block
+*******************************]]
+function Prototype:Style(opt)
+	-- Default dimensions
+	self:SetWidth(opt.width)
+	self:SetHeight(opt.height)
+	self:SetScale(opt.scale)
+	self:SetAlpha(opt.alpha)
+
+	if(not opt.noIcon) then	-- Icon left side
+		local icon = self:CreateTexture(nil, "OVERLAY")
+		icon:SetPoint("TOPLEFT")
+		icon:SetPoint("BOTTOMLEFT")
+		icon:SetWidth(opt.height)
+		self.Icon = icon
+	end
+
+	if(not opt.noText) then	-- Text right
+		local text = self:CreateFontString(nil, "OVERLAY", opt.fontObject)
+		if(not opt.fontObject) then
+			text:SetFont(opt.font, opt.fontSize, opt.fontStyle)
+			if(not opt.noShadow) then
+				text:SetShadowOffset(opt.shadowX, opt.shadowY)
+			end
+		end
+		text:SetTextColor(unpack(opt.textColor))
+		text:SetJustifyH("CENTER")
+		if(self.Icon) then	-- Don't overlap the icon!
+			text:SetPoint("TOPLEFT", self.Icon, "TOPRIGHT", 5, 0)
+		else
+			text:SetPoint("TOPLEFT")
+		end
+		text:SetPoint("BOTTOMLEFT")
+		self.Text = text
+	elseif(self.Icon) then
+		self:SetWidth(opt.height)
+	end
+end
+
+--[[##################################
+	Private Object Functions
+###################################]]
+
+getDataObject = function(arg1)
+	if(type(arg1) == "table") then
+		return LDB:GetNameByDataObject(arg1), arg1
+	else
+		return arg1, LDB:GetDataObjectByName(arg1)
+	end
+end
+
+local function getTipAnchor(frame)
+	local x,y = frame:GetCenter()
+	if not x or not y then return "TOPLEFT", "BOTTOMLEFT" end
+	local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or ""
+	local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM"
+	return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf
+end
+
+local function showTooltip(self)
+	local dataobj = self.DataObject
+	local frame = dataobj.tooltip or GameTooltip
+	frame:SetOwner(self, getTipAnchor(self))
+	if(not dataobj.tooltip and dataobj.OnTooltipShow) then
+		dataobj.OnTooltipShow(frame)
+	end
+	frame:Show()
+end
+
+local function hideTooltip(self)
+	local frame = self.DataObject.tooltip or GameTooltip
+	frame:Hide()
+end
+
+local taggedObject
+local function tag(word)
+	return taggedObject.DataObject[word] or taggedObject[word]
+end
+
+--[[##################################
+	Default Update functions
+###################################]]
+
+updateFunctions.icon = function(self, attr, dataobj)
+	if(not self.Icon) then return end
+	self.Icon:SetTexture(dataobj.icon)
+	self:Update("iconCoords")
+	self:Update("iconR")
+end
+updateFunctions.iconCoords = function(self, attr, dataobj)
+	if(dataobj.iconCoords) then
+		self.Icon:SetTexCoord(unpack(dataobj.iconCoords))
+	else
+		self.Icon:SetTexCoord(0, 1, 0, 1)
+	end
+end
+updateFunctions.iconR = function(self, attr, dataobj)
+		self.Icon:SetVertexColor(dataobj.iconR or 1, dataobj.iconG or 1, dataobj.iconB or 1)
+	end
+updateFunctions.text = function(self, attr, dataobj)
+	if(not self.Text) then return end
+	if(self.tagString) then
+		taggedObject = self
+		local text = self.tagString:gsub("%[(%w+)%]", tag)
+		self.Text:SetText(text)
+	else
+		local text = self.useLabel and (dataobj.label or self.name) or ""
+		if(dataobj.text) then
+			if(self.useLabel) then
+				text = text..": "..dataobj.text
+			else
+				text = dataobj.text
+			end
+		end
+		self.Text:SetText(text)
+	end
+	local iconWidth = self.Icon and self.Icon:GetWidth()+5 or 0
+	local textWidth = self.Text:GetWidth() or 0
+	self:SetWidth(iconWidth+textWidth)
+end
+updateFunctions.OnEnter = function(self, attr, dataobj)
+	self:SetScript("OnEnter", (dataobj.tooltip and showTooltip) or dataobj.OnEnter or (dataobj.OnTooltipShow and showTooltip))
+end
+updateFunctions.OnLeave = function(self, attr, dataobj)
+	self:SetScript("OnLeave", (dataobj.tooltip and hideTooltip) or dataobj.OnLeave or (dataobj.OnTooltipShow and hideTooltip))
+end
+updateFunctions.tooltip = function(self, attr, dataobj)
+	self:Update("OnEnter")
+	self:Update("OnLeave")
+end
+updateFunctions.OnClick = function(self, attr, dataobj)
+	self:SetScript("OnClick", dataobj.OnClick)
+end
+
+updateFunctions.value = updateFunctions.text
+updateFunctions.suffix = updateFunctions.text
+updateFunctions.iconG = updateFunctions.iconR
+updateFunctions.iconB = updateFunctions.iconR
+updateFunctions.OnTooltipShow = updateFunctions.tooltip
\ No newline at end of file
diff --git a/libs/LibDataBroker-1.1.lua b/libs/LibDataBroker-1.1.lua
new file mode 100755
index 0000000..f47c0cd
--- /dev/null
+++ b/libs/LibDataBroker-1.1.lua
@@ -0,0 +1,90 @@
+
+assert(LibStub, "LibDataBroker-1.1 requires LibStub")
+assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
+
+local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
+if not lib then return end
+oldminor = oldminor or 0
+
+
+lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
+lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
+local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
+
+if oldminor < 2 then
+	lib.domt = {
+		__metatable = "access denied",
+		__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
+	}
+end
+
+if oldminor < 3 then
+	lib.domt.__newindex = function(self, key, value)
+		if not attributestorage[self] then attributestorage[self] = {} end
+		if attributestorage[self][key] == value then return end
+		attributestorage[self][key] = value
+		local name = namestorage[self]
+		if not name then return end
+		callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
+		callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
+		callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
+		callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
+	end
+end
+
+if oldminor < 2 then
+	function lib:NewDataObject(name, dataobj)
+		if self.proxystorage[name] then return end
+
+		if dataobj then
+			assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
+			self.attributestorage[dataobj] = {}
+			for i,v in pairs(dataobj) do
+				self.attributestorage[dataobj][i] = v
+				dataobj[i] = nil
+			end
+		end
+		dataobj = setmetatable(dataobj or {}, self.domt)
+		self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
+		self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
+		return dataobj
+	end
+end
+
+if oldminor < 1 then
+	function lib:DataObjectIterator()
+		return pairs(self.proxystorage)
+	end
+
+	function lib:GetDataObjectByName(dataobjectname)
+		return self.proxystorage[dataobjectname]
+	end
+
+	function lib:GetNameByDataObject(dataobject)
+		return self.namestorage[dataobject]
+	end
+end
+
+if oldminor < 4 then
+	local next = pairs(attributestorage)
+	function lib:pairs(dataobject_or_name)
+		local t = type(dataobject_or_name)
+		assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
+
+		local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+		assert(attributestorage[dataobj], "Data object not found")
+
+		return next, attributestorage[dataobj], nil
+	end
+
+	local ipairs_iter = ipairs(attributestorage)
+	function lib:ipairs(dataobject_or_name)
+		local t = type(dataobject_or_name)
+		assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
+
+		local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+		assert(attributestorage[dataobj], "Data object not found")
+
+		return ipairs_iter, attributestorage[dataobj], 0
+	end
+end
diff --git a/libs/LibStub.lua b/libs/LibStub.lua
new file mode 100755
index 0000000..0a41ac0
--- /dev/null
+++ b/libs/LibStub.lua
@@ -0,0 +1,30 @@
+-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
+-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+	LibStub = LibStub or {libs = {}, minors = {} }
+	_G[LIBSTUB_MAJOR] = LibStub
+	LibStub.minor = LIBSTUB_MINOR
+
+	function LibStub:NewLibrary(major, minor)
+		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+		minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+
+		local oldminor = self.minors[major]
+		if oldminor and oldminor >= minor then return nil end
+		self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+		return self.libs[major], oldminor
+	end
+
+	function LibStub:GetLibrary(major, silent)
+		if not self.libs[major] and not silent then
+			error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+		end
+		return self.libs[major], self.minors[major]
+	end
+
+	function LibStub:IterateLibraries() return pairs(self.libs) end
+	setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end