New version draft, preparing to publish

Deome [04-06-16 - 17:28]
New version draft, preparing to publish
Filename
Lib/LibAddonMenu-2.0/LICENSE
Lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
Lib/LibAddonMenu-2.0/controls/button.lua
Lib/LibAddonMenu-2.0/controls/checkbox.lua
Lib/LibAddonMenu-2.0/controls/colorpicker.lua
Lib/LibAddonMenu-2.0/controls/custom.lua
Lib/LibAddonMenu-2.0/controls/description.lua
Lib/LibAddonMenu-2.0/controls/dropdown.lua
Lib/LibAddonMenu-2.0/controls/editbox.lua
Lib/LibAddonMenu-2.0/controls/header.lua
Lib/LibAddonMenu-2.0/controls/iconpicker.lua
Lib/LibAddonMenu-2.0/controls/panel.lua
Lib/LibAddonMenu-2.0/controls/separator.dds
Lib/LibAddonMenu-2.0/controls/slider.lua
Lib/LibAddonMenu-2.0/controls/submenu.lua
Lib/LibAddonMenu-2.0/controls/texture.lua
Lib/LibLogos/LibLogos.lua
Lib/LibStub/LibStub.lua
Lib/LibStub/LibStub.txt
Lib/LibStub/LibStub/LibStub.lua
ddDataDaedra.lua
ddDataDaedra.txt
ddDataDaedra.xml
i18n/DE.lua
i18n/EN.lua
i18n/FR.lua
diff --git a/Lib/LibAddonMenu-2.0/LICENSE b/Lib/LibAddonMenu-2.0/LICENSE
new file mode 100644
index 0000000..755f075
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/LICENSE
@@ -0,0 +1,201 @@
+               The Artistic License 2.0
+
+           Copyright (c) 2016 Ryan Lakanen (Seerah)
+
+     Everyone is permitted to copy and distribute verbatim copies
+      of this license document, but changing it is not allowed.
+
+Preamble
+
+This license establishes the terms under which a given free software
+Package may be copied, modified, distributed, and/or redistributed.
+The intent is that the Copyright Holder maintains some artistic
+control over the development of that Package while still keeping the
+Package available as open source and free software.
+
+You are always permitted to make arrangements wholly outside of this
+license directly with the Copyright Holder of a given Package.  If the
+terms of this license do not permit the full use that you propose to
+make of the Package, you should contact the Copyright Holder and seek
+a different licensing arrangement.
+
+Definitions
+
+    "Copyright Holder" means the individual(s) or organization(s)
+    named in the copyright notice for the entire Package.
+
+    "Contributor" means any party that has contributed code or other
+    material to the Package, in accordance with the Copyright Holder's
+    procedures.
+
+    "You" and "your" means any person who would like to copy,
+    distribute, or modify the Package.
+
+    "Package" means the collection of files distributed by the
+    Copyright Holder, and derivatives of that collection and/or of
+    those files. A given Package may consist of either the Standard
+    Version, or a Modified Version.
+
+    "Distribute" means providing a copy of the Package or making it
+    accessible to anyone else, or in the case of a company or
+    organization, to others outside of your company or organization.
+
+    "Distributor Fee" means any fee that you charge for Distributing
+    this Package or providing support for this Package to another
+    party.  It does not mean licensing fees.
+
+    "Standard Version" refers to the Package if it has not been
+    modified, or has been modified only in ways explicitly requested
+    by the Copyright Holder.
+
+    "Modified Version" means the Package, if it has been changed, and
+    such changes were not explicitly requested by the Copyright
+    Holder.
+
+    "Original License" means this Artistic License as Distributed with
+    the Standard Version of the Package, in its current version or as
+    it may be modified by The Perl Foundation in the future.
+
+    "Source" form means the source code, documentation source, and
+    configuration files for the Package.
+
+    "Compiled" form means the compiled bytecode, object code, binary,
+    or any other form resulting from mechanical transformation or
+    translation of the Source form.
+
+
+Permission for Use and Modification Without Distribution
+
+(1)  You are permitted to use the Standard Version and create and use
+Modified Versions for any purpose without restriction, provided that
+you do not Distribute the Modified Version.
+
+
+Permissions for Redistribution of the Standard Version
+
+(2)  You may Distribute verbatim copies of the Source form of the
+Standard Version of this Package in any medium without restriction,
+either gratis or for a Distributor Fee, provided that you duplicate
+all of the original copyright notices and associated disclaimers.  At
+your discretion, such verbatim copies may or may not include a
+Compiled form of the Package.
+
+(3)  You may apply any bug fixes, portability changes, and other
+modifications made available from the Copyright Holder.  The resulting
+Package will still be considered the Standard Version, and as such
+will be subject to the Original License.
+
+
+Distribution of Modified Versions of the Package as Source
+
+(4)  You may Distribute your Modified Version as Source (either gratis
+or for a Distributor Fee, and with or without a Compiled form of the
+Modified Version) provided that you clearly document how it differs
+from the Standard Version, including, but not limited to, documenting
+any non-standard features, executables, or modules, and provided that
+you do at least ONE of the following:
+
+    (a)  make the Modified Version available to the Copyright Holder
+    of the Standard Version, under the Original License, so that the
+    Copyright Holder may include your modifications in the Standard
+    Version.
+
+    (b)  ensure that installation of your Modified Version does not
+    prevent the user installing or running the Standard Version. In
+    addition, the Modified Version must bear a name that is different
+    from the name of the Standard Version.
+
+    (c)  allow anyone who receives a copy of the Modified Version to
+    make the Source form of the Modified Version available to others
+    under
+
+    (i)  the Original License or
+
+    (ii)  a license that permits the licensee to freely copy,
+    modify and redistribute the Modified Version using the same
+    licensing terms that apply to the copy that the licensee
+    received, and requires that the Source form of the Modified
+    Version, and of any works derived from it, be made freely
+    available in that license fees are prohibited but Distributor
+    Fees are allowed.
+
+
+Distribution of Compiled Forms of the Standard Version
+or Modified Versions without the Source
+
+(5)  You may Distribute Compiled forms of the Standard Version without
+the Source, provided that you include complete instructions on how to
+get the Source of the Standard Version.  Such instructions must be
+valid at the time of your distribution.  If these instructions, at any
+time while you are carrying out such distribution, become invalid, you
+must provide new instructions on demand or cease further distribution.
+If you provide valid instructions or cease distribution within thirty
+days after you become aware that the instructions are invalid, then
+you do not forfeit any of your rights under this license.
+
+(6)  You may Distribute a Modified Version in Compiled form without
+the Source, provided that you comply with Section 4 with respect to
+the Source of the Modified Version.
+
+
+Aggregating or Linking the Package
+
+(7)  You may aggregate the Package (either the Standard Version or
+Modified Version) with other packages and Distribute the resulting
+aggregation provided that you do not charge a licensing fee for the
+Package.  Distributor Fees are permitted, and licensing fees for other
+components in the aggregation are permitted. The terms of this license
+apply to the use and Distribution of the Standard or Modified Versions
+as included in the aggregation.
+
+(8) You are permitted to link Modified and Standard Versions with
+other works, to embed the Package in a larger work of your own, or to
+build stand-alone binary or bytecode versions of applications that
+include the Package, and Distribute the result without restriction,
+provided the result does not expose a direct interface to the Package.
+
+
+Items That are Not Considered Part of a Modified Version
+
+(9) Works (including, but not limited to, modules and scripts) that
+merely extend or make use of the Package, do not, by themselves, cause
+the Package to be a Modified Version.  In addition, such works are not
+considered parts of the Package itself, and are not subject to the
+terms of this license.
+
+
+General Provisions
+
+(10)  Any use, modification, and distribution of the Standard or
+Modified Versions is governed by this Artistic License. By using,
+modifying or distributing the Package, you accept this license. Do not
+use, modify, or distribute the Package, if you do not accept this
+license.
+
+(11)  If your Modified Version has been derived from a Modified
+Version made by someone other than you, you are nevertheless required
+to ensure that your Modified Version complies with the requirements of
+this license.
+
+(12)  This license does not grant you the right to use any trademark,
+service mark, tradename, or logo of the Copyright Holder.
+
+(13)  This license includes the non-exclusive, worldwide,
+free-of-charge patent license to make, have made, use, offer to sell,
+sell, import and otherwise transfer the Package with respect to any
+patent claims licensable by the Copyright Holder that are necessarily
+infringed by the Package. If you institute patent litigation
+(including a cross-claim or counterclaim) against any party alleging
+that the Package constitutes direct or contributory patent
+infringement, then this Artistic License to you shall terminate on the
+date that such litigation is filed.
+
+(14)  Disclaimer of Warranty:
+THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
+LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
new file mode 100644
index 0000000..96acfef
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
@@ -0,0 +1,877 @@
+--	LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah)		--
+--	Distributed under The Artistic License 2.0 (see LICENSE)	--
+------------------------------------------------------------------
+
+
+--Register LAM with LibStub
+local MAJOR, MINOR = "LibAddonMenu-2.0", 20
+local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+if not lam then return end	--the same or newer version of this lib is already loaded into memory
+
+local messages = {}
+local MESSAGE_PREFIX = "[LAM2] "
+local function PrintLater(msg)
+	if CHAT_SYSTEM.primaryContainer then
+		d(MESSAGE_PREFIX .. msg)
+	else
+		messages[#messages + 1] = msg
+	end
+end
+
+local function FlushMessages()
+	for i = 1, #messages do
+		d(MESSAGE_PREFIX .. messages[i])
+	end
+	messages = {}
+end
+
+if LAMSettingsPanelCreated and not LAMCompatibilityWarning then
+	PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com")
+	LAMCompatibilityWarning = true
+end
+
+--UPVALUES--
+local wm = WINDOW_MANAGER
+local em = EVENT_MANAGER
+local sm = SCENE_MANAGER
+local cm = CALLBACK_MANAGER
+local tconcat = table.concat
+local tinsert = table.insert
+
+local addonsForList = {}
+local addonToOptionsMap = {}
+local optionsCreated = {}
+lam.widgets = lam.widgets or {}
+local widgets = lam.widgets
+lam.util = {}
+local util = lam.util
+
+local function GetDefaultValue(default)
+	if type(default) == "function" then
+		return default()
+	end
+	return default
+end
+
+local function GetStringFromValue(value)
+	if type(value) == "function" then
+		return value()
+	elseif type(value) == "number" then
+		return GetString(value)
+	end
+	return value
+end
+
+local function CreateBaseControl(parent, controlData, controlName)
+	local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL)
+	control.panel = parent.panel or parent	-- if this is in a submenu, panel is the submenu's parent
+	control.data = controlData
+
+	control.isHalfWidth = controlData.width == "half"
+	local width = 510 -- set default width in case a custom parent object is passed
+	if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end
+	control:SetWidth(width)
+	return control
+end
+
+local MIN_HEIGHT = 26
+local HALF_WIDTH_LINE_SPACING = 2
+local function CreateLabelAndContainerControl(parent, controlData, controlName)
+	local control = CreateBaseControl(parent, controlData, controlName)
+	local width = control:GetWidth()
+
+	local container = wm:CreateControl(nil, control, CT_CONTROL)
+	container:SetDimensions(width / 3, MIN_HEIGHT)
+	control.container = container
+
+	local label = wm:CreateControl(nil, control, CT_LABEL)
+	label:SetFont("ZoFontWinH4")
+	label:SetHeight(MIN_HEIGHT)
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(GetStringFromValue(controlData.name))
+	control.label = label
+
+	if control.isHalfWidth then
+		control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING)
+		label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
+		label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0)
+		container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING)
+	else
+		control:SetDimensions(width, MIN_HEIGHT)
+		container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0)
+		label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
+		label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0)
+	end
+
+	control.data.tooltipText = GetStringFromValue(control.data.tooltip)
+	control:SetMouseEnabled(true)
+	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+	return control
+end
+
+util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead
+util.GetStringFromValue = GetStringFromValue
+util.GetDefaultValue = GetDefaultValue
+util.CreateBaseControl = CreateBaseControl
+util.CreateLabelAndContainerControl = CreateLabelAndContainerControl
+
+local ADDON_DATA_TYPE = 1
+local RESELECTING_DURING_REBUILD = true
+local USER_REQUESTED_OPEN = true
+
+
+--INTERNAL FUNCTION
+--scrolls ZO_ScrollList `list` to move the row corresponding to `data`
+--	into view (does nothing if there is no such row in the list)
+--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for
+--	fading near the list's edges - it avoids the fading area by scrolling
+--	a little further than the ZO function
+local function ScrollDataIntoView(list, data)
+	local targetIndex = data.sortIndex
+	if not targetIndex then return end
+
+	local scrollMin, scrollMax = list.scrollbar:GetMinMax()
+	local scrollTop = list.scrollbar:GetValue()
+	local controlHeight = list.controlHeight
+	local targetMin = controlHeight * (targetIndex - 1) - 64
+	-- subtracting 64 ain't arbitrary, it's the maximum fading height
+	-- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade)
+
+	if targetMin < scrollTop then
+		ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin))
+	else
+		local listHeight = ZO_ScrollList_GetHeight(list)
+		local targetMax = controlHeight * targetIndex + 64 - listHeight
+
+		if targetMax > scrollTop then
+			ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax))
+		end
+	end
+end
+
+
+--INTERNAL FUNCTION
+--constructs a string pattern from the text in `searchEdit` control
+--	* metacharacters are escaped, losing their special meaning
+--	* whitespace matches anything (including empty substring)
+--if there is nothing but whitespace, returns nil
+--otherwise returns a filter function, which takes a `data` table argument
+--	and returns true iff `data.filterText` matches the pattern
+local function GetSearchFilterFunc(searchEdit)
+	local text = searchEdit:GetText():lower()
+	local pattern = text:match("(%S+.-)%s*$")
+
+	if not pattern then -- nothing but whitespace
+		return nil
+	end
+
+	-- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de"
+	pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0")
+
+	-- replace whitespace with "match shortest anything"
+	pattern = pattern:gsub("%s+", ".-")
+
+	return function(data)
+		return data.filterText:lower():find(pattern) ~= nil
+	end
+end
+
+
+--INTERNAL FUNCTION
+--populates `addonList` with entries from `addonsForList`
+--	addonList = ZO_ScrollList control
+--	filter = [optional] function(data)
+local function PopulateAddonList(addonList, filter)
+	local entryList = ZO_ScrollList_GetDataList(addonList)
+	local numEntries = 0
+	local selectedData = nil
+
+	ZO_ScrollList_Clear(addonList)
+
+	for i, data in ipairs(addonsForList) do
+		if not filter or filter(data) then
+			local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data)
+			numEntries = numEntries + 1
+			data.sortIndex = numEntries
+			entryList[numEntries] = dataEntry
+			-- select the first panel passing the filter, or the currently
+			-- shown panel, but only if it passes the filter as well
+			if selectedData == nil or data.panel == lam.currentAddonPanel then
+				selectedData = data
+			end
+		else
+			data.sortIndex = nil
+		end
+	end
+
+	ZO_ScrollList_Commit(addonList)
+
+	if selectedData then
+		if selectedData.panel == lam.currentAddonPanel then
+			ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD)
+		else
+			ZO_ScrollList_SelectData(addonList, selectedData, nil)
+		end
+		ScrollDataIntoView(addonList, selectedData)
+	end
+end
+
+
+--METHOD: REGISTER WIDGET--
+--each widget has its version checked before loading,
+--so we only have the most recent one in memory
+--Usage:
+--	widgetType = "string"; the type of widget being registered
+--	widgetVersion = integer; the widget's version number
+LAMCreateControl = LAMCreateControl or {}
+local lamcc = LAMCreateControl
+
+function lam:RegisterWidget(widgetType, widgetVersion)
+	if widgets[widgetType] and widgets[widgetType] >= widgetVersion then
+		return false
+	else
+		widgets[widgetType] = widgetVersion
+		return true
+	end
+end
+
+-- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done
+local function OpenCurrentPanel()
+	if(lam.currentAddonPanel and not lam.currentPanelOpened) then
+		lam.currentPanelOpened = true
+		cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel)
+	end
+end
+
+-- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done
+local function CloseCurrentPanel()
+	if(lam.currentAddonPanel and lam.currentPanelOpened) then
+		lam.currentPanelOpened = false
+		cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel)
+	end
+end
+
+--METHOD: OPEN TO ADDON PANEL--
+--opens to a specific addon's option panel
+--Usage:
+--	panel = userdata; the panel returned by the :RegisterOptionsPanel method
+local locSettings = GetString(SI_GAME_MENU_SETTINGS)
+function lam:OpenToPanel(panel)
+
+	-- find and select the panel's row in addon list
+
+	local addonList = lam.addonList
+	local selectedData = nil
+
+	for _, addonData in ipairs(addonsForList) do
+		if addonData.panel == panel then
+			selectedData = addonData
+			ScrollDataIntoView(addonList, selectedData)
+			break
+		end
+	end
+
+	ZO_ScrollList_SelectData(addonList, selectedData)
+	ZO_ScrollList_RefreshVisible(addonList, selectedData)
+
+	local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit")
+	srchEdit:Clear()
+
+	-- note that ZO_ScrollList doesn't require `selectedData` to be actually
+	-- present in the list, and that the list will only be populated once LAM
+	-- "Addon Settings" menu entry is selected for the first time
+
+	local function openAddonSettingsMenu()
+		local gameMenu = ZO_GameMenu_InGame.gameMenu
+		local settingsMenu = gameMenu.headerControls[locSettings]
+
+		if settingsMenu then -- an instance of ZO_TreeNode
+			local children = settingsMenu:GetChildren()
+			for i = 1, (children and #children or 0) do
+				local childNode = children[i]
+				local data = childNode:GetData()
+				if data and data.id == lam.panelId then
+					-- found LAM "Addon Settings" node, yay!
+					childNode:GetTree():SelectNode(childNode)
+					break
+				end
+			end
+		end
+	end
+
+	if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then
+		openAddonSettingsMenu()
+	else
+		sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu)
+		sm:Show("gameMenuInGame")
+	end
+end
+
+local TwinOptionsContainer_Index = 0
+local function TwinOptionsContainer(parent, leftWidget, rightWidget)
+	TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1
+	local cParent = parent.scroll or parent
+	local panel = parent.panel or cParent
+	local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index),
+										cParent, CT_CONTROL)
+	container:SetResizeToFitDescendents(true)
+	container:SetAnchor(select(2, leftWidget:GetAnchor(0) ))
+
+	leftWidget:ClearAnchors()
+	leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT)
+	rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0)
+
+	leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls
+	rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 )
+
+	leftWidget:SetParent(container)
+	rightWidget:SetParent(container)
+
+	container.data = {type = "container"}
+	container.panel = panel
+	return container
+end
+
+--INTERNAL FUNCTION
+--creates controls when options panel is first shown
+--controls anchoring of these controls in the panel
+local function CreateOptionsControls(panel)
+	local addonID = panel:GetName()
+	local optionsTable = addonToOptionsMap[addonID]
+
+	if optionsTable then
+		local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf)
+			local widget
+			local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end)
+			if not status then
+				return err or true, offsetY, anchorTarget, wasHalf
+			else
+				local isHalf = (widgetData.width == "half")
+				if not anchorTarget then -- the first widget in a panel is just placed in the top left corner
+					widget:SetAnchor(TOPLEFT)
+					anchorTarget = widget
+				elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side
+					widget.lineControl = anchorTarget
+					isHalf = false
+					offsetY = 0
+					anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget)
+				else -- otherwise we just put it below the previous one normally
+					widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15)
+					offsetY = 0
+					anchorTarget = widget
+				end
+				return false, offsetY, anchorTarget, isHalf
+			end
+		end
+
+		local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20
+		local fifo = {}
+		local anchorOffset, lastAddedControl, wasHalf
+		local CreateWidgetsInPanel, err
+
+		local function PrepareForNextPanel()
+			anchorOffset, lastAddedControl, wasHalf = 0, nil, false
+		end
+
+		local function SetupCreationCalls(parent, widgetDataTable)
+			fifo[#fifo + 1] = PrepareForNextPanel
+			local count = #widgetDataTable
+			for i = 1, count, THROTTLE_COUNT do
+				fifo[#fifo + 1] = function()
+					CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count))
+				end
+			end
+			return count ~= NonContiguousCount(widgetDataTable)
+		end
+
+		CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex)
+			for i=startIndex,endIndex do
+				local widgetData = widgetDataTable[i]
+				if not widgetData then
+					PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".")
+				else
+					local widgetType = widgetData.type
+					local offsetX = 0
+					local isSubmenu = (widgetType == "submenu")
+					if isSubmenu then
+						wasHalf = false
+						offsetX = 5
+					end
+
+					err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf)
+					if err then
+						PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, widgetData.name or "unnamed", addonID))
+					end
+
+					if isSubmenu then
+						if SetupCreationCalls(lastAddedControl, widgetData.controls) then
+							PrintLater(("The sub menu '%s' of %s is missing some entries."):format(widgetData.name or "unnamed", addonID))
+						end
+					end
+				end
+			end
+		end
+
+		local function DoCreateSettings()
+			if #fifo > 0 then
+				local nextCall = table.remove(fifo, 1)
+				nextCall()
+				if(nextCall == PrepareForNextPanel) then
+					DoCreateSettings()
+				else
+					zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT)
+				end
+			else
+				optionsCreated[addonID] = true
+				cm:FireCallbacks("LAM-PanelControlsCreated", panel)
+				OpenCurrentPanel()
+			end
+		end
+
+		if SetupCreationCalls(panel, optionsTable) then
+			PrintLater(("The settings menu of %s is missing some entries."):format(addonID))
+		end
+		DoCreateSettings()
+	else
+		optionsCreated[addonID] = true
+		cm:FireCallbacks("LAM-PanelControlsCreated", panel)
+		OpenCurrentPanel()
+	end
+end
+
+
+--INTERNAL FUNCTION
+--handles switching between panels
+local function ToggleAddonPanels(panel)	--called in OnShow of newly shown panel
+	local currentlySelected = lam.currentAddonPanel
+	if currentlySelected and currentlySelected ~= panel then
+		currentlySelected:SetHidden(true)
+		CloseCurrentPanel()
+	end
+	lam.currentAddonPanel = panel
+
+	-- refresh visible rows to reflect panel IsHidden status
+	ZO_ScrollList_RefreshVisible(lam.addonList)
+
+	if not optionsCreated[panel:GetName()] then	--if this is the first time opening this panel, create these options
+		CreateOptionsControls(panel)
+	else
+		OpenCurrentPanel()
+	end
+
+	cm:FireCallbacks("LAM-RefreshPanel", panel)
+end
+
+local CheckSafetyAndInitialize
+
+--METHOD: REGISTER ADDON PANEL
+--registers your addon with LibAddonMenu and creates a panel
+--Usage:
+--	addonID = "string"; unique ID which will be the global name of your panel
+--	panelData = table; data object for your panel - see controls\panel.lua
+function lam:RegisterAddonPanel(addonID, panelData)
+	CheckSafetyAndInitialize(addonID)
+	local container = lam:GetAddonPanelContainer()
+	local panel = lamcc.panel(container, panelData, addonID)	--addonID==global name of panel
+	panel:SetHidden(true)
+	panel:SetAnchorFill(container)
+	panel:SetHandler("OnShow", ToggleAddonPanels)
+
+	local function stripMarkup(str)
+		return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "")
+	end
+
+	local filterParts = {panelData.name, nil, nil}
+	-- append keywords and author separately, the may be nil
+	filterParts[#filterParts + 1] = panelData.keywords
+	filterParts[#filterParts + 1] = panelData.author
+
+	local addonData = {
+		panel = panel,
+		name = stripMarkup(panelData.name),
+		filterText = stripMarkup(tconcat(filterParts, "\t")):lower(),
+	}
+
+	tinsert(addonsForList, addonData)
+
+	if panelData.slashCommand then
+		SLASH_COMMANDS[panelData.slashCommand] = function()
+			lam:OpenToPanel(panel)
+		end
+	end
+
+	return panel	--return for authors creating options manually
+end
+
+
+--METHOD: REGISTER OPTION CONTROLS
+--registers the options you want shown for your addon
+--these are stored in a table where each key-value pair is the order
+--of the options in the panel and the data for that control, respectively
+--see exampleoptions.lua for an example
+--see controls\<widget>.lua for each widget type
+--Usage:
+--	addonID = "string"; the same string passed to :RegisterAddonPanel
+--	optionsTable = table; the table containing all of the options controls and their data
+function lam:RegisterOptionControls(addonID, optionsTable)	--optionsTable = {sliderData, buttonData, etc}
+	addonToOptionsMap[addonID] = optionsTable
+end
+
+
+--INTERNAL FUNCTION
+--creates LAM's Addon Settings entry in ZO_GameMenu
+local function CreateAddonSettingsMenuEntry()
+	--Russian for TERAB1T's RuESO addon, which creates an "ru" locale
+	--game font does not support Cyrillic, so they are using custom fonts + extended latin charset
+	--Spanish provided by Luisen75 for their translation project
+	local controlPanelNames = {
+		en = "Addon Settings",
+		fr = "Extensions",
+		de = "Erweiterungen",
+		ru = "Îacòpoéêè äoïoìîeîèé",
+		es = "Configura Addons",
+	}
+
+	local panelData = {
+		id = KEYBOARD_OPTIONS.currentPanelId,
+		name = controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"],
+	}
+
+	KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1
+	KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name
+
+	lam.panelId = panelData.id
+
+	local addonListSorted = false
+
+	function panelData.callback()
+		sm:AddFragment(lam:GetAddonSettingsFragment())
+		KEYBOARD_OPTIONS:ChangePanels(lam.panelId)
+
+		local title = LAMAddonSettingsWindow:GetNamedChild("Title")
+		title:SetText(panelData.name)
+
+		if not addonListSorted and #addonsForList > 0 then
+			local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit")
+			--we're about to show our list for the first time - let's sort it
+			table.sort(addonsForList, function(a, b) return a.name < b.name end)
+			PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit))
+			addonListSorted = true
+		end
+	end
+
+	function panelData.unselectedCallback()
+		sm:RemoveFragment(lam:GetAddonSettingsFragment())
+		if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011
+			SetCameraOptionsPreviewModeEnabled(false)
+		end
+	end
+
+	ZO_GameMenu_AddSettingPanel(panelData)
+end
+
+
+--INTERNAL FUNCTION
+--creates the left-hand menu in LAM's window
+local function CreateAddonList(name, parent)
+	local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList")
+
+	local function addonListRow_OnMouseDown(control, button)
+		if button == 1 then
+			local data = ZO_ScrollList_GetData(control)
+			ZO_ScrollList_SelectData(addonList, data, control)
+		end
+	end
+
+	local function addonListRow_OnMouseEnter(control)
+		ZO_ScrollList_MouseEnter(addonList, control)
+	end
+
+	local function addonListRow_OnMouseExit(control)
+		ZO_ScrollList_MouseExit(addonList, control)
+	end
+
+	local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild)
+		if not reselectingDuringRebuild then
+			if previouslySelectedData then
+				previouslySelectedData.panel:SetHidden(true)
+			end
+			if selectedData then
+				selectedData.panel:SetHidden(false)
+				PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION)
+			end
+		end
+	end
+
+	local function addonListRow_Setup(control, data)
+		control:SetText(data.name)
+		control:SetSelected(not data.panel:IsHidden())
+	end
+
+	ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup)
+	-- I don't know how to make highlights clear properly; they often
+	-- get stuck and after a while the list is full of highlighted rows
+	--ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight")
+	ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select)
+
+	local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE)
+	local addonListRow_CreateRaw = addonDataType.pool.m_Factory
+
+	local function addonListRow_Create(pool)
+		local control = addonListRow_CreateRaw(pool)
+		control:SetHandler("OnMouseDown", addonListRow_OnMouseDown)
+		--control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter)
+		--control:SetHandler("OnMouseExit", addonListRow_OnMouseExit)
+		control:SetHeight(28)
+		control:SetFont("ZoFontHeader")
+		control:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
+		control:SetVerticalAlignment(TEXT_ALIGN_CENTER)
+		control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+		return control
+	end
+
+	addonDataType.pool.m_Factory = addonListRow_Create
+
+	return addonList
+end
+
+
+--INTERNAL FUNCTION
+local function CreateSearchFilterBox(name, parent)
+	local boxControl = wm:CreateControl(name, parent, CT_CONTROL)
+
+	local srchButton =  wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON)
+	srchButton:SetDimensions(32, 32)
+	srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0)
+	srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds")
+	srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds")
+	srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds")
+
+	local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit")
+	srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1)
+	srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1)
+	srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
+
+	local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP)
+	srchBg:SetAnchorFill()
+	srchBg:SetAlpha(0)
+	srchBg:SetCenterColor(0, 0, 0, 0.5)
+	srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA())
+	srchBg:SetEdgeTexture("", 1, 1, 0, 0)
+
+	-- search backdrop should appear whenever you hover over either
+	-- the magnifying glass button or the edit field (which is only
+	-- visible when it contains some text), and also while the edit
+	-- field has keyboard focus
+
+	local srchActive = false
+	local srchHover = false
+
+	local function srchBgUpdateAlpha()
+		if srchActive or srchEdit:HasFocus() then
+			srchBg:SetAlpha(srchHover and 0.8 or 0.6)
+		else
+			srchBg:SetAlpha(srchHover and 0.6 or 0.0)
+		end
+	end
+
+	local function srchMouseEnter(control)
+		srchHover = true
+		srchBgUpdateAlpha()
+	end
+
+	local function srchMouseExit(control)
+		srchHover = false
+		srchBgUpdateAlpha()
+	end
+
+	boxControl:SetMouseEnabled(true)
+	boxControl:SetHitInsets(1, 1, -1, -1)
+	boxControl:SetHandler("OnMouseEnter", srchMouseEnter)
+	boxControl:SetHandler("OnMouseExit", srchMouseExit)
+
+	srchButton:SetHandler("OnMouseEnter", srchMouseEnter)
+	srchButton:SetHandler("OnMouseExit", srchMouseExit)
+
+	local focusLostTime = 0
+
+	srchButton:SetHandler("OnClicked", function(self)
+		srchEdit:Clear()
+		if GetFrameTimeMilliseconds() - focusLostTime < 100 then
+			-- re-focus the edit box if it lost focus due to this
+			-- button click (note that this handler may run a few
+			-- frames later)
+			srchEdit:TakeFocus()
+		end
+	end)
+
+	srchEdit:SetHandler("OnMouseEnter", srchMouseEnter)
+	srchEdit:SetHandler("OnMouseExit", srchMouseExit)
+	srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha)
+
+	srchEdit:SetHandler("OnFocusLost", function()
+		focusLostTime = GetFrameTimeMilliseconds()
+		srchBgUpdateAlpha()
+	end)
+
+	srchEdit:SetHandler("OnEscape", function(self)
+		self:Clear()
+		self:LoseFocus()
+	end)
+
+	srchEdit:SetHandler("OnTextChanged", function(self)
+		local filterFunc = GetSearchFilterFunc(self)
+		if filterFunc then
+			srchActive = true
+			srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA())
+			srchButton:SetState(BSTATE_PRESSED)
+		else
+			srchActive = false
+			srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA())
+			srchButton:SetState(BSTATE_NORMAL)
+		end
+		srchBgUpdateAlpha()
+		PopulateAddonList(lam.addonList, filterFunc)
+		PlaySound(SOUNDS.SPINNER_DOWN)
+	end)
+
+	return boxControl
+end
+
+
+--INTERNAL FUNCTION
+--creates LAM's Addon Settings top-level window
+local function CreateAddonSettingsWindow()
+	local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow")
+	tlw:SetHidden(true)
+	tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow
+
+	ZO_ReanchorControlForLeftSidePanel(tlw)
+
+	-- create black background for the window (mimic ZO_RightFootPrintBackground)
+
+	local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE)
+	bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds")
+	bgLeft:SetDimensions(1024, 1024)
+	bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT)
+	bgLeft:SetDrawLayer(DL_BACKGROUND)
+	bgLeft:SetExcludeFromResizeToFitExtents(true)
+
+	local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE)
+	bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds")
+	bgRight:SetDimensions(64, 1024)
+	bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT)
+	bgRight:SetDrawLayer(DL_BACKGROUND)
+	bgRight:SetExcludeFromResizeToFitExtents(true)
+
+	-- create gray background for addon list (mimic ZO_TreeUnderlay)
+
+	local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE)
+	underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds")
+	underlayLeft:SetDimensions(256, 1024)
+	underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT)
+	underlayLeft:SetDrawLayer(DL_BACKGROUND)
+	underlayLeft:SetExcludeFromResizeToFitExtents(true)
+
+	local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE)
+	underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds")
+	underlayRight:SetDimensions(128, 1024)
+	underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT)
+	underlayRight:SetDrawLayer(DL_BACKGROUND)
+	underlayRight:SetExcludeFromResizeToFitExtents(true)
+
+	-- create title bar (mimic ZO_OptionsWindow)
+
+	local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL)
+	title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70)
+	title:SetFont("ZoFontWinH1")
+	title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE)
+
+	local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider")
+	divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108)
+
+	-- create search filter box
+
+	local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw)
+	srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120)
+	srchBox:SetDimensions(260, 30)
+
+	-- create scrollable addon list
+
+	local addonList = CreateAddonList("$(parent)AddonList", tlw)
+	addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160)
+	addonList:SetDimensions(285, 665)
+
+	lam.addonList = addonList -- for easy access from elsewhere
+
+	-- create container for option panels
+
+	local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL)
+	panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120)
+	panelContainer:SetDimensions(645, 675)
+
+	return tlw
+end
+
+
+--INITIALIZING
+local safeToInitialize = false
+local hasInitialized = false
+
+local eventHandle = table.concat({MAJOR, MINOR}, "r")
+local function OnLoad(_, addonName)
+	-- wait for the first loaded event
+	em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED)
+	safeToInitialize = true
+end
+em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad)
+
+local function OnActivated(_, addonName)
+	em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED)
+	FlushMessages()
+
+	-- a little something for 4/1. Please keep it a secret ;-) The code was minified with https://mothereff.in/lua-minifier and the original code can be found at https://gist.github.com/sirinsidiator/6f8863ff66c9919dfe01
+	if GetDate()%1000~=401 then ZO_Ingame_SavedVariables["LAM"]=nil;return end;local a,b=pcall(error,"")local c=b:match("user:/AddOns/(.*)LibAddonMenu.-.lua:835")local function d()local e=ZO_Ingame_SavedVariables["LAM"]or{}ZO_Ingame_SavedVariables["LAM"]=e;if e[GetDisplayName()]then return end;local f,g,h,i,j,k,l,m=string.rep,string.format,math.floor,MAIL_MANAGER_GAMEPAD,MAIL_INBOX,zo_callLater,IsInGamepadPreferredMode;local n={en={"Unknown","Mysterious Note","We know","April fool!\nThe addon community wishes you a happy April Fools' Day!",0},de={"Unbekannt","Geheimnisvolle Notiz","Wir wissen Bescheid","April, April!\nEinen guten 1. April wünscht euch eure Addon Gemeinschaft!",7},fr={"Inconnu","Note mystérieuse","Nous savons tout","Poisson d'avril!\nLes développeurs d'addons vous souhaitent un joyeux premier avril!",6}}local o=n[GetCVar("language.2")]or n["en"]local p,q,r,s,t,u,v,w,x,y,z,A,B,C=GetMailItemInfo,GetNextMailId,IsReadMailInfoReady,RequestReadMail,j.GetMailData,ReadMail,DeleteMail,GetNumUnreadMail,i.inbox,GetMailAttachmentInfo,GetAttachedItemLink,ItemTooltip.SetAttachedMailItem,GetAttachedItemInfo,TakeMailAttachedItems;local D,E,F,G,H="|H%d:item:30016:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0|h|h",c.."controls/separator.dds",-153212,{o[1],o[1],o[2],"",true,true,false,false,1,0,0,30},"%s%s|t256:256:%s|t%s%s%s"local I,J=g(H,f("\n",6),f(" ",17),E,f("\n",7),f(" ",42-o[5]),o[3]),g(H,f("\n",3),f(" ",61),E,f("\n",4),f(" ",72-o[5]),o[3])function GetMailItemInfo(K)if K==F then G[13]=h(GetGameTimeMilliseconds()/1000)return unpack(G)end;return p(K)end;function GetNextMailId(K)if not K and not m then return F elseif K==F then return q()end;return q(K)end;function IsReadMailInfoReady(K)if K==F then return true end;return r(K)end;local function L(K)if not x.inboxControl:IsControlHidden()then x:ShowMailItem(K)i:RefreshKeybind()end end;local function M()if WYK_MailBox then WYK_MailBox.ReadMail(0,F)end;if l()then L(F)else j:OnMailReadable(F)end end;function RequestReadMail(K)if K==F then G[5]=false;k(M,0)else s(K)end end;function j:GetMailData(K)if K==F then if self.masterList then for N=1,#self.masterList do local O=self.masterList[N]if O.mailId==K then return O end end end else return t(self,K)end end;function ReadMail(K)if K==F then return l()and J or I end;return u(K)end;function DeleteMail(K,P)if K==F then m=true;j:OnMailRemoved(K)i:RefreshHeader()x:RefreshMailList()e[GetDisplayName()]=true else v(K,P)end end;function GetNumUnreadMail()local Q=w()if G[5]then return Q+1 end;return Q end;function GetMailAttachmentInfo(K)if K==F and G[9]>0 then return 1,0,0 end;return y(K)end;function GetAttachedItemLink(K,R,S)if K==F and G[9]>0 then return g(D,S or 0)end;return z(K,R,S)end;function ItemTooltip:SetAttachedMailItem(K,T)if K==F and G[9]>0 then self:SetLink(GetAttachedItemLink(K,T))else A(self,K,T)end end;function GetAttachedItemInfo(K,R)if K==F and G[9]>0 then local U,V,W,X,Y=GetItemLinkInfo(g(D,1))return U,1,nil,V,W,X,Y,2 end;return B(K,R)end;function TakeMailAttachedItems(K)if K==F then LORE_READER:Show(o[1],o[4],4,false,"loreLibrary")SCENE_MANAGER:Show("loreReaderInteraction")G[9]=0;j:OnTakeAttachedItemSuccess(K)else C(K)end end;CHAT_SYSTEM:OnNumUnreadMailChanged(GetNumUnreadMail())end;pcall(d)
+end
+em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated)
+
+function CheckSafetyAndInitialize(addonID)
+	if not safeToInitialize then
+		local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID)
+		PrintLater(msg)
+	end
+	if not hasInitialized then
+		hasInitialized = true
+	end
+end
+
+
+--TODO documentation
+function lam:GetAddonPanelContainer()
+	local fragment = lam:GetAddonSettingsFragment()
+	local window = fragment:GetControl()
+	return window:GetNamedChild("PanelContainer")
+end
+
+
+--TODO documentation
+function lam:GetAddonSettingsFragment()
+	assert(hasInitialized or safeToInitialize)
+	if not LAMAddonSettingsFragment then
+		local window = CreateAddonSettingsWindow()
+		LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100)
+		LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState)
+			if(newState == SCENE_FRAGMENT_SHOWN) then
+				OpenCurrentPanel()
+			elseif(newState == SCENE_FRAGMENT_HIDDEN) then
+				CloseCurrentPanel()
+			end
+		end)
+		CreateAddonSettingsMenuEntry()
+	end
+	return LAMAddonSettingsFragment
+end
+
+
+-- vi: noexpandtab
diff --git a/Lib/LibAddonMenu-2.0/controls/button.lua b/Lib/LibAddonMenu-2.0/controls/button.lua
new file mode 100644
index 0000000..f588703
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/button.lua
@@ -0,0 +1,89 @@
+--[[buttonData = {
+	type = "button",
+	name = "My Button", -- string id or function returning a string
+	func = function() end,
+	tooltip = "Button's tooltip text.", -- string id or function returning a string (optional)
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	icon = "icon\\path.dds",	--(optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	reference = "MyAddonButton",	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 9
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("button", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+
+local function UpdateDisabled(control)
+	local disable
+	if type(control.data.disabled) == "function" then
+		disable = control.data.disabled()
+	else
+		disable = control.data.disabled
+	end
+
+	control.button:SetEnabled(not disable)
+end
+
+
+--controlName is optional
+local MIN_HEIGHT = 28 -- default_button height
+local HALF_WIDTH_LINE_SPACING = 2
+function LAMCreateControl.button(parent, buttonData, controlName)
+	local control = LAM.util.CreateBaseControl(parent, buttonData, controlName)
+	control:SetMouseEnabled(true)
+
+	local width = control:GetWidth()
+	if control.isHalfWidth then
+		control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING)
+	else
+		control:SetDimensions(width, MIN_HEIGHT)
+	end
+
+	if buttonData.icon then
+		control.button = wm:CreateControl(nil, control, CT_BUTTON)
+		control.button:SetDimensions(26, 26)
+		control.button:SetNormalTexture(buttonData.icon)
+		control.button:SetPressedOffset(2, 2)
+	else
+		--control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton")
+		control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton")
+		control.button:SetWidth(width / 3)
+		control.button:SetText(LAM.util.GetStringFromValue(buttonData.name))
+	end
+	local button = control.button
+	button:SetAnchor(control.isHalfWidth and CENTER or RIGHT)
+	button:SetClickSound("Click")
+	button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)}
+	button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+	button:SetHandler("OnClicked", function(self, ...)
+		buttonData.func(self, ...)
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	end)
+
+	if buttonData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0)
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.warning)}
+	end
+
+	if buttonData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+
+		--this is here because buttons don't have an UpdateValue method
+		if control.panel.data.registerForRefresh then	--if our parent window wants to refresh controls, then add this to the list
+			tinsert(control.panel.controlsToRefresh, control)
+		end
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/checkbox.lua b/Lib/LibAddonMenu-2.0/controls/checkbox.lua
new file mode 100644
index 0000000..51d9fd7
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/checkbox.lua
@@ -0,0 +1,144 @@
+--[[checkboxData = {
+	type = "checkbox",
+	name = "My Checkbox", -- or string id or function returning a string
+	getFunc = function() return db.var end,
+	setFunc = function(value) db.var = value doStuff() end,
+	tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional)
+	width = "full", -- or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.", -- or string id or function returning a string (optional)
+	default = defaults.var,	-- a boolean or function that returns a boolean (optional)
+	reference = "MyAddonCheckbox", -- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 11
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("checkbox", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+--label
+local enabledColor = ZO_DEFAULT_ENABLED_COLOR
+local enabledHLcolor = ZO_HIGHLIGHT_TEXT
+local disabledColor = ZO_DEFAULT_DISABLED_COLOR
+local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR
+--checkbox
+local checkboxColor = ZO_NORMAL_TEXT
+local checkboxHLcolor = ZO_HIGHLIGHT_TEXT
+
+
+local function UpdateDisabled(control)
+	local disable
+	if type(control.data.disabled) == "function" then
+		disable = control.data.disabled()
+	else
+		disable = control.data.disabled
+	end
+
+	control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA())
+	control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA())
+	--control:SetMouseEnabled(not disable)
+	--control:SetMouseEnabled(true)
+
+	control.isDisabled = disable
+end
+
+local function ToggleCheckbox(control)
+	if control.value then
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+		control.checkbox:SetText(control.checkedText)
+	else
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+		control.checkbox:SetText(control.uncheckedText)
+	end
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = LAM.util.GetDefaultValue(control.data.default)
+		control.data.setFunc(value)
+	elseif value ~= nil then	--our value could be false
+		control.data.setFunc(value)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		value = control.data.getFunc()
+	end
+	control.value = value
+
+	ToggleCheckbox(control)
+end
+
+local function OnMouseEnter(control)
+	ZO_Options_OnMouseEnter(control)
+
+	if control.isDisabled then return end
+
+	local label = control.label
+	if control.value then
+		label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
+	else
+		label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
+	end
+	control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
+end
+
+local function OnMouseExit(control)
+	ZO_Options_OnMouseExit(control)
+
+	if control.isDisabled then return end
+
+	local label = control.label
+	if control.value then
+		label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	else
+		label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	end
+	control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
+end
+
+--controlName is optional
+function LAMCreateControl.checkbox(parent, checkboxData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName)
+	control:SetHandler("OnMouseEnter", OnMouseEnter)
+	control:SetHandler("OnMouseExit", OnMouseExit)
+	control:SetHandler("OnMouseUp", function(control)
+		if control.isDisabled then return end
+		PlaySound(SOUNDS.DEFAULT_CLICK)
+		control.value = not control.value
+		control:UpdateValue(false, control.value)
+	end)
+
+	control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL)
+	local checkbox = control.checkbox
+	checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0)
+	checkbox:SetFont("ZoFontGameBold")
+	checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
+	control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper()
+	control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper()
+
+	if checkboxData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(checkboxData.warning)}
+	end
+
+	control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip)
+
+	if checkboxData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/colorpicker.lua b/Lib/LibAddonMenu-2.0/controls/colorpicker.lua
new file mode 100644
index 0000000..c25452f
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/colorpicker.lua
@@ -0,0 +1,110 @@
+--[[colorpickerData = {
+	type = "colorpicker",
+	name = "My Color Picker", -- or string id or function returning a string
+	getFunc = function() return db.r, db.g, db.b, db.a end,	--(alpha is optional)
+	setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end,	--(alpha is optional)
+	tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	-- or string id or function returning a string (optional)
+	default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a},	--(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color
+	reference = "MyAddonColorpicker"	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 10
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+
+
+local function UpdateDisabled(control)
+	local disable
+	if type(control.data.disabled) == "function" then
+		disable = control.data.disabled()
+	else
+		disable = control.data.disabled
+	end
+
+	if disable then
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	else
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	end
+
+	control.isDisabled = disable
+end
+
+local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA)
+	if forceDefault then	--if we are forcing defaults
+		local color = LAM.util.GetDefaultValue(control.data.default)
+		valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a
+		control.data.setFunc(valueR, valueG, valueB, valueA)
+	elseif valueR and valueG and valueB then
+		control.data.setFunc(valueR, valueG, valueB, valueA or 1)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		valueR, valueG, valueB, valueA = control.data.getFunc()
+	end
+
+	control.thumb:SetColor(valueR, valueG, valueB, valueA or 1)
+end
+
+function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName)
+
+	control.color = control.container
+	local color = control.color
+
+	control.thumb = wm:CreateControl(nil, color, CT_TEXTURE)
+	local thumb = control.thumb
+	thumb:SetDimensions(36, 18)
+	thumb:SetAnchor(LEFT, color, LEFT, 4, 0)
+
+	color.border = wm:CreateControl(nil, color, CT_TEXTURE)
+	local border = color.border
+	border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds")
+	border:SetTextureCoords(0, .625, 0, .8125)
+	border:SetDimensions(40, 22)
+	border:SetAnchor(CENTER, thumb, CENTER, 0, 0)
+
+	local function ColorPickerCallback(r, g, b, a)
+		control:UpdateValue(false, r, g, b, a)
+	end
+
+	control:SetHandler("OnMouseUp", function(self, btn, upInside)
+		if self.isDisabled then return end
+
+		if upInside then
+			local r, g, b, a = colorpickerData.getFunc()
+			COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name))
+		end
+	end)
+
+	if colorpickerData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0)
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(colorpickerData.warning)}
+	end
+
+	control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip)
+
+	if colorpickerData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/custom.lua b/Lib/LibAddonMenu-2.0/controls/custom.lua
new file mode 100644
index 0000000..e7b7312
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/custom.lua
@@ -0,0 +1,40 @@
+--[[customData = {
+	type = "custom",
+	reference = "MyAddonCustomControl",	--(optional) unique name for your control to use as reference
+	refreshFunc = function(customControl) end,	--(optional) function to call when panel/controls refresh
+	width = "full",	--or "half" (optional)
+}	]]
+
+local widgetVersion = 6
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("custom", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local tinsert = table.insert
+
+local function UpdateValue(control)
+	if control.data.refreshFunc then
+		control.data.refreshFunc(control)
+	end
+end
+
+local MIN_HEIGHT = 26
+function LAMCreateControl.custom(parent, customData, controlName)
+	local control = LAM.util.CreateBaseControl(parent, customData, controlName)
+	local width = control:GetWidth()
+	control:SetResizeToFitDescendents(true)
+
+	if control.isHalfWidth then	--note these restrictions
+		control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
+	else
+		control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
+	end
+
+	control.UpdateValue = UpdateValue
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
\ No newline at end of file
diff --git a/Lib/LibAddonMenu-2.0/controls/description.lua b/Lib/LibAddonMenu-2.0/controls/description.lua
new file mode 100644
index 0000000..ba769ba
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/description.lua
@@ -0,0 +1,63 @@
+--[[descriptionData = {
+	type = "description",
+	text = "My description text to display.", -- or string id or function returning a string
+	title = "My Title",	-- or string id or function returning a string (optional)
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonDescription"	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 8
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("description", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local tinsert = table.insert
+
+local function UpdateValue(control)
+	if control.title then
+		control.title:SetText(LAM.util.GetStringFromValue(control.data.title))
+	end
+	control.desc:SetText(LAM.util.GetStringFromValue(control.data.text))
+end
+
+function LAMCreateControl.description(parent, descriptionData, controlName)
+	local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName)
+	local isHalfWidth = control.isHalfWidth
+	local width = control:GetWidth()
+	control:SetResizeToFitDescendents(true)
+
+	if isHalfWidth then
+		control:SetDimensionConstraints(width / 2, 0, width / 2, 0)
+	else
+		control:SetDimensionConstraints(width, 0, width, 0)
+	end
+
+	control.desc = wm:CreateControl(nil, control, CT_LABEL)
+	local desc = control.desc
+	desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
+	desc:SetFont("ZoFontGame")
+	desc:SetText(LAM.util.GetStringFromValue(descriptionData.text))
+	desc:SetWidth(isHalfWidth and width / 2 or width)
+
+	if descriptionData.title then
+		control.title = wm:CreateControl(nil, control, CT_LABEL)
+		local title = control.title
+		title:SetWidth(isHalfWidth and width / 2 or width)
+		title:SetAnchor(TOPLEFT, control, TOPLEFT)
+		title:SetFont("ZoFontWinH4")
+		title:SetText(LAM.util.GetStringFromValue(descriptionData.title))
+		desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT)
+	else
+		desc:SetAnchor(TOPLEFT)
+	end
+
+	control.UpdateValue = UpdateValue
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+
+end
\ No newline at end of file
diff --git a/Lib/LibAddonMenu-2.0/controls/dropdown.lua b/Lib/LibAddonMenu-2.0/controls/dropdown.lua
new file mode 100644
index 0000000..7d9f9b3
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/dropdown.lua
@@ -0,0 +1,131 @@
+--[[dropdownData = {
+	type = "dropdown",
+	name = "My Dropdown", -- or string id or function returning a string
+	choices = {"table", "of", "choices"},
+	getFunc = function() return db.var end,
+	setFunc = function(var) db.var = var doStuff() end,
+	tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional)
+	sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	 -- or string id or function returning a string (optional)
+	default = defaults.var,	-- default value or function that returns the default value (optional)
+	reference = "MyAddonDropdown"	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 12
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("dropdown", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+
+
+local function UpdateDisabled(control)
+	local disable
+	if type(control.data.disabled) == "function" then
+		disable = control.data.disabled()
+	else
+		disable = control.data.disabled
+	end
+
+	control.dropdown:SetEnabled(not disable)
+	if disable then
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	else
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	end
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = LAM.util.GetDefaultValue(control.data.default)
+		control.data.setFunc(value)
+		control.dropdown:SetSelectedItem(value)
+	elseif value then
+		control.data.setFunc(value)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		value = control.data.getFunc()
+		control.dropdown:SetSelectedItem(value)
+	end
+end
+
+local function DropdownCallback(control, choiceText, choice)
+	choice.control:UpdateValue(false, choiceText)
+end
+
+local function UpdateChoices(control, choices)
+	control.dropdown:ClearItems()	--remove previous choices	--(need to call :SetSelectedItem()?)
+
+	--build new list of choices
+	local choices = choices or control.data.choices
+	for i = 1, #choices do
+		local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback)
+		entry.control = control
+		control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE)	--if sort type/order isn't specified, then don't sort
+	end
+end
+
+local function GrabSortingInfo(sortInfo)
+	local t, i = {}, 1
+	for info in string.gmatch(sortInfo, "([^%-]+)") do
+		t[i] = info
+		i = i + 1
+	end
+
+	return t
+end
+
+function LAMCreateControl.dropdown(parent, dropdownData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName)
+
+	local countControl = parent
+	local name = parent:GetName()
+	if not name or #name == 0 then
+		countControl = LAMCreateControl
+		name = "LAM"
+	end
+	local comboboxCount = (countControl.comboboxCount or 0) + 1
+	countControl.comboboxCount = comboboxCount
+	control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, "ZO_ComboBox")
+
+	local combobox = control.combobox
+	combobox:SetAnchor(TOPLEFT)
+	combobox:SetDimensions(control.container:GetDimensions())
+	combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+	combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
+	control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox)
+	local dropdown = control.dropdown
+	if dropdownData.sort then
+		local sortInfo = GrabSortingInfo(dropdownData.sort)
+		local sortType, sortOrder = sortInfo[1], sortInfo[2]
+		dropdown:SetSortOrder(sortOrder == "up" and ZO_SORT_ORDER_UP or ZO_SORT_ORDER_DOWN, sortType == "name" and ZO_SORT_BY_NAME or ZO_SORT_BY_NAME_NUMERIC)
+	end
+
+	if dropdownData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0)
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(dropdownData.warning)}
+	end
+
+	if dropdownData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+	control.UpdateChoices = UpdateChoices
+	control:UpdateChoices(dropdownData.choices)
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/editbox.lua b/Lib/LibAddonMenu-2.0/controls/editbox.lua
new file mode 100644
index 0000000..a7e4830
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/editbox.lua
@@ -0,0 +1,160 @@
+--[[editboxData = {
+	type = "editbox",
+	name = "My Editbox", -- or string id or function returning a string
+	getFunc = function() return db.text end,
+	setFunc = function(text) db.text = text doStuff() end,
+	tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional)
+	isMultiline = true,	--boolean (optional)
+	isExtraWide = true,	--boolean (optional)
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	-- or string id or function returning a string (optional)
+	default = defaults.text,	-- default value or function that returns the default value (optional)
+	reference = "MyAddonEditbox"	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 11
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("editbox", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+
+
+local function UpdateDisabled(control)
+	local disable
+	if type(control.data.disabled) == "function" then
+		disable = control.data.disabled()
+	else
+		disable = control.data.disabled
+	end
+
+	if disable then
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+		control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
+	else
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+		control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	end
+	--control.editbox:SetEditEnabled(not disable)
+	control.editbox:SetMouseEnabled(not disable)
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = LAM.util.GetDefaultValue(control.data.default)
+		control.data.setFunc(value)
+		control.editbox:SetText(value)
+	elseif value then
+		control.data.setFunc(value)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		value = control.data.getFunc()
+		control.editbox:SetText(value)
+	end
+end
+
+local MIN_HEIGHT = 24
+local HALF_WIDTH_LINE_SPACING = 2
+function LAMCreateControl.editbox(parent, editboxData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName)
+
+	local container = control.container
+	control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop")
+	local bg = control.bg
+	bg:SetAnchorFill()
+
+	if editboxData.isMultiline then
+		control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop")
+		control.editbox:SetHandler("OnMouseWheel", function(self, delta)
+			if self:HasFocus() then	--only set focus to new spots if the editbox is currently in use
+				local cursorPos = self:GetCursorPosition()
+				local text = self:GetText()
+				local textLen = text:len()
+				local newPos
+				if delta > 0 then	--scrolling up
+					local reverseText = text:reverse()
+					local revCursorPos = textLen - cursorPos
+					local revPos = reverseText:find("\n", revCursorPos+1)
+					newPos = revPos and textLen - revPos
+				else	--scrolling down
+					newPos = text:find("\n", cursorPos+1)
+				end
+				if newPos then	--if we found a new line, then scroll, otherwise don't
+					self:SetCursorPosition(newPos)
+				end
+			end
+		end)
+	else
+		control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop")
+	end
+	local editbox = control.editbox
+	editbox:SetText(editboxData.getFunc())
+	editbox:SetMaxInputChars(3000)
+	editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end)
+	editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end)
+	editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+	editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
+
+	local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0
+
+	control.label:ClearAnchors()
+	container:ClearAnchors()
+
+	control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
+	container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0)
+
+	if control.isHalfWidth then
+		container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0)
+	end
+
+	if editboxData.isExtraWide then
+		container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0)
+	else
+		container:SetWidth(MIN_WIDTH * 3.2)
+	end
+
+	if editboxData.isMultiline then
+		container:SetHeight(MIN_HEIGHT * 3)
+	else
+		container:SetHeight(MIN_HEIGHT)
+	end
+
+	if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then
+		control:SetHeight(container:GetHeight())
+	else
+		control:SetHeight(container:GetHeight() + control.label:GetHeight())
+	end
+
+	editbox:ClearAnchors()
+	editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2)
+	editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2)
+
+	if editboxData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		if editboxData.isExtraWide then
+			control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0)
+		else
+			control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0)
+		end
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(editboxData.warning)}
+	end
+
+	if editboxData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/header.lua b/Lib/LibAddonMenu-2.0/controls/header.lua
new file mode 100644
index 0000000..a96066e
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/header.lua
@@ -0,0 +1,45 @@
+--[[headerData = {
+	type = "header",
+	name = "My Header", -- or string id or function returning a string
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonHeader"	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 7
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("header", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local tinsert = table.insert
+
+local function UpdateValue(control)
+	control.header:SetText(LAM.util.GetStringFromValue(control.data.name))
+end
+
+local MIN_HEIGHT = 30
+function LAMCreateControl.header(parent, headerData, controlName)
+	local control = LAM.util.CreateBaseControl(parent, headerData, controlName)
+	local isHalfWidth = control.isHalfWidth
+	local width = control:GetWidth()
+	control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT)
+
+	control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider")
+	local divider = control.divider
+	divider:SetWidth(isHalfWidth and width / 2 or width)
+	divider:SetAnchor(TOPLEFT)
+
+	control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
+	local header = control.header
+	header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT)
+	header:SetAnchor(BOTTOMRIGHT)
+	header:SetText(LAM.util.GetStringFromValue(headerData.name))
+
+	control.UpdateValue = UpdateValue
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
\ No newline at end of file
diff --git a/Lib/LibAddonMenu-2.0/controls/iconpicker.lua b/Lib/LibAddonMenu-2.0/controls/iconpicker.lua
new file mode 100644
index 0000000..c070b3f
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/iconpicker.lua
@@ -0,0 +1,441 @@
+--[[iconpickerData = {
+	type = "iconpicker",
+	name = "My Icon Picker", -- or string id or function returning a string
+	choices = {"texture path 1", "texture path 2", "texture path 3"},
+	getFunc = function() return db.var end,
+	setFunc = function(var) db.var = var doStuff() end,
+	tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
+	choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional)
+	maxColumns = 5, -- number of icons in one row (optional)
+	visibleRows = 4.5, -- number of visible rows (optional)
+	iconSize = 28, -- size of the icons (optional)
+	defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional)
+	width = "full",	--or "half" (optional)
+	beforeShow = function(control, iconPicker) return preventShow end, --(optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	-- or string id or function returning a string (optional)
+	default = defaults.var,	-- default value or function that returns the default value (optional)
+	reference = "MyAddonIconPicker"	-- unique global reference to control (optional)
+}	]]
+
+local widgetVersion = 5
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+
+local IconPickerMenu = ZO_Object:Subclass()
+local iconPicker
+LAM.util.GetIconPickerMenu = function()
+	if not iconPicker then
+		iconPicker = IconPickerMenu:New("LAMIconPicker")
+		local sceneFragment = LAM:GetAddonSettingsFragment()
+		ZO_PreHook(sceneFragment, "OnHidden", function()
+			if not iconPicker.control:IsHidden() then
+				iconPicker:Clear()
+			end
+		end)
+	end
+	return iconPicker
+end
+
+function IconPickerMenu:New(...)
+	local object = ZO_Object.New(self)
+	object:Initialize(...)
+	return object
+end
+
+function IconPickerMenu:Initialize(name)
+	local control = wm:CreateTopLevelWindow(name)
+	control:SetDrawTier(DT_HIGH)
+	control:SetHidden(true)
+	self.control = control
+
+	local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer")
+	-- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count
+	scrollContainer:SetAnchorFill()
+	ZO_Scroll_SetUseFadeGradient(scrollContainer, false)
+	ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false)
+	ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value
+	local scroll = GetControl(scrollContainer, "ScrollChild")
+	self.scroll = scroll
+	self.scrollContainer = scrollContainer
+
+	local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP)
+	bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3)
+	bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5)
+	bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
+	bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
+	bg:SetInsets(16, 16, -16, -16)
+
+	local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
+	mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
+	mungeOverlay:SetDrawLevel(1)
+	mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
+	mungeOverlay:SetAnchorFill()
+
+	local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE)
+	mouseOver:SetDrawLevel(2)
+	mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds")
+	mouseOver:SetHidden(true)
+
+	local function IconFactory(pool)
+		local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE)
+		icon:SetMouseEnabled(true)
+		icon:SetDrawLevel(3)
+		icon:SetHandler("OnMouseEnter", function()
+			mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0)
+			mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0)
+			mouseOver:SetHidden(false)
+			if self.customOnMouseEnter then
+				self.customOnMouseEnter(icon)
+			else
+				self:OnMouseEnter(icon)
+			end
+		end)
+		icon:SetHandler("OnMouseExit", function()
+			mouseOver:ClearAnchors()
+			mouseOver:SetHidden(true)
+			if self.customOnMouseExit then
+				self.customOnMouseExit(icon)
+			else
+				self:OnMouseExit(icon)
+			end
+		end)
+		icon:SetHandler("OnMouseUp", function(control, ...)
+			PlaySound("Click")
+			icon.OnSelect(icon, icon.texture)
+			self:Clear()
+		end)
+		return icon
+	end
+
+	local function ResetFunction(icon)
+		icon:ClearAnchors()
+	end
+
+	self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction)
+	self:SetMaxColumns(1)
+	self.icons = {}
+	self.color = ZO_DEFAULT_ENABLED_COLOR
+
+	EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function()
+		if self.refCount ~= nil then
+			local moc = wm:GetMouseOverControl()
+			if(moc:GetOwningWindow() ~= control) then
+				self.refCount = self.refCount - 1
+				if self.refCount <= 0 then
+					self:Clear()
+				end
+			end
+		end
+	end)
+end
+
+function IconPickerMenu:OnMouseEnter(icon)
+	InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT)
+	SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip))
+	InformationTooltipTopLevel:BringWindowToTop()
+end
+
+function IconPickerMenu:OnMouseExit(icon)
+	ClearTooltip(InformationTooltip)
+end
+
+function IconPickerMenu:SetMaxColumns(value)
+	self.maxCols = value ~= nil and value or 5
+end
+
+local DEFAULT_SIZE = 28
+function IconPickerMenu:SetIconSize(value)
+	local iconSize = DEFAULT_SIZE
+	if value ~= nil then iconSize = math.max(iconSize, value) end
+	self.iconSize = iconSize
+end
+
+function IconPickerMenu:SetVisibleRows(value)
+	self.visibleRows = value ~= nil and value or 4.5
+end
+
+function IconPickerMenu:SetMouseHandlers(onEnter, onExit)
+	self.customOnMouseEnter = onEnter
+	self.customOnMouseExit = onExit
+end
+
+function IconPickerMenu:UpdateDimensions()
+	local iconSize = self.iconSize
+	local width = iconSize * self.maxCols + 20
+	local height = iconSize * self.visibleRows
+	self.control:SetDimensions(width, height)
+
+	local icons = self.icons
+	for i = 1, #icons do
+		local icon = icons[i]
+		icon:SetDimensions(iconSize, iconSize)
+	end
+end
+
+function IconPickerMenu:UpdateAnchors()
+	local iconSize = self.iconSize
+	local col, maxCols = 1, self.maxCols
+	local previousCol, previousRow
+	local scroll = self.scroll
+	local icons = self.icons
+
+	for i = 1, #icons do
+		local icon = icons[i]
+		icon:ClearAnchors()
+		if i == 1 then
+			icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0)
+			previousRow = icon
+		elseif col == 1 then
+			icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0)
+			previousRow = icon
+		else
+			icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0)
+		end
+		previousCol = icon
+		col = col >= maxCols and 1 or col + 1
+	end
+end
+
+function IconPickerMenu:Clear()
+	self.icons = {}
+	self.iconPool:ReleaseAllObjects()
+	self.control:SetHidden(true)
+	self.color = ZO_DEFAULT_ENABLED_COLOR
+	self.refCount = nil
+	self.parent = nil
+	self.customOnMouseEnter = nil
+	self.customOnMouseExit = nil
+end
+
+function IconPickerMenu:AddIcon(texturePath, callback, tooltip)
+	local icon, key = self.iconPool:AcquireObject()
+	icon:SetTexture(texturePath)
+	icon:SetColor(self.color:UnpackRGBA())
+	icon.texture = texturePath
+	icon.tooltip = tooltip
+	icon.OnSelect = callback
+	self.icons[#self.icons + 1] = icon
+end
+
+function IconPickerMenu:Show(parent)
+	if #self.icons == 0 then return false end
+	if not self.control:IsHidden() then self:Clear() return false end
+	self:UpdateDimensions()
+	self:UpdateAnchors()
+
+	local control = self.control
+	control:ClearAnchors()
+	control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8)
+	control:SetHidden(false)
+	control:BringWindowToTop()
+	self.parent = parent
+	self.refCount = 2
+
+	return true
+end
+
+function IconPickerMenu:SetColor(color)
+	local icons = self.icons
+	self.color = color
+	for i = 1, #icons do
+		local icon = icons[i]
+		icon:SetColor(color:UnpackRGBA())
+	end
+end
+
+-------------------------------------------------------------
+
+local function UpdateChoices(control, choices, choicesTooltips)
+	local data = control.data
+	if not choices then
+		choices, choicesTooltips = data.choices, data.choicesTooltips or {}
+	end
+	local addedChoices = {}
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	iconPicker:Clear()
+	for i = 1, #choices do
+		local texture = choices[i]
+		if not addedChoices[texture] then -- remove duplicates
+			iconPicker:AddIcon(choices[i], function(self, texture)
+				control.icon:SetTexture(texture)
+				data.setFunc(texture)
+				if control.panel.data.registerForRefresh then
+					cm:FireCallbacks("LAM-RefreshPanel", control)
+				end
+			end, LAM.util.GetStringFromValue(choicesTooltips[i]))
+			addedChoices[texture] = true
+		end
+	end
+end
+
+local function IsDisabled(control)
+	if type(control.data.disabled) == "function" then
+		return control.data.disabled()
+	else
+		return control.data.disabled
+	end
+end
+
+local function SetColor(control, color)
+	local icon = control.icon
+	if IsDisabled(control) then
+		icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	else
+		icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR
+		icon:SetColor(icon.color:UnpackRGBA())
+	end
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
+		iconPicker:SetColor(icon.color)
+	end
+end
+
+local function UpdateDisabled(control)
+	local disable = IsDisabled(control)
+
+	control.dropdown:SetMouseEnabled(not disable)
+	control.dropdownButton:SetEnabled(not disable)
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
+		iconPicker:Clear()
+	end
+
+	SetColor(control)
+	if disable then
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	else
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	end
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = LAM.util.GetDefaultValue(control.data.default)
+		control.data.setFunc(value)
+		control.icon:SetTexture(value)
+	elseif value then
+		control.data.setFunc(value)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		value = control.data.getFunc()
+		control.icon:SetTexture(value)
+	end
+end
+
+local MIN_HEIGHT = 26
+local HALF_WIDTH_LINE_SPACING = 2
+local function SetIconSize(control, size)
+	local icon = control.icon
+	icon.size = size
+	icon:SetDimensions(size, size)
+
+	local height = size + 4
+	control.dropdown:SetDimensions(size + 20, height)
+	height = math.max(height, MIN_HEIGHT)
+	control.container:SetHeight(height)
+	if control.lineControl then
+		control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING)
+	else
+		control:SetHeight(height)
+	end
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
+		iconPicker:SetIconSize(size)
+		iconPicker:UpdateDimensions()
+		iconPicker:UpdateAnchors()
+	end
+end
+
+function LAMCreateControl.iconpicker(parent, iconpickerData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName)
+
+	local function ShowIconPicker()
+		local iconPicker = LAM.util.GetIconPickerMenu()
+		if iconPicker.parent == control.container then
+			iconPicker:Clear()
+		else
+			iconPicker:SetMaxColumns(iconpickerData.maxColumns)
+			iconPicker:SetVisibleRows(iconpickerData.visibleRows)
+			iconPicker:SetIconSize(control.icon.size)
+			UpdateChoices(control)
+			iconPicker:SetColor(control.icon.color)
+			if iconpickerData.beforeShow then
+				if iconpickerData.beforeShow(control, iconPicker) then
+					iconPicker:Clear()
+					return
+				end
+			end
+			iconPicker:Show(control.container)
+		end
+	end
+
+	local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE
+	control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL)
+	local dropdown = control.dropdown
+	dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0)
+	dropdown:SetMouseEnabled(true)
+	dropdown:SetHandler("OnMouseUp", ShowIconPicker)
+	dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+	dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
+
+	control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE)
+	local icon = control.icon
+	icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0)
+	icon:SetDrawLevel(2)
+
+	local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton")
+	dropdownButton:SetDimensions(16, 16)
+	dropdownButton:SetHandler("OnClicked", ShowIconPicker)
+	dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0)
+	control.dropdownButton = dropdownButton
+
+	control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP)
+	local bg = control.bg
+	bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3)
+	bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5)
+	bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16)
+	bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds")
+	bg:SetInsets(16, 16, -16, -16)
+	local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
+	mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
+	mungeOverlay:SetDrawLevel(1)
+	mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
+	mungeOverlay:SetAnchorFill()
+
+	if iconpickerData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0)
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(iconpickerData.warning)}
+	end
+
+	if iconpickerData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+
+	control.UpdateChoices = UpdateChoices
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+	control.SetColor = SetColor
+	control:SetColor()
+	control.SetIconSize = SetIconSize
+	control:SetIconSize(iconSize)
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/panel.lua b/Lib/LibAddonMenu-2.0/controls/panel.lua
new file mode 100644
index 0000000..00a909e
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/panel.lua
@@ -0,0 +1,132 @@
+--[[panelData = {
+	type = "panel",
+	name = "Window Title", -- or string id or function returning a string
+	displayName = "My Longer Window Title",	 -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it)
+	author = "Seerah",	 -- or string id or function returning a string (optional)
+	version = "2.0",	 -- or string id or function returning a string (optional)
+	keywords = "settings",	-- additional keywords for search filter (it looks for matches in name..keywords..author) (optional)
+	slashCommand = "/myaddon",	-- will register a keybind to open to this panel (don't forget to include the slash!) (optional)
+	registerForRefresh = true,	--boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown)
+	registerForDefaults = true,	--boolean (optional) (will set all options controls back to default values)
+	resetFunc = function() print("defaults reset") end,	--(optional) custom function to run after settings are reset to defaults
+}	]]
+
+
+local widgetVersion = 10
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("panel", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+
+local function RefreshPanel(control)
+	local panel = control.panel or control	--callback can be fired by a single control or by the panel showing
+	local panelControls = panel.controlsToRefresh
+
+	for i = 1, #panelControls do
+		local updateControl = panelControls[i]
+		if  updateControl ~= control then
+			if updateControl.UpdateValue then
+				updateControl:UpdateValue()
+			end
+			if updateControl.UpdateDisabled then
+				updateControl:UpdateDisabled()
+			end
+		end
+	end
+end
+
+local function ForceDefaults(panel)
+	local panelControls = panel.controlsToRefresh
+
+	for i = 1, #panelControls do
+		local updateControl = panelControls[i]
+		if updateControl.UpdateValue and updateControl.data.default ~= nil then
+			updateControl:UpdateValue(true)
+		end
+	end
+
+	if panel.data.resetFunc then
+		panel.data.resetFunc()
+	end
+
+	cm:FireCallbacks("LAM-RefreshPanel", panel)
+end
+ESO_Dialogs["LAM_DEFAULTS"] = {
+	title = {
+		text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP,
+	},
+	mainText = {
+		text = SI_OPTIONS_RESET_PROMPT,
+		align = TEXT_ALIGN_CENTER,
+	},
+	buttons = {
+		[1] = {
+			text = SI_OPTIONS_RESET,
+			callback = function(dialog) ForceDefaults(dialog.data[1]) end,
+		},
+		[2] = {
+			text = SI_DIALOG_CANCEL,
+		},
+	},
+}
+
+local callbackRegistered = false
+LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1
+function LAMCreateControl.panel(parent, panelData, controlName)
+	local control = wm:CreateControl(controlName, parent, CT_CONTROL)
+
+	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
+	local label = control.label
+	label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4)
+	label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name))
+
+	if panelData.author or panelData.version then
+		control.info = wm:CreateControl(nil, control, CT_LABEL)
+		local info = control.info
+		info:SetFont("$(CHAT_FONT)|14|soft-shadow-thin")
+		info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2)
+		if panelData.author and panelData.version then
+			info:SetText(string.format("Version: %s  -  %s: %s", LAM.util.GetStringFromValue(panelData.version), GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author)))
+		elseif panelData.author then
+			info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author)))
+		else
+			info:SetText("Version: " .. LAM.util.GetStringFromValue(panelData.version))
+		end
+	end
+
+	control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer")
+	LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1
+	local container = control.container
+	container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20)
+	container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3)
+	control.scroll = GetControl(control.container, "ScrollChild")
+	control.scroll:SetResizeToFitPadding(0, 20)
+
+	if panelData.registerForDefaults then
+		control.defaultButton = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultTextButton")
+		local defaultButton = control.defaultButton
+		defaultButton:SetFont("ZoFontDialogKeybindDescription")
+		defaultButton:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
+		--defaultButton:SetText("Reset To Defaults")
+		defaultButton:SetText(GetString(SI_OPTIONS_DEFAULTS))
+		defaultButton:SetDimensions(200, 30)
+		defaultButton:SetAnchor(TOPLEFT, control, BOTTOMLEFT, 0, 2)
+		defaultButton:SetHandler("OnClicked", function()
+				ZO_Dialogs_ShowDialog("LAM_DEFAULTS", {control})
+			end)
+	end
+
+	if panelData.registerForRefresh and not callbackRegistered then	--don't want to register our callback more than once
+		cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel)
+		callbackRegistered = true
+	end
+
+	control.data = panelData
+	control.controlsToRefresh = {}
+
+	return control
+end
+
+
+-- vi: noexpandtab
diff --git a/Lib/LibAddonMenu-2.0/controls/separator.dds b/Lib/LibAddonMenu-2.0/controls/separator.dds
new file mode 100644
index 0000000..02bb2ab
Binary files /dev/null and b/Lib/LibAddonMenu-2.0/controls/separator.dds differ
diff --git a/Lib/LibAddonMenu-2.0/controls/slider.lua b/Lib/LibAddonMenu-2.0/controls/slider.lua
new file mode 100644
index 0000000..e4b16ef
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/slider.lua
@@ -0,0 +1,166 @@
+--[[sliderData = {
+	type = "slider",
+	name = "My Slider", -- or string id or function returning a string
+	getFunc = function() return db.var end,
+	setFunc = function(value) db.var = value doStuff() end,
+	min = 0,
+	max = 20,
+	step = 1,	--(optional)
+	decimals = 0, --(optional)
+	tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional)
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	-- or string id or function returning a string (optional)
+	default = defaults.var,	-- default value or function that returns the default value (optional)
+	reference = "MyAddonSlider"	-- unique global reference to control (optional)
+}	]]
+
+
+local widgetVersion = 9
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("slider", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local round = zo_round
+local strformat = string.format
+local tinsert = table.insert
+
+local function UpdateDisabled(control)
+	local disable
+	if type(control.data.disabled) == "function" then
+		disable = control.data.disabled()
+	else
+		disable = control.data.disabled
+	end
+
+	control.slider:SetEnabled(not disable)
+	control.slidervalue:SetEditEnabled(not disable)
+	if disable then
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+		control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+		control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+		control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
+	else
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+		control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+		control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+		control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	end
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = LAM.util.GetDefaultValue(control.data.default)
+		control.data.setFunc(value)
+	elseif value and value >= control.data.min and value <= control.data.max then
+		control.data.setFunc(value)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		value = control.data.getFunc()
+	end
+
+	control.slider:SetValue(value)
+	control.slidervalue:SetText(value)
+end
+
+
+function LAMCreateControl.slider(parent, sliderData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName)
+
+	--skipping creating the backdrop...  Is this the actual slider texture?
+	control.slider = wm:CreateControl(nil, control.container, CT_SLIDER)
+	local slider = control.slider
+	slider:SetAnchor(TOPLEFT)
+	slider:SetAnchor(TOPRIGHT)
+	slider:SetHeight(14)
+	slider:SetMouseEnabled(true)
+	slider:SetOrientation(ORIENTATION_HORIZONTAL)
+	--put nil for highlighted texture file path, and what look to be texture coords
+	slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16)
+	local minValue = sliderData.min
+	local maxValue = sliderData.max
+	slider:SetMinMax(minValue, maxValue)
+	slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+	slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseExit(control) end)
+
+	slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP)
+	local bg = slider.bg
+	bg:SetCenterColor(0, 0, 0)
+	bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4)
+	bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4)
+	bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4)
+
+	control.minText = wm:CreateControl(nil, slider, CT_LABEL)
+	local minText = control.minText
+	minText:SetFont("ZoFontGameSmall")
+	minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT)
+	minText:SetText(sliderData.min)
+
+	control.maxText = wm:CreateControl(nil, slider, CT_LABEL)
+	local maxText = control.maxText
+	maxText:SetFont("ZoFontGameSmall")
+	maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT)
+	maxText:SetText(sliderData.max)
+
+	control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop")
+	control.slidervalueBG:SetDimensions(50, 16)
+	control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0)
+	control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop")
+	local slidervalue = control.slidervalue
+	slidervalue:ClearAnchors()
+	slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1)
+	slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1)
+	slidervalue:SetTextType(TEXT_TYPE_NUMERIC)
+	slidervalue:SetFont("ZoFontGameSmall")
+	slidervalue:SetHandler("OnEscape", function(self)
+			self:LoseFocus()
+			control:UpdateValue()
+		end)
+	slidervalue:SetHandler("OnEnter", function(self)
+			self:LoseFocus()
+			control:UpdateValue(false, tonumber(self:GetText()))
+		end)
+	local function RoundDecimalToPlace(d, place)
+		return tonumber(string.format("%." .. tostring(place) .. "f", d))
+	end
+	local range = maxValue - minValue
+	slider:SetValueStep(sliderData.step or 1)
+	slider:SetHandler("OnValueChanged", function(self, value, eventReason)
+			if eventReason == EVENT_REASON_SOFTWARE then return end
+			local new_value = sliderData.decimals and RoundDecimalToPlace(value, sliderData.decimals) or value
+			self:SetValue(new_value)	--do we actually need this line?
+			slidervalue:SetText(new_value)
+		end)
+	slider:SetHandler("OnSliderReleased", function(self, value)
+			--sliderData.setFunc(value)
+			local new_value = sliderData.decimals and RoundDecimalToPlace(value, sliderData.decimals) or value
+			control:UpdateValue(false, new_value)	--does this work here instead?
+		end)
+	slider:SetHandler("OnMouseWheel", function(self, value)
+			local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value)
+			control:UpdateValue(false, new_value)
+		end)
+
+	if sliderData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0)
+		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(sliderData.warning)}
+	end
+
+	if sliderData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/submenu.lua b/Lib/LibAddonMenu-2.0/controls/submenu.lua
new file mode 100644
index 0000000..4508c82
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/submenu.lua
@@ -0,0 +1,112 @@
+--[[submenuData = {
+	type = "submenu",
+	name = "Submenu Title", -- or string id or function returning a string
+	tooltip = "My submenu tooltip",	-- -- or string id or function returning a string (optional)
+	controls = {sliderData, buttonData}	--(optional) used by LAM
+	reference = "MyAddonSubmenu"	--(optional) unique global reference to control
+}	]]
+
+local widgetVersion = 11
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("submenu", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local am = ANIMATION_MANAGER
+local tinsert = table.insert
+
+
+local function UpdateValue(control)
+	control.label:SetText(LAM.util.GetStringFromValue(control.data.name))
+	if control.data.tooltip then
+		control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip)
+	end
+end
+
+local function AnimateSubmenu(clicked)
+	local control = clicked:GetParent()
+	control.open = not control.open
+
+	if control.open then
+		control.animation:PlayFromStart()
+	else
+		control.animation:PlayFromEnd()
+	end
+end
+
+function LAMCreateControl.submenu(parent, submenuData, controlName)
+	local width = parent:GetWidth() - 45
+	local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL)
+	control.panel = parent
+	control.data = submenuData
+
+	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
+	local label = control.label
+	label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5)
+	label:SetDimensions(width, 30)
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(LAM.util.GetStringFromValue(submenuData.name))
+	label:SetMouseEnabled(true)
+	if submenuData.tooltip then
+		label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)}
+		label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+		label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+	end
+
+	control.scroll = wm:CreateControl(nil, control, CT_SCROLL)
+	local scroll = control.scroll
+	scroll:SetParent(control)
+	scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10)
+	scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0)
+
+	control.bg = wm:CreateControl(nil, label, CT_BACKDROP)
+	local bg = control.bg
+	bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5)
+	bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0)
+	bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
+	bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
+	bg:SetInsets(16, 16, -16, -16)
+
+	control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE)
+	local arrow = control.arrow
+	arrow:SetDimensions(28, 28)
+	arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds")	--list_sortup for the other way
+	arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5)
+
+	--figure out the cool animation later...
+	control.animation = am:CreateTimeline()
+	local animation = control.animation
+	animation:SetPlaybackType(ANIMATION_SIZE, 0)	--2nd arg = loop count
+
+	control:SetResizeToFitDescendents(true)
+	control.open = false
+	label:SetHandler("OnMouseUp", AnimateSubmenu)
+	animation:SetHandler("OnStop", function(self, completedPlaying)
+			scroll:SetResizeToFitDescendents(control.open)
+			if control.open then
+				control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds")
+				scroll:SetResizeToFitPadding(5, 20)
+			else
+				control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds")
+				scroll:SetResizeToFitPadding(5, 0)
+				scroll:SetHeight(0)
+			end
+		end)
+
+	--small strip at the bottom of the submenu that you can click to close it
+	control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE)
+	local btmToggle = control.btmToggle
+	btmToggle:SetMouseEnabled(true)
+	btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT)
+	btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT)
+	btmToggle:SetHeight(15)
+	btmToggle:SetAlpha(0)
+	btmToggle:SetHandler("OnMouseUp", AnimateSubmenu)
+
+	control.UpdateValue = UpdateValue
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/Lib/LibAddonMenu-2.0/controls/texture.lua b/Lib/LibAddonMenu-2.0/controls/texture.lua
new file mode 100644
index 0000000..b7f4f8b
--- /dev/null
+++ b/Lib/LibAddonMenu-2.0/controls/texture.lua
@@ -0,0 +1,45 @@
+--[[textureData = {
+	type = "texture",
+	image = "file/path.dds",
+	imageWidth = 64,	--max of 250 for half width, 510 for full
+	imageHeight = 32,	--max of 100
+	tooltip = "Image's tooltip text.",	-- or string id or function returning a string (optional)
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonTexture"	--(optional) unique global reference to control
+}	]]
+
+--add texture coords support?
+
+local widgetVersion = 8
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("texture", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+
+local MIN_HEIGHT = 26
+function LAMCreateControl.texture(parent, textureData, controlName)
+	local control = LAM.util.CreateBaseControl(parent, textureData, controlName)
+	local width = control:GetWidth()
+	control:SetResizeToFitDescendents(true)
+
+	if control.isHalfWidth then	--note these restrictions
+		control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
+	else
+		control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
+	end
+
+	control.texture = wm:CreateControl(nil, control, CT_TEXTURE)
+	local texture = control.texture
+	texture:SetAnchor(CENTER)
+	texture:SetDimensions(textureData.imageWidth, textureData.imageHeight)
+	texture:SetTexture(textureData.image)
+
+	if textureData.tooltip then
+		texture:SetMouseEnabled(true)
+		texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)}
+		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit)
+	end
+
+	return control
+end
\ No newline at end of file
diff --git a/Lib/LibLogos/LibLogos.lua b/Lib/LibLogos/LibLogos.lua
new file mode 100644
index 0000000..d1a2cab
--- /dev/null
+++ b/Lib/LibLogos/LibLogos.lua
@@ -0,0 +1,262 @@
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   LibLogos   --------------------------------------------
+---------------------------   by Deome (@deome) - heydeome@gmail.com   ---------------------------
+local									VERSION = "1.01"										--
+--																								--
+--																								--
+--------------------------------------   Obligatory Spam   ---------------------------------------
+--																								--
+-- 		"This Add-on is not created by, affiliated with or sponsored by ZeniMax 		  		--
+--		Media Inc. or its affiliates. The Elder Scrolls® and related logos are registered 	 	--
+--		trademarks of ZeniMax Media Inc. in the United States and/or other countries. 			--
+--		All rights reserved."																	--
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   Globals   --------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+local MAJOR, MINOR = "LibLogos", 2
+local LibLogos, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+if not LibLogos then return end
+
+function LibLogos:SortTable() 			end
+function LibLogos:ClearTable() 			end
+function LibLogos:CountTable() 			end
+function LibLogos:WeightedAverage()		end
+function LibLogos:Round()				end
+function LibLogos:RoundTo100s()			end
+function LibLogos:YearsToSeconds()  	end
+function LibLogos:MonthsToSeconds() 	end
+function LibLogos:WeeksToSeconds() 		end
+function LibLogos:DaysToSeconds() 		end
+function LibLogos:HoursToSeconds() 		end
+function LibLogos:SecondsToYears() 		end
+function LibLogos:SecondsToDays() 		end
+function LibLogos:SecondsToWeeks() 		end
+function LibLogos:SecondsToDays() 		end
+function LibLogos:SecondsToHours() 		end
+
+
+--------------------------------------------------------------------------------------------------
+------------------------------------------   Logic   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   Tables   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function LibLogos:ClearTable(aTable, numericIndex)
+	if numericIndex then
+		for key = #aTable, 1, -1 do
+			aTable[key] = nil
+		end
+
+		return aTable
+	else
+		for key in pairs(aTable) do
+			aTable[key] = nil
+		end
+
+		return aTable
+	end
+end
+
+function LibLogos:CountTable(aTable, deep)
+    local keys = 0
+
+	for key, value in pairs(aTable) do
+		keys = keys + 1
+
+		if deep then
+			if type(value) == "table" then
+				LibLogos:CountTable(value)
+			end
+		end
+	end
+
+    return keys
+end
+
+function LibLogos:SortTable(aTable, direction)
+	if direction == "asc" then
+		table.sort(aTable)
+	elseif direction == "desc" then
+		table.sort(aTable, function(a, b) return a<b end)
+	end
+
+	return aTable
+end
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   Arithmetic   ------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function LibLogos:WeightedAverage(value, weight)													-- For further study: https://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Mathematical_definition
+	local Avg	= value / weight																	-- Gonna show my work using the same symbols as in the above definition:
+	local wAvg 	= (Avg * weight) / weight															-- for reference, µ is the same as "Avg"
+
+	return wAvg
+
+--  µ = x₁ / w₁
+--	µ = (x₁ * w₁) / w₁
+--	( (x₁ * w₁) + (x₂ * w₂) + ... (x₉ * w₉) ) / (w₁ + w₂ + ... w₉)
+
+-- ^^ Repeat for each value/weight pair (ie price/stack in a sale) ^^
+end
+
+
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   Currency   -------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function LibLogos:Round(value)
+	return math.floor(value + 0.5) or 0
+end
+
+function LibLogos:RoundTo100s(value)
+	value = math.floor(value * 100)
+	value = value / 100
+
+	return value or 0
+end
+
+
+--------------------------------------------------------------------------------------------------
+-------------------------------------------   Time   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function LibLogos:YearsToSeconds(years)
+	years = tonumber(years)
+	assert(type(years) == "number",
+	"Bad argument #1 to `YearsToSeconds' (number expected)")
+
+	if years < 0 then
+		years = years * (-1)
+	end
+
+	local seconds = years * 31556925.9747
+	return seconds
+end
+
+function LibLogos:MonthsToSeconds(months)
+	months = tonumber(months)
+	assert(type(months) == "number",
+	"Bad argument #1 to `MonthsToSeconds' (number expected)")
+
+	if months < 0 then
+		months = months * (-1)
+	end
+
+	local seconds = months * 259200
+	return seconds
+end
+
+function LibLogos:WeeksToSeconds(weeks)
+	weeks = tonumber(weeks)
+	assert(type(weeks) == "number",
+	"Bad argument #1 to `WeeksToSeconds' (number expected)")
+
+	if weeks < 0 then																			-- Why would I bother adding a check for negative weeks?
+		weeks = weeks * (-1)																	-- Simple: to reduce the frequency of UI errors originating between chair and keyboard.
+	end
+
+	local seconds = weeks * 604800
+	return seconds
+end
+
+function LibLogos:DaysToSeconds(days)
+	days = tonumber(days)
+	assert(type(days) == "number",
+	"Bad argument #1 to `DaysToSeconds' (number expected)")
+
+	if days < 0 then
+		days = days * (-1)
+	end
+
+	local seconds = days * 86400
+	return seconds
+end
+
+function LibLogos:HoursToSeconds(hours)
+	hours = tonumber(hours)
+	assert(type(hours) == "number",
+	"Bad argument #1 to `HoursToSeconds' (number expected)")
+
+	if hours < 0 then
+		hours = hours * (-1)
+	end
+
+	local seconds = hours * 3600
+	return seconds
+end
+
+function LibLogos:SecondsToYears(seconds)
+	seconds = tonumber(seconds)
+	assert(type(seconds) == "number",
+	"Bad argument #1 to `SecondsToYears' (number expected)")
+
+	if seconds < 0 then
+		seconds = seconds * (-1)
+	end
+
+	local years = seconds / 31556925.9747
+	return years
+end
+
+function LibLogos:SecondsToMonths(seconds)
+	seconds = tonumber(seconds)
+	assert(type(seconds) == "number",
+	"Bad argument #1 to `SecondsToMonths' (number expected)")
+
+	if seconds < 0 then
+		seconds = seconds * (-1)
+	end
+
+	local months = seconds / 2592000
+	return months
+end
+
+function LibLogos:SecondsToWeeks(seconds)
+	seconds = tonumber(seconds)
+	assert(type(seconds) == "number",
+	"Bad argument #1 to `SecondsToWeeks' (number expected)")
+
+	if seconds < 0 then
+		seconds = seconds * (-1)
+	end
+
+	local weeks = seconds / 604800
+	return weeks
+end
+
+function LibLogos:SecondsToDays(seconds)
+	seconds = tonumber(seconds)
+	assert(type(seconds) == "number",
+	"Bad argument #1 to `SecondsToDays' (number expected)")
+
+	if seconds < 0 then
+		seconds = seconds * (-1)
+	end
+
+	local days = seconds / 86400
+	return days
+end
+
+function LibLogos:SecondsToHours(seconds)
+	seconds = tonumber(seconds)
+	assert(type(seconds) == "number",
+	"Bad argument #1 to `SecondsToHours' (number expected)")
+
+	if seconds < 0 then
+		seconds = seconds * (-1)
+	end
+
+	local hours = seconds / 3600
+	return hours
+end
+
diff --git a/Lib/LibStub/LibStub.lua b/Lib/LibStub/LibStub.lua
new file mode 100644
index 0000000..4dbff7b
--- /dev/null
+++ b/Lib/LibStub/LibStub.lua
@@ -0,0 +1,34 @@
+-- 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
+-- LibStub developed for World of Warcraft by above members of the WowAce community.
+-- Ported to Elder Scrolls Online by Seerah
+
+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]
+
+local strformat = string.format
+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(zo_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(strformat("Cannot find a library instance of %q.", 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
diff --git a/Lib/LibStub/LibStub.txt b/Lib/LibStub/LibStub.txt
new file mode 100644
index 0000000..df3488c
--- /dev/null
+++ b/Lib/LibStub/LibStub.txt
@@ -0,0 +1,7 @@
+## APIVersion: 100007
+## Title: LibStub
+## Description: Universal Library Stub
+## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, ported to ESO by Seerah
+## Version: 1.0 r4
+
+LibStub\LibStub.lua
\ No newline at end of file
diff --git a/Lib/LibStub/LibStub/LibStub.lua b/Lib/LibStub/LibStub/LibStub.lua
new file mode 100644
index 0000000..4c35014
--- /dev/null
+++ b/Lib/LibStub/LibStub/LibStub.lua
@@ -0,0 +1,38 @@
+-- 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
+-- LibStub developed for World of Warcraft by above members of the WowAce community.
+-- Ported to Elder Scrolls Online by Seerah
+
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4
+local LibStub = _G[LIBSTUB_MAJOR]
+
+local strformat = string.format
+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)")
+		if type(minor) ~= "number" then
+			minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.")
+		end
+
+		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(strformat("Cannot find a library instance of %q.", 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
+
+LibStub.SILENT = true
\ No newline at end of file
diff --git a/ddDataDaedra.lua b/ddDataDaedra.lua
new file mode 100644
index 0000000..74abf31
--- /dev/null
+++ b/ddDataDaedra.lua
@@ -0,0 +1,1536 @@
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   DataDaedra   -----------------------------------------
+---------------------------   by Deome (@deome) - heydeome@gmail.com   ---------------------------
+local									VERSION = "1.9"											--
+--																								--
+--																								--
+---------------------------------------   Deome's License   --------------------------------------
+--																								--
+-- 		Copyright (c) 2014, 2015, 2016 D. Deome (@deome) - heydeome@gmail.com					--
+--																								--
+-- 		This software is provided 'as-is', without any express or implied						--
+-- 		warranty. In no event will the author(s) be held liable for any damages					--
+-- 		arising from the use of this software. This software, and the ideas, processes, 		--
+--		functions, and all other intellectual property contained within may not be modified,	--
+--		distributed, or used in any other works without the written permission of the			--
+--		author.																					--
+--																								--
+--		Any use with permission of author must include the above license and copyright,			--
+--		and any other license and copyright notices noted within this software.			 		--
+--																								--
+-------------------------------------   ZO Obligatory Spam   -------------------------------------
+--																								--
+-- 		"This Add-on is not created by, affiliated with or sponsored by ZeniMax 		  		--
+--		Media Inc. or its affiliates. The Elder Scrolls and related logos are registered 	 	--
+--		trademarks of ZeniMax Media Inc. in the United States and/or other countries. 			--
+--		All rights reserved."																	--
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   Libraries   -------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+local LIB_LAM2 	= LibStub("LibAddonMenu-2.0")
+local LIB_LOG	= LibStub("LibLogos")
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   Namespace   -------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+ddDataDaedra = {
+	["name"] 						= "ddDataDaedra",
+	["version"]						= VERSION,
+	["savedVarsVersion"] 			= 8,
+	["isScanning"]					= false,
+	["dataCairn"] = {
+		["lastScan"]				= {},
+		["lastSale"]				= {},
+		["numSales"]				= {},
+		["prices"]					= {},
+		["codex"] = {
+			["init"]				= function() end,
+			["cResetButton"] 		= {},
+			["cPanelHeader"] 		= {},
+			["cNotify"] 			= {},
+			["cDebug"] 				= {},
+			["cwAvgSalePrice"]		= {},
+			["cSaveSalePrice"]		= {},
+			["cInterval"]			= {},
+			["cTooltipDetails"] 	= {},
+			["cTooltipFontHeader"] 	= {},
+			["cTooltipFontBody"] 	= {},
+			["cTooltipQuality"] 	= {},
+		},
+		["UI"] = {
+		},
+	},
+	["mPanel"] 						= function() end,
+	["mControls"] 					= function() end,
+	["chatLinkStatsToChat"] 		= function() end,
+	["slotControlStatsToChat"] 		= function() end,
+	["seenToStr"]	 				= function() end,
+	["wAvgToStr"]	 				= function() end,
+	["stackToStr"]	 				= function() end,
+	["inscribeCraftSigilstone"]		= function() end,
+	["inscribeItemSigilstone"]		= function() end,
+	["inscribePopupSigilstone"]		= function() end,
+	["alchemySigil"]				= function() end,
+	["provisionerSigil"]			= function() end,
+	["enchantingSigil"] 			= function() end,
+	["creationSigil"] 				= function() end,
+	["improvementSigil"] 			= function() end,
+	["sigilDesign"]					= function() end,
+	["linkStatsToChat"]				= function() end,
+	["twilightMaiden"]				= function() end,
+	["twilightSummons"]				= function() end,
+	["displayMsg"]					= function() end,
+	["hooks"]						= function() end,
+	["liminalBridge"] 				= function() end,
+}
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   Constants   -------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+local DATACAIRN			= ddDataDaedra.dataCairn
+local CODEX				= ddDataDaedra.dataCairn.codex
+local PRICES			= ddDataDaedra.dataCairn.prices
+local ADDON_NAME 		= ddDataDaedra.name
+local SV_VERSION 		= ddDataDaedra.savedVarsVersion
+local TASKMASTER		= nil
+local Sigil				= nil
+local TooltipControl	= nil
+local PopupControl 		= nil
+local ResultControl		= nil
+local SlotControl 		= nil
+local craftingStation	= nil
+local ACTIVE_SLOT		= nil
+local NUMGUILDS			= GetNumGuilds()
+local PostFunc 			= nil
+
+local fonts	= {
+	"DataDaedraHeader",
+	"DataDaedraBody",
+	"ZoFontBookTabletTitle",
+	"ZoFontBookTablet",
+	"ZoFontBookScrollTitle",
+    "ZoFontBookScroll",
+	"ZoFontBookNoteTitle",
+	"ZoFontBookNote",
+	"ZoFontBookLetterTitle",
+	"ZoFontBookLetter",
+	"ZoFontBookRubbingTitle",
+	"ZoFontBookRubbing",
+	"ZoFontBookSkinTitle",
+	"ZoFontBookSkin",
+	"ZoFontBookPaperTitle",
+    "ZoFontBookPaper",
+	"ZoFontTooltipTitle",
+	"ZoFontTooltipSubtitle",
+	"ZoFontHeader4",
+	"ZoFontHeader3",
+    "ZoFontHeader2",
+    "ZoFontHeader",
+	"ZoFontGameLargeBoldShadow",
+	"ZoFontGameLargeBold",
+	"ZoFontGameLarge",
+	"ZoFontGameShadow",
+	"ZoFontGameOutline",
+	"ZoFontGameBold",
+	"ZoFontGameMedium",
+	"ZoFontGame",
+    "ZoFontGameSmall",
+}
+
+local Str_Item_Quality = {
+[ITEM_QUALITY_NORMAL] 					= SI_ITEMQUALITY1,
+[ITEM_QUALITY_MAGIC] 					= SI_ITEMQUALITY2,
+[ITEM_QUALITY_ARCANE] 					= SI_ITEMQUALITY3,
+[ITEM_QUALITY_ARTIFACT] 				= SI_ITEMQUALITY4,
+[ITEM_QUALITY_LEGENDARY] 				= SI_ITEMQUALITY5,
+[ITEM_QUALITY_TRASH] 					= SI_ITEMQUALITY0,
+}
+
+local Str_Item_Trait = {
+[ITEM_TRAIT_TYPE_NONE] 					= SI_ITEMTRAITTYPE0,
+[ITEM_TRAIT_TYPE_WEAPON_POWERED] 		= SI_ITEMTRAITTYPE1,
+[ITEM_TRAIT_TYPE_WEAPON_CHARGED] 		= SI_ITEMTRAITTYPE2,
+[ITEM_TRAIT_TYPE_WEAPON_PRECISE] 		= SI_ITEMTRAITTYPE3,
+[ITEM_TRAIT_TYPE_WEAPON_INFUSED] 		= SI_ITEMTRAITTYPE4,
+[ITEM_TRAIT_TYPE_WEAPON_DEFENDING] 		= SI_ITEMTRAITTYPE5,
+[ITEM_TRAIT_TYPE_WEAPON_TRAINING] 		= SI_ITEMTRAITTYPE6,
+[ITEM_TRAIT_TYPE_WEAPON_SHARPENED] 		= SI_ITEMTRAITTYPE7,
+[ITEM_TRAIT_TYPE_WEAPON_WEIGHTED] 		= SI_ITEMTRAITTYPE8,
+[ITEM_TRAIT_TYPE_WEAPON_INTRICATE] 		= SI_ITEMTRAITTYPE9,
+[ITEM_TRAIT_TYPE_WEAPON_ORNATE] 		= SI_ITEMTRAITTYPE10,
+[ITEM_TRAIT_TYPE_ARMOR_STURDY] 			= SI_ITEMTRAITTYPE11,
+[ITEM_TRAIT_TYPE_ARMOR_IMPENETRABLE] 	= SI_ITEMTRAITTYPE12,
+[ITEM_TRAIT_TYPE_ARMOR_REINFORCED] 		= SI_ITEMTRAITTYPE13,
+[ITEM_TRAIT_TYPE_ARMOR_WELL_FITTED] 	= SI_ITEMTRAITTYPE14,
+[ITEM_TRAIT_TYPE_ARMOR_TRAINING] 		= SI_ITEMTRAITTYPE15,
+[ITEM_TRAIT_TYPE_ARMOR_INFUSED] 		= SI_ITEMTRAITTYPE16,
+[ITEM_TRAIT_TYPE_ARMOR_EXPLORATION] 	= SI_ITEMTRAITTYPE17,
+[ITEM_TRAIT_TYPE_ARMOR_DIVINES] 		= SI_ITEMTRAITTYPE18,
+[ITEM_TRAIT_TYPE_ARMOR_ORNATE] 			= SI_ITEMTRAITTYPE19,
+[ITEM_TRAIT_TYPE_ARMOR_INTRICATE] 		= SI_ITEMTRAITTYPE20,
+[ITEM_TRAIT_TYPE_JEWELRY_HEALTHY] 		= SI_ITEMTRAITTYPE21,
+[ITEM_TRAIT_TYPE_JEWELRY_ARCANE] 		= SI_ITEMTRAITTYPE22,
+[ITEM_TRAIT_TYPE_JEWELRY_ROBUST] 		= SI_ITEMTRAITTYPE23,
+[ITEM_TRAIT_TYPE_JEWELRY_ORNATE] 		= SI_ITEMTRAITTYPE24,
+[ITEM_TRAIT_TYPE_ARMOR_NIRNHONED]		= SI_ITEMTRAITTYPE25,
+[ITEM_TRAIT_TYPE_WEAPON_NIRNHONED]		= SI_ITEMTRAITTYPE26,
+}
+
+
+local function parseItemLinkLevel(itemLink)
+	if itemLink == nil then return nil end
+
+	local vetRank = GetItemLinkRequiredVeteranRank(itemLink)
+	local reqLevel = GetItemLinkRequiredLevel(itemLink)
+
+	if not vetRank then
+		vetRank = 0
+	elseif not reqLevel then
+		reqLevel = 1
+	end
+
+	if vetRank > 0 then
+		return reqLevel, vetRank, zo_strformat(SI_ITEM_FORMAT_STR_LEVEL, reqLevel).." "..reqLevel, zo_strformat(SI_ITEM_FORMAT_STR_RANK, vetRank).." "..vetRank
+	else
+		return reqLevel, vetRank, zo_strformat(SI_ITEM_FORMAT_STR_LEVEL, reqLevel).." "..reqLevel, ""
+	end
+end
+
+local function parseItemLinkQuality(itemLink)
+	if not itemLink then return nil end
+	local iQuality = GetItemLinkQuality(itemLink)
+
+	return iQuality, zo_strformat(Str_Item_Quality[iQuality])
+end
+
+local function parseItemLinkSetItem(itemLink)
+	if not itemLink then return nil end
+	local iHasSet, setName = GetItemLinkSetInfo(itemLink)
+
+	if not iHasSet then iHasSet = 0 else iHasSet = 1 end
+
+	return iHasSet, zo_strformat(SI_ITEM_FORMAT_STR_SET_NAME, setName)
+end
+
+local function parseItemLinkTrait(itemLink)
+	if not itemLink then return nil end
+	local iTrait = select(1, GetItemLinkTraitInfo(itemLink))
+
+	return iTrait, zo_strformat(Str_Item_Trait[iTrait])
+end
+
+local function parseItemLinkToTable(itemLink)
+	if not itemLink then return nil end
+	local ParsedItemLink = {}
+
+	for val in string.gmatch(itemLink, "(%d-):") do
+		if val ~= "" then
+			table.insert(ParsedItemLink, val)
+		else
+			table.insert(ParsedItemLink, "item")
+		end
+	end
+
+	return ParsedItemLink
+end
+
+local function parseLinkValue(itemLink, place)
+	if not itemLink then return nil end
+	local LinkTable = parseItemLinkToTable(itemLink)
+
+	if (place <= 21 and place >= 1) then
+		local val = tonumber(LinkTable[place])
+		return val
+	else
+		return nil
+	end
+end
+
+local function getItemLinkFromSlotControl(slotControl)
+	local InventorySlot, ItemLink
+
+	if not slotControl.dataEntry then
+		InventorySlot = slotControl
+		return GetItemLink(InventorySlot.bagId, InventorySlot.slotIndex)
+
+	elseif slotControl.dataEntry then
+		InventorySlot = slotControl.dataEntry.data
+
+		if InventorySlot.bagId and
+		InventorySlot.slotIndex then
+			return GetItemLink(InventorySlot.bagId, InventorySlot.slotIndex)
+		else
+			return GetItemLink(InventorySlot.bag, InventorySlot.index)
+		end
+	else
+		return ""
+	end
+end
+
+local function getKeyedItem(itemLink)
+	local codex			= ddDataDaedra.dataCairn.codex
+	local PRICES		= ddDataDaedra.dataCairn.prices
+	local ItemId		= parseLinkValue(itemLink, 3)
+	local EnchtId		= parseLinkValue(itemLink, 6)
+	local Trait			= parseItemLinkTrait(itemLink)
+	local Level, VetRank = parseItemLinkLevel(itemLink)
+	local Quality		= parseItemLinkQuality(itemLink)
+
+	if PRICES[ItemId] then
+		if PRICES[ItemId][Trait] then
+			if PRICES[ItemId][Trait][Quality] then
+				if PRICES[ItemId][Trait][Quality][Level] then
+					if PRICES[ItemId][Trait][Quality][Level][VetRank] then
+						if PRICES[ItemId][Trait][Quality][Level][VetRank][EnchtId] then
+							return PRICES[ItemId][Trait][Quality][Level][VetRank][EnchtId]
+						end
+					end
+				end
+			end
+		end
+	end
+
+	return nil
+end
+
+local function isKeyedItem(itemLink)
+	local KeyedItem = getKeyedItem(itemLink)
+
+	if not KeyedItem then
+		return false
+	else
+		return true
+	end
+end
+
+local function pendListing()
+	local twAvgSalePrice = ddDataDaedra.dataCairn.codex.cwAvgSalePrice.getFunc()
+	local tSaveSalePrice = ddDataDaedra.dataCairn.codex.cSaveSalePrice.getFunc()
+	PostFunc(TRADING_HOUSE)
+
+	if TRADING_HOUSE.m_pendingItemSlot and
+	(twAvgSalePrice or tSaveSalePrice) then
+		local ItemLink 		= GetItemLink(BAG_BACKPACK, TRADING_HOUSE.m_pendingItemSlot)
+		local KeyedItem 	= getKeyedItem(ItemLink)
+		local Stack 		= select(2, GetItemInfo(BAG_BACKPACK, TRADING_HOUSE.m_pendingItemSlot)) or 1
+
+		if KeyedItem and
+		(twAvgSalePrice or tSaveSalePrice) then
+			if not KeyedItem.wAvg then KeyedItem.wAvg = 0 end
+			if not KeyedItem.PostPrice then KeyedItem.PostPrice = 0 end
+
+			if twAvgSalePrice and
+			KeyedItem.wAvg ~= 0 then
+				if tSaveSalePrice and
+				KeyedItem.PostPrice ~= 0 and
+				KeyedItem.PostPrice > KeyedItem.wAvg then
+					TRADING_HOUSE:SetPendingPostPrice(LIB_LOG:Round(KeyedItem.PostPrice * Stack))
+				else
+					TRADING_HOUSE:SetPendingPostPrice(LIB_LOG:Round(KeyedItem.wAvg * Stack))
+				end
+
+			elseif tSaveSalePrice and
+			KeyedItem.PostPrice ~= 0 then
+				TRADING_HOUSE:SetPendingPostPrice(LIB_LOG:Round(KeyedItem.PostPrice * Stack))
+			end
+		end
+	end
+end
+
+local function savePrice()
+	local CODEX				= ddDataDaedra.dataCairn.codex
+	local tSaveSalePrice	= CODEX.cSaveSalePrice.getFunc()
+	local itemLink 			= GetItemLink(BAG_BACKPACK, TRADING_HOUSE.m_pendingItemSlot)
+	local Stack 			= select(2, GetItemInfo(BAG_BACKPACK, TRADING_HOUSE.m_pendingItemSlot))
+	local KeyedItem			= getKeyedItem(itemLink)
+	local PostPrice 		= LIB_LOG:Round(LIB_LOG:RoundTo100s(TRADING_HOUSE.m_invoiceSellPrice.sellPrice / Stack))
+
+	if tSaveSalePrice then
+		if KeyedItem then
+			local wAvgPrice	= LIB_LOG:Round(LIB_LOG:RoundTo100s(KeyedItem.wAvg / Stack))
+
+			if wAvgPrice ~= PostPrice then
+				KeyedItem.PostPrice = PostPrice
+			end
+		else
+			local PRICES		= ddDataDaedra.dataCairn.prices
+			local ItemId		= parseLinkValue(itemLink, 3)
+			local EnchtId		= parseLinkValue(itemLink, 6)
+			local Trait			= parseItemLinkTrait(itemLink)
+			local Level, VetRank = parseItemLinkLevel(itemLink)
+			local Quality		= parseItemLinkQuality(itemLink)
+
+			Values = {
+				["Seen"] 		= 0,
+				["RawValue"] 	= 0,
+				["Weight"] 		= 0,
+				["wAvg"] 		= 0,
+				["PostPrice"]	= PostPrice,
+			}
+
+			if PRICES[ItemId] then
+				if PRICES[ItemId] then
+					if PRICES[ItemId][Trait] then
+						if PRICES[ItemId][Trait][Quality] then
+							if PRICES[ItemId][Trait][Quality][Level] then
+								if PRICES[ItemId][Trait][Quality][Level][VetRank] then
+									if not PRICES[ItemId][Trait][Quality][Level][VetRank][EnchtId] then
+										table.insert(PRICES[ItemId][Trait][Quality][Level][VetRank], EnchtId, Values)
+									end
+
+								end
+							end
+						end
+					end
+				end
+			end
+		end
+	end
+end
+
+--------------------------------------------------------------------------------------------------
+-------------------------------   Modular Controls by @Deome   -----------------------------------
+--																								--
+--						 ----  For LibAddonMenu 2.0 by Seerah  ----								--
+--				----   With gratitude and credit for this wonderful library   ----				--
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------------------------
+--			    -- Modular Controls allow even more customization for LAM2 --					--
+--					        -- (which already offers so much!) --								--
+--		  -- and make plugins, updates, and common settings simple for everyone --				--
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+------------------------------------   LAM2 Panel Layout   ---------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function ddDataDaedra:mControls()
+	local CODEX = self.dataCairn.codex
+	local menu = {
+		CODEX.cNotify:init(),
+		CODEX.cDebug:init(),
+--		CODEX.cResetButton:init(),
+		CODEX.cInterval:init(),
+		CODEX.cwAvgSalePrice:init(),
+		CODEX.cSaveSalePrice:init(),
+		CODEX.cTooltipFontHeader:init(),
+		CODEX.cTooltipFontBody:init(),
+	}
+	return menu
+end
+
+function ddDataDaedra:mPanel()
+	local Panel = {
+		type = "panel",
+		name = GetString(DD_TASKMASTER_NAME),
+		displayName = GetString(DD_TASKMASTER_DISPLAYNAME),
+		author = GetString(DD_TASKMASTER_AUTHOR),
+		version = self.version,
+		registerForRefresh = true,
+		registerForDefaults = true,
+	}
+	return Panel
+end
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------   LAM2 Modular Controls   -------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function CODEX:init()																					-- Initializes all controls so that they're fully set up and ready to use,
+	self.cInterval:init()																				-- regardless of whether they're displayed or active.
+--	self.cResetButton:init()
+--	self.cTooltipQuality:init()
+	self.cDebug:init()
+	self.cNotify:init()
+	self.cSaveSalePrice:init()
+	self.cwAvgSalePrice:init()
+	self.cTooltipFontHeader:init()
+	self.cTooltipFontBody:init()
+
+end
+
+function CODEX.cNotify:init()
+	self.type = "checkbox"
+	self.name = GetString(DD_TASKMASTER_NOTIFICATIONS_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_NOTIFICATIONS_TIP)
+	self.width = "full"
+
+	self.default = true
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) self.value = value end
+	return self
+end
+
+function CODEX.cDebug:init()
+	self.type = "checkbox"
+	self.name = GetString(DD_TASKMASTER_DEBUG_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_DEBUG_TIP)
+	self.width = "full"
+
+	self.default = false
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) self.value = value end
+	return self
+end
+
+function CODEX.cInterval:init()
+	self.type = "slider"
+	self.name = GetString(DD_TASKMASTER_INTERVAL_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_INTERVAL_TIP)
+	self.width = "full"
+
+	self.min = 1
+	self.max = 10
+	self.step = 1
+	self.default = 3
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) EVENT_MANAGER:UnregisterForUpdate(ddDataDaedra.name)
+		self.value = value
+		EVENT_MANAGER:RegisterForUpdate(ddDataDaedra.name, (self.value * 60 * 1000), function() ddDataDaedra:twilightSummons() end)
+	end
+	return self
+end
+
+function CODEX.cSaveSalePrice:init()
+	self.type = "checkbox"
+	self.name = GetString(DD_TASKMASTER_SAVE_SALE_PRICE_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_SAVE_SALE_PRICE_TIP)
+	self.width = "full"
+
+	self.default = false
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) self.value = value end
+	return self
+end
+
+function CODEX.cwAvgSalePrice:init()
+	self.type = "checkbox"
+	self.name = GetString(DD_TASKMASTER_WAVG_SALE_PRICE_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_WAVG_SALE_PRICE_TIP)
+	self.width = "full"
+
+	self.default = true
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) self.value = value end
+	return self
+end
+
+function CODEX.cTooltipFontHeader:init()
+	self.type = "dropdown"
+	self.name = GetString(DD_TASKMASTER_TOOLTIP_HEADER_FONT_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_TOOLTIP_HEADER_FONT_TIP)
+	self.width = "full"
+
+	self.choices = fonts
+	self.default = fonts[1]
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) self.value = value end
+	return self
+end
+
+function CODEX.cTooltipFontBody:init()
+	self.type = "dropdown"
+	self.name = GetString(DD_TASKMASTER_TOOLTIP_BODY_FONT_NAME)
+	self.tooltip = GetString(DD_TASKMASTER_TOOLTIP_BODY_FONT_TIP)
+	self.width = "full"
+
+	self.choices = fonts
+	self.default = fonts[2]
+	self.getFunc = function() if self.value == nil then self.value = self.default end return self.value end
+	self.setFunc = function(value) self.value = value end
+	return self
+end
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   Key Bindings   ----------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   UI Bindings   -----------------------------------------
+--------------------------------------------------------------------------------------------------
+
+function ddDataDaedra:seenToStr(seen)
+	local LowSeen		= 25
+	local HighSeen		= 100
+	local Str_SeenColor = "|cFF0000"
+
+	if seen > LowSeen and
+	seen < HighSeen then
+		Str_SeenColor = "|cFFFF00"
+	elseif seen >= HighSeen then
+		Str_SeenColor = "|c00FF00"
+	end
+
+	return zo_strformat(GetString(DD_TOOLTIP_STAT_SEEN), Str_SeenColor, ZO_CommaDelimitNumber(seen), zo_iconFormat("esoui/art/miscellaneous/search_icon.dds", 32, 32))
+end
+
+function ddDataDaedra:wAvgToStr(wAvg)
+	return zo_strformat(GetString(DD_TOOLTIP_STAT_WAVG), ZO_CommaDelimitNumber(LIB_LOG:Round(wAvg)), zo_iconFormat("esoui/art/currency/currency_gold.dds", 18, 18))
+end
+
+function ddDataDaedra:stackToStr(wAvg, stack)
+	return zo_strformat(GetString(DD_TOOLTIP_STAT_STACK), ZO_CommaDelimitNumber(LIB_LOG:Round(wAvg * stack)), zo_iconFormat("esoui/art/currency/currency_gold.dds", 18, 18), stack)
+end
+
+function ddDataDaedra:resizeSigil(tooltip, label)
+	local DimDefault 	= 416
+	local Pad1, Pad2	= tooltip:GetResizeToFitPadding()
+	local labelWidth	= label:GetTextWidth()
+
+	if (labelWidth + Pad1) > DimDefault then
+		local NewDim = Pad1 + labelWidth
+		tooltip:SetDimensionConstraints(NewDim, -1, NewDim, -1)
+	else
+		tooltip:SetDimensionConstraints(DimDefault, -1, DimDefault, -1)
+	end
+end
+
+function ddDataDaedra:createItemSigil(tooltip, keyedItem, stack)
+	if not tooltip.labelPool then
+        tooltip.labelPool = ZO_ControlPool:New("ZO_TooltipLabel", tooltip, "Label")
+    end
+	if not stack or stack < 2 then stack = 1 end
+	local FontHeader		= self.dataCairn.codex.cTooltipFontHeader.getFunc()
+	local FontBody			= self.dataCairn.codex.cTooltipFontBody.getFunc()
+	local SigilHeader 		= tooltip.labelPool:AcquireObject()
+    local SigilLabel 		= tooltip.labelPool:AcquireObject()
+	local BulletIcon		= zo_iconFormat(GetString(DD_ICON_BULLET), 12, 12)
+	local Str_Buffer 		= " "..BulletIcon.." "
+	local Str_Seen			= self:seenToStr(keyedItem.Seen)
+	local Str_wAvg			= self:wAvgToStr(keyedItem.wAvg)
+	local Str_Stack			= self:stackToStr(keyedItem.wAvg, stack)
+	local Str_Sigil			= Str_Seen..Str_Buffer..Str_wAvg
+
+	if stack > 1 then
+		Str_Sigil = Str_Sigil..Str_Buffer..Str_Stack
+	end
+
+	tooltip:AddVerticalPadding(20)
+	ZO_Tooltip_AddDivider(tooltip)
+
+	tooltip:AddControl(SigilHeader)
+	SigilHeader:SetAnchor(CENTER)
+	SigilHeader:SetHorizontalAlignment(CENTER)
+	SigilHeader:SetFont(FontHeader)
+	SigilHeader:SetModifyTextType(MODIFY_TEXT_TYPE_NONE)
+	SigilHeader:SetColor(ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB())
+	SigilHeader:SetText(GetString(DD_TOOLTIP_HEADER))
+
+	tooltip:AddControl(SigilLabel)
+	SigilLabel:SetAnchor(CENTER)
+	SigilLabel:SetHorizontalAlignment(CENTER)
+	SigilLabel:SetFont(FontBody)
+	SigilLabel:SetModifyTextType(MODIFY_TEXT_TYPE_NONE)
+	SigilLabel:SetColor(ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB())
+	SigilLabel:SetText(Str_Sigil)
+	self:resizeSigil(tooltip, SigilLabel)
+end
+
+function ddDataDaedra:createMiserSigil(tooltip, str_TotalCost)
+	if not tooltip.labelPool then
+        tooltip.labelPool = ZO_ControlPool:New("ZO_TooltipLabel", tooltip, "Label")
+    end
+
+	local FontHeader	= self.dataCairn.codex.cTooltipFontHeader.getFunc()
+	local FontBody		= self.dataCairn.codex.cTooltipFontBody.getFunc()
+	local MiserHeader 	= tooltip.labelPool:AcquireObject()
+    local MiserLabel 	= tooltip.labelPool:AcquireObject()
+
+	tooltip:AddVerticalPadding(20)
+
+	tooltip:AddControl(MiserHeader)
+	MiserHeader:SetAnchor(CENTER)
+	MiserHeader:SetHorizontalAlignment(CENTER)
+	MiserHeader:SetFont(FontHeader)
+	MiserHeader:SetModifyTextType(MODIFY_TEXT_TYPE_NONE)
+	MiserHeader:SetColor(ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB())
+	MiserHeader:SetText(GetString(DD_TOOLTIP_CRAFTING_HEADER))
+
+	tooltip:AddControl(MiserLabel)
+	MiserLabel:SetAnchor(CENTER)
+	MiserLabel:SetHorizontalAlignment(CENTER)
+	MiserLabel:SetFont(FontBody)
+	MiserLabel:SetModifyTextType(MODIFY_TEXT_TYPE_NONE)
+	MiserLabel:SetColor(ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB())
+	MiserLabel:SetText(str_TotalCost)
+	self:resizeSigil(tooltip, MiserLabel)
+end
+
+function ddDataDaedra:inscribePopupSigilstone(tooltip)
+	if tooltip == PopupControl then return end
+	PopupControl = tooltip
+
+	local ResultKeyedItem 	= getKeyedItem(PopupControl.lastLink)
+
+	if ResultKeyedItem and
+	ResultKeyedItem.wAvg and
+	ResultKeyedItem.Seen and
+	ResultKeyedItem.wAvg > 0 and
+	ResultKeyedItem.Seen > 0 then
+		self:createItemSigil(tooltip, ResultKeyedItem)
+	end
+end
+
+function ddDataDaedra:inscribeItemSigilstone(tooltip, itemLink, stack)
+	if not tooltip or
+	not itemLink or
+	itemLink == "" then
+		return
+
+	elseif not stack or
+	stack < 2 then
+		stack = 1
+	end
+
+	local ResultKeyedItem = getKeyedItem(itemLink)
+
+	if ResultKeyedItem and
+	ResultKeyedItem.wAvg and
+	ResultKeyedItem.Seen and
+	ResultKeyedItem.wAvg > 0 and
+	ResultKeyedItem.Seen > 0 then
+		self:createItemSigil(tooltip, ResultKeyedItem, stack)
+	end
+end
+
+function ddDataDaedra:inscribeCraftSigilstone(tooltip, resultLink, resultStack, str_TotalCost)
+	if not tooltip then return end
+	local ResultKeyedItem = getKeyedItem(resultLink)
+
+	if not resultStack or
+	resultStack < 2 then
+		resultStack = 1
+	end
+
+	if ResultKeyedItem and
+	ResultKeyedItem.wAvg and
+	ResultKeyedItem.Seen and
+	ResultKeyedItem.wAvg > 0 and
+	ResultKeyedItem.Seen > 0 then
+		self:createItemSigil(tooltip, ResultKeyedItem, resultStack)
+	end
+
+	self:createMiserSigil(tooltip, str_TotalCost)
+end
+
+function ddDataDaedra:alchemySigil(self, tooltip)
+	if not tooltip or
+	tooltip == ResultControl then
+		return
+	end
+	ResultControl = tooltip
+	craftingStation = ALCHEMY
+
+	local SolventBagId = craftingStation.solventSlot.bagId
+	local SolventSlotIndex = craftingStation.solventSlot.slotIndex
+	local SolventItemLink = GetItemLink(SolventBagId, SolventSlotIndex, LINK_STYLE_BRACKETS)
+	local SolventIcon = zo_iconFormat(GetItemLinkInfo(SolventItemLink), 28, 28)
+	local SolventKeyedItem = getKeyedItem(SolventItemLink)
+	local SolventCost = 0
+
+	if SolventKeyedItem and
+	SolventKeyedItem.wAvg and
+	SolventKeyedItem.wAvg > 0 then
+		SolventCost = SolventKeyedItem.wAvg
+	end
+
+	local Reagent1BagId	= craftingStation.reagentSlots[1].bagId
+	local Reagent1SlotIndex = craftingStation.reagentSlots[1].slotIndex
+	local Reagent1ItemLink = GetItemLink(Reagent1BagId, Reagent1SlotIndex, LINK_STYLE_BRACKETS)
+	local Reagent1Icon = zo_iconFormat(GetItemLinkInfo(Reagent1ItemLink), 28, 28)
+	local Reagent1KeyedItem = getKeyedItem(Reagent1ItemLink)
+	local Reagent1Cost = 0
+
+	if Reagent1KeyedItem and
+	Reagent1KeyedItem.wAvg and
+	Reagent1KeyedItem.wAvg > 0 then
+		Reagent1Cost = Reagent1KeyedItem.wAvg
+	end
+
+	local Reagent2BagId = craftingStation.reagentSlots[2].bagId
+	local Reagent2SlotIndex = craftingStation.reagentSlots[2].slotIndex
+	local Reagent2ItemLink = GetItemLink(Reagent2BagId, Reagent2SlotIndex, LINK_STYLE_BRACKETS)
+	local Reagent2Icon = zo_iconFormat(GetItemLinkInfo(Reagent2ItemLink), 28, 28)
+	local Reagent2KeyedItem = getKeyedItem(Reagent2ItemLink)
+	local Reagent2Cost = 0
+
+	if Reagent2KeyedItem and
+	Reagent2KeyedItem.wAvg and
+	Reagent2KeyedItem.wAvg > 0 then
+		Reagent2Cost = Reagent2KeyedItem.wAvg
+	end
+
+	local Reagent3BagId = craftingStation.reagentSlots[3].bagId
+	local Reagent3SlotIndex = craftingStation.reagentSlots[3].slotIndex
+	local Reagent3ItemLink = GetItemLink(Reagent3BagId, Reagent3SlotIndex, LINK_STYLE_BRACKETS)
+	local Reagent3Icon = zo_iconFormat(GetItemLinkInfo(Reagent3ItemLink), 28, 28)
+	local Reagent3KeyedItem = getKeyedItem(Reagent3ItemLink)
+	local Reagent3Cost = 0
+
+	if Reagent3KeyedItem and
+	Reagent3KeyedItem.wAvg and
+	Reagent3KeyedItem.wAvg > 0 then
+		Reagent3Cost = Reagent3KeyedItem.wAvg
+	end
+
+	local PotionLink = GetAlchemyResultingItemLink(SolventBagId, SolventSlotIndex, Reagent1BagId, Reagent1SlotIndex, Reagent2BagId, Reagent2SlotIndex, Reagent3BagId, Reagent3SlotIndex, LINK_STYLE_BRACKETS)
+	local PotionCount = select(3, GetAlchemyResultingItemInfo(SolventBagId, SolventSlotIndex, Reagent1BagId, Reagent1SlotIndex, Reagent2BagId, Reagent2SlotIndex, Reagent3BagId, Reagent3SlotIndex, LINK_STYLE_BRACKETS))
+	local TotalCost = LIB_LOG:Round(SolventCost + Reagent1Cost + Reagent2Cost + Reagent3Cost)
+
+	if TotalCost ~= 0 then
+		local Str_TotalReagentCost = ""
+		local Str_Buffer = " "
+		local GoldIcon = zo_iconFormat(GetString(DD_ICON_GOLD), 20, 20)
+		local PlusIcon = zo_iconFormat("esoui/art/progression/addpoints_up.dds", 32, 32)
+		local EqualsIcon = zo_iconFormat("/esoui/art/progression/progression_tabicon_passive_inactive.dds", 32, 32)
+		local Str_TotalCost = zo_strformat(GetString(DD_TOOLTIP_CRAFTING_WAVG), ZO_CommaDelimitNumber(TotalCost), GoldIcon)
+
+		if SolventCost > 0 and
+		Reagent1Cost > 0 then
+			Str_TotalReagentCost = SolventIcon..Str_Buffer..PlusIcon..Str_Buffer..Reagent1Icon
+
+			if Reagent2Cost > 0 then
+				Str_TotalReagentCost = Str_TotalReagentCost..Str_Buffer..PlusIcon..Str_Buffer..Reagent2Icon
+			end
+			if Reagent3Cost > 0 then
+				Str_TotalReagentCost = Str_TotalReagentCost..Str_Buffer..PlusIcon..Str_Buffer..Reagent3Icon
+			end
+
+			Str_TotalReagentCost = Str_TotalReagentCost..EqualsIcon..Str_Buffer..Str_TotalCost
+		end
+
+		self:inscribeCraftSigilstone(tooltip, PotionLink, PotionCount, Str_TotalReagentCost)
+	end
+end
+
+function ddDataDaedra:provisionerSigil(self, tooltip)
+	if not tooltip or
+	tooltip == ResultControl then
+		return
+	end
+	ResultControl = tooltip
+	craftingStation = PROVISIONER
+
+	local RecipeListIndex = craftingStation:GetSelectedRecipeListIndex()
+	local RecipeIndex = craftingStation:GetSelectedRecipeIndex()
+	local RecipeLink = GetRecipeResultItemLink(RecipeListIndex, RecipeIndex, LINK_STYLE_BRACKETS)
+	local RecipeCount = select(3, GetRecipeResultItemInfo(RecipeListIndex, RecipeIndex))
+
+	local MatIndex1 = craftingStation.ingredientRows[1].control.ingredientIndex
+	local MatLink1, MatIcon1, MatKeyedItem1
+	local MatCost1 = 0
+
+	if MatIndex1 then
+		MatLink1 = GetRecipeIngredientItemLink(RecipeListIndex, RecipeIndex, MatIndex1, LINK_STYLE_BRACKETS)
+		MatIcon1 = zo_iconFormat(select(2, GetRecipeIngredientItemInfo(RecipeListIndex, RecipeIndex, MatIndex1)), 28, 28)
+		MatKeyedItem1 = getKeyedItem(MatLink1)
+		MatCost1 = 0
+
+		if MatKeyedItem1 and
+		MatKeyedItem1.wAvg ~= 0 then
+			MatCost1 = MatKeyedItem1.wAvg
+		end
+	end
+
+	local MatIndex2 = craftingStation.ingredientRows[2].control.ingredientIndex
+	local MatLink2, MatIcon2, MatKeyedItem2
+	local MatCost2 = 0
+
+	if MatIndex2 then
+		MatLink2 = GetRecipeIngredientItemLink(RecipeListIndex, RecipeIndex, MatIndex2, LINK_STYLE_BRACKETS)
+		MatIcon2 = zo_iconFormat(select(2, GetRecipeIngredientItemInfo(RecipeListIndex, RecipeIndex, MatIndex2)), 28, 28)
+		MatKeyedItem2 = getKeyedItem(MatLink2)
+		MatCost2 = 0
+
+		if MatKeyedItem2 and
+		MatKeyedItem2.wAvg ~= 0 then
+			MatCost2 = MatKeyedItem2.wAvg
+		end
+	end
+
+	local MatIndex3 = craftingStation.ingredientRows[3].control.ingredientIndex
+	local MatLink3, MatIcon3, MatKeyedItem3
+	local MatCost3 = 0
+
+	if MatIndex3 then
+		MatLink3 = GetRecipeIngredientItemLink(RecipeListIndex, RecipeIndex, MatIndex3, LINK_STYLE_BRACKETS)
+		MatIcon3 = zo_iconFormat(select(2, GetRecipeIngredientItemInfo(RecipeListIndex, RecipeIndex, MatIndex3)), 28, 28)
+		MatKeyedItem3 = getKeyedItem(MatLink3)
+		MatCost3 = 0
+
+		if MatKeyedItem3 and
+		MatKeyedItem3.wAvg ~= 0 then
+			MatCost3 = MatKeyedItem3.wAvg
+		end
+	end
+
+	local MatIndex4 = craftingStation.ingredientRows[4].control.ingredientIndex
+	local MatLink4, MatIcon4, MatKeyedItem4
+	local MatCost4 = 0
+
+	if MatIndex4 then
+		MatLink4 = GetRecipeIngredientItemLink(RecipeListIndex, RecipeIndex, MatIndex4, LINK_STYLE_BRACKETS)
+		MatIcon4 = zo_iconFormat(select(2, GetRecipeIngredientItemInfo(RecipeListIndex, RecipeIndex, MatIndex4)), 28, 28)
+		MatKeyedItem4 = getKeyedItem(MatLink4)
+		MatCost4 = 0
+
+		if MatKeyedItem4 and
+		MatKeyedItem4.wAvg ~= 0 then
+			MatCost4 = MatKeyedItem4.wAvg
+		end
+	end
+
+	local MatIndex5 = craftingStation.ingredientRows[5].control.ingredientIndex
+	local MatLink5, MatIcon5, MatKeyedItem5
+	local MatCost5 = 0
+
+	if MatIndex5 then
+		MatLink5 = GetRecipeIngredientItemLink(RecipeListIndex, RecipeIndex, MatIndex5, LINK_STYLE_BRACKETS)
+		MatIcon5 = zo_iconFormat(select(2, GetRecipeIngredientItemInfo(RecipeListIndex, RecipeIndex, MatIndex5)), 28, 28)
+		MatKeyedItem5 = getKeyedItem(MatLink5)
+		MatCost5 = 0
+
+		if MatKeyedItem5 and
+		MatKeyedItem5.wAvg ~= 0 then
+			MatCost5 = MatKeyedItem5.wAvg
+		end
+	end
+
+	local TotalCost = LIB_LOG:Round(MatCost1 + MatCost2 + MatCost3 + MatCost4 + MatCost5)
+
+	if TotalCost ~= 0 then
+		local Str_TotalIngredientCost = ""
+		local Str_Buffer = " "
+		local GoldIcon = zo_iconFormat("esoui/art/currency/currency_gold.dds", 20, 20)
+		local PlusIcon = zo_iconFormat("esoui/art/progression/addpoints_up.dds", 32, 32)
+		local EqualsIcon = zo_iconFormat("/esoui/art/progression/progression_tabicon_passive_inactive.dds", 32, 32)
+		local Str_TotalCost = zo_strformat(GetString(DD_TOOLTIP_CRAFTING_WAVG), ZO_CommaDelimitNumber(TotalCost), GoldIcon)
+
+		if MatCost1 > 0 then
+			Str_TotalIngredientCost = MatIcon1
+		end
+		if MatCost2 > 0 then
+			Str_TotalIngredientCost = Str_TotalIngredientCost..Str_Buffer..PlusIcon..Str_Buffer..MatIcon2
+		end
+		if MatCost3 > 0 then
+			Str_TotalIngredientCost = Str_TotalIngredientCost..Str_Buffer..PlusIcon..Str_Buffer..MatIcon3
+		end
+		if MatCost4 > 0 then
+			Str_TotalIngredientCost = Str_TotalIngredientCost..Str_Buffer..PlusIcon..Str_Buffer..MatIcon4
+		end
+		if MatCost5 > 0 then
+			Str_TotalIngredientCost = Str_TotalIngredientCost..Str_Buffer..PlusIcon..Str_Buffer..MatIcon5
+		end
+		Str_TotalIngredientCost = Str_TotalIngredientCost..Str_Buffer..EqualsIcon..Str_Buffer..Str_TotalCost
+
+		self:inscribeCraftSigilstone(tooltip, RecipeLink, RecipeCount, Str_TotalIngredientCost)
+	end
+end
+
+function ddDataDaedra:enchantingSigil(self, tooltip)
+	if not tooltip or
+	tooltip == ResultControl then
+		return
+	end
+	ResultControl = tooltip
+	craftingStation = ENCHANTING
+
+	local EnchantingResultItemLink = GetEnchantingResultingItemLink(craftingStation:GetAllCraftingBagAndSlots())
+
+	local RunePotencySlot = ZO_EnchantingTopLevelRuneSlotContainerPotencyRune
+	local RunePotencyItemLink = GetItemLink(craftingStation.runeSlots[1]:GetBagAndSlot())
+	local RunePotencyKeyedItem = getKeyedItem(RunePotencyItemLink)
+	local RunePotencyIcon = zo_iconFormat(GetItemInfo(craftingStation.runeSlots[3]:GetBagAndSlot()), 28, 28)
+	local RunePotencyCost = 0
+	local RunePotencyName = GetItemLinkEnchantingRuneName(RunePotencyItemLink)
+
+	if RunePotencyKeyedItem and
+	RunePotencyKeyedItem.wAvg ~= 0 then
+		RunePotencyCost = RunePotencyKeyedItem.wAvg
+	end
+
+	local RuneEssenceSlot = ZO_EnchantingTopLevelRuneSlotContainerEssenceRune
+	local RuneEssenceItemLink = GetItemLink(RuneEssenceSlot.bagId, RuneEssenceSlot.slotIndex)
+	local RuneEssenceKeyedItem = getKeyedItem(RuneEssenceItemLink)
+	local RuneEssenceIcon = zo_iconFormat(GetItemInfo(RuneEssenceSlot.bagId, RuneEssenceSlot.slotIndex), 28, 28)
+	local RuneEssenceCost = 0
+	local RuneEssenceName = GetItemLinkEnchantingRuneName(RuneEssenceItemLink)
+
+	if RuneEssenceKeyedItem and
+	RuneEssenceKeyedItem.wAvg ~= 0 then
+		RuneEssenceCost = RuneEssenceKeyedItem.wAvg
+	end
+
+	local RuneAspectSlot = ZO_EnchantingTopLevelRuneSlotContainerAspectRune
+	local RuneAspectItemLink = GetItemLink(RuneAspectSlot.bagId, RuneAspectSlot.slotIndex)
+	local RuneAspectKeyedItem = getKeyedItem(RuneAspectItemLink)
+	local RuneAspectIcon = zo_iconFormat(GetItemInfo(RuneAspectSlot.bagId, RuneAspectSlot.slotIndex), 28, 28)
+	local RuneAspectCost = 0
+	local RuneAspectName = GetItemLinkEnchantingRuneName(RuneAspectItemLink)
+
+	if RuneAspectKeyedItem and
+	RuneAspectKeyedItem.wAvg ~= 0 then
+		RuneAspectCost = RuneAspectKeyedItem.wAvg
+	end
+
+	local TotalCost = LIB_LOG:Round(RunePotencyCost + RuneEssenceCost + RuneAspectCost)
+
+	if TotalCost ~= 0 then
+		local Str_TotaGlyphCost = ""
+		local Str_Buffer = " "
+		local GoldIcon = zo_iconFormat("esoui/art/currency/currency_gold.dds", 20, 20)
+		local PlusIcon = zo_iconFormat("esoui/art/progression/addpoints_up.dds", 32, 32)
+		local EqualsIcon = zo_iconFormat("/esoui/art/progression/progression_tabicon_passive_inactive.dds", 32, 32)
+		local Str_TotalCost = zo_strformat(GetString(DD_TOOLTIP_CRAFTING_WAVG), ZO_CommaDelimitNumber(TotalCost), GoldIcon)
+		Str_TotaGlyphCost = RunePotencyIcon..Str_Buffer..PlusIcon..Str_Buffer..RuneEssenceIcon
+		Str_TotaGlyphCost = Str_TotaGlyphCost..Str_Buffer..PlusIcon..Str_Buffer..RuneAspectIcon
+		Str_TotaGlyphCost = Str_TotaGlyphCost..Str_Buffer..EqualsIcon..Str_Buffer..Str_TotalCost
+
+		self:inscribeCraftSigilstone(tooltip, EnchantingResultItemLink, 1, Str_TotaGlyphCost)
+	end
+end
+
+function ddDataDaedra:improvementSigil(self, tooltip)
+	if not tooltip or
+	tooltip == ResultControl then
+		return
+	end
+	ResultControl = tooltip
+	local Panel = SMITHING.improvementPanel
+
+	local ImproveResultItemLink = GetSmithingImprovedItemLink(Panel:GetCurrentImprovementParams(), LINK_STYLE_BRACKETS)
+	local BoosterLink = GetSmithingImprovementItemLink(GetCraftingInteractionType(), Panel.boosterSlot.index, LINK_STYLE_BRACKETS)
+
+	local BoosterKeyedItem = getKeyedItem(BoosterLink)
+	local BoosterCount = Panel.spinner.value
+	local BoosterCost = 0
+
+	if BoosterKeyedItem and
+	BoosterKeyedItem.wAvg ~= 0 then
+		BoosterCost = BoosterKeyedItem.wAvg * BoosterCount
+	end
+
+	local TotalCost = LIB_LOG:Round(BoosterCost)
+
+	if TotalCost ~= 0 then
+		local Str_TotalImprovementCost = ""
+		local Str_Buffer = " "
+		local GoldIcon = zo_iconFormat("esoui/art/currency/currency_gold.dds", 20, 20)
+		local PlusIcon = zo_iconFormat("esoui/art/progression/addpoints_up.dds", 32, 32)
+		local EqualsIcon = zo_iconFormat("/esoui/art/progression/progression_tabicon_passive_inactive.dds", 32, 32)
+		local Str_TotalCost = zo_strformat(GetString(DD_TOOLTIP_CRAFTING_WAVG), ZO_CommaDelimitNumber(TotalCost), GoldIcon)
+		local BoosterIcon = BoosterCount..zo_iconFormat(ZO_SmithingTopLevelImprovementPanelSlotContainerBoosterSlotIcon:GetTextureFileName(), 28, 28)
+		Str_TotalImprovementCost = BoosterIcon..Str_Buffer..EqualsIcon..Str_Buffer..Str_TotalCost
+
+		ZO_SmithingTopLevelImprovementPanelResultTooltip:SetHidden(false)
+		ZO_SmithingTopLevelImprovementPanelResultTooltip:ClearLines()
+		Panel:SetupResultTooltip(Panel:GetCurrentImprovementParams())
+		self:inscribeCraftSigilstone(tooltip, ImproveResultItemLink, 1, Str_TotalImprovementCost)
+	end
+end
+
+function ddDataDaedra:creationSigil(self, tooltip)
+	if not tooltip or
+	tooltip == ResultControl then
+		return
+	end
+	ResultControl = tooltip
+
+	local Panel = SMITHING.creationPanel
+	local MatList = Panel.materialList.selectedData
+	local MatCount = Panel.materialQuantitySpinner.value
+	local StyleList = Panel.styleList.selectedData
+	local TraitList = Panel.traitList.selectedData
+
+
+	local MatItemLink = GetSmithingPatternMaterialItemLink(MatList.patternIndex, MatList.materialIndex, LINK_STYLE_BRACKETS)
+	local MatKeyedItem = getKeyedItem(MatItemLink)
+	local MatCost = 0
+
+	if MatKeyedItem and
+	MatKeyedItem.wAvg ~= 0 then
+		MatCost = MatKeyedItem.wAvg * MatCount
+	end
+
+	local StyleItemLink = GetSmithingStyleItemLink(StyleList.styleIndex, LINK_STYLE_BRACKETS)
+	local StyleKeyedItem = getKeyedItem(StyleItemLink)
+	local StyleCost = 0
+
+	if StyleKeyedItem and
+	StyleKeyedItem.wAvg ~= 0 then
+		StyleCost = StyleKeyedItem.wAvg
+	end
+
+	local TraitItemLink = GetSmithingTraitItemLink(TraitList.traitIndex, LINK_STYLE_BRACKETS)
+	local TraitKeyedItem = getKeyedItem(TraitItemLink)
+	local TraitCost = 0
+
+	if TraitKeyedItem and
+	TraitKeyedItem.wAvg ~= 0 then
+		TraitCost = TraitKeyedItem.wAvg
+	end
+
+	local ResultItemLink = GetSmithingPatternResultLink(MatList.patternIndex, MatList.materialIndex, MatCount, StyleList.styleIndex, TraitList.traitIndex, LINK_STYLE_BRACKETS)
+	local TotalCost = LIB_LOG:Round(MatCost + StyleCost + TraitCost)
+
+	if TotalCost ~= 0 then
+		local Str_TotalSmithingCost = ""
+		local Str_Buffer = " "
+		local MatIcon = MatCount..zo_iconFormat(MatList.icon, 28, 28)
+		local StyleIcon = zo_iconFormat(StyleList.icon, 28, 28)
+		local TraitIcon = zo_iconFormat(TraitList.icon, 28, 28)
+		local GoldIcon = zo_iconFormat("esoui/art/currency/currency_gold.dds", 20, 20)
+		local PlusIcon = zo_iconFormat("esoui/art/progression/addpoints_up.dds", 32, 32)
+		local EqualsIcon = zo_iconFormat("/esoui/art/progression/progression_tabicon_passive_inactive.dds", 32, 32)
+		local Str_TotalCost = zo_strformat(GetString(DD_TOOLTIP_CRAFTING_WAVG), ZO_CommaDelimitNumber(TotalCost), GoldIcon)
+		Str_TotalSmithingCost = MatIcon..Str_Buffer..PlusIcon..Str_Buffer..StyleIcon
+
+		if TraitCost ~= 0 then
+			Str_TotalSmithingCost = Str_TotalSmithingCost..Str_Buffer..PlusIcon..Str_Buffer..TraitIcon
+		end
+
+		Str_TotalSmithingCost = Str_TotalSmithingCost..Str_Buffer..EqualsIcon..Str_Buffer..Str_TotalCost
+
+		self:inscribeCraftSigilstone(tooltip, ResultItemLink, 1, Str_TotalSmithingCost)
+	end
+end
+
+function ddDataDaedra:sigilDesign(tooltip)
+	local MoC = moc()
+	local TH = TRADING_HOUSE
+
+	if not tooltip or
+	not MoC.dataEntry or
+	not MoC.dataEntry.data or
+	tooltip == TooltipControl then
+		return
+	end
+
+	TooltipControl = tooltip
+	local Row = MoC.dataEntry.data
+	local Index = Row.slotIndex
+	local Stack = Row.stackCount
+	local ItemLink
+
+	if not tooltip or
+	tooltip:GetOwningWindow():GetName() == "ZO_SmithingTopLevelCreationPanel" or
+	tooltip:GetOwningWindow():GetName() == "ZO_ListDialog1" or
+	tooltip:GetOwningWindow():GetName() == "ZO_InteractWindow" or		-- GetQuestRewardItemLink
+	tooltip:GetOwningWindow():GetName() == "ZO_QuickSlotCircle" or
+	tooltip:GetOwningWindow():GetName() == "ZO_StablePanel" then
+		return
+	end
+
+	if Row then
+		if Row.lootId then
+			ItemLink = GetLootItemLink(Row.lootId)
+			Stack = Row.count
+			self:inscribeItemSigilstone(tooltip, ItemLink, Stack)
+			return
+
+		elseif Row.index then
+			if Row.craftingType then
+				ItemLink = GetSmithingImprovementItemLink(Row.craftingType, Row.index)
+			elseif tooltip:GetOwningWindow():GetName() == "ZO_StoreWindow" then
+				ItemLink = GetStoreItemLink(Row.index)
+			elseif tooltip:GetOwningWindow():GetName() == "ZO_BuyBack" then
+				ItemLink = GetBuybackItemLink(Row.index)
+			elseif tooltip:GetOwningWindow():GetName() == "ZO_QuestReward" then
+				ItemLink = GetQuestRewardItemLink(Row.index)
+			end
+
+			self:inscribeItemSigilstone(tooltip, ItemLink, 1)
+			return
+
+		elseif TRADING_HOUSE:IsAtTradingHouse() and
+		TH:IsInSearchMode() and
+		Row.timeRemaining and
+		Row.timeRemaining > 0 then
+			ItemLink = GetTradingHouseSearchResultItemLink(Row.slotIndex)
+			self:inscribeItemSigilstone(tooltip, ItemLink, Stack)
+			return
+
+		elseif TRADING_HOUSE:IsAtTradingHouse() and
+		Row.bagId then
+			ItemLink = GetItemLink(Row.bagId, Row.slotIndex)
+			self:inscribeItemSigilstone(tooltip, ItemLink, Stack)
+			return
+
+		elseif TRADING_HOUSE:IsAtTradingHouse() and
+		TH:IsInListingsMode() then
+			ItemLink = GetTradingHouseListingItemLink(Row.slotIndex)
+			self:inscribeItemSigilstone(tooltip, ItemLink, Stack)
+			return
+
+		elseif Row.bagId then
+			ItemLink = GetItemLink(Row.bagId, Row.slotIndex)
+
+			if tooltip ~= ComparativeTooltip1 or ComparativeTooltip2 then								-- They inherit from ItemTooltip, so we have to rule them out specifically
+				self:inscribeItemSigilstone(tooltip, ItemLink, Stack)
+				return
+			end
+
+		else
+			return
+		end
+	end
+end
+
+
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   Arcana   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+-- Copyright (c) 2014 Matthew Miller (Mattmillus)
+--
+-- Permission is hereby granted, free of charge, to any person
+-- obtaining a copy of this software and associated documentation
+-- files (the "Software"), to deal in the Software without
+-- restriction, including without limitation the rights to use,
+-- copy, modify, merge, publish, distribute, sublicense, and/or sell
+-- copies of the Software, and to permit persons to whom the
+-- Software is furnished to do so, subject to the following
+-- conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+
+function ddDataDaedra:linkStatsToChat(itemLink)
+	if not itemLink or itemLink == "" then return end
+	itemLink = string.gsub(itemLink, "|H0", "|H1")
+	local KeyedItem = getKeyedItem(itemLink)
+	local ChatEditControl = CHAT_SYSTEM.textEntry.editControl
+
+	if not KeyedItem or
+	not KeyedItem.wAvg or
+	KeyedItem.wAvg == 0 or
+	not KeyedItem.Seen or
+	KeyedItem.Seen == 0 then
+		return
+	end
+
+	if not ChatEditControl:HasFocus() then
+		StartChatInput()
+	end
+
+	ChatEditControl:InsertText(zo_strformat(GetString(DD_STATS_TO_CHAT), itemLink, KeyedItem.Seen, ZO_CommaDelimitNumber(LIB_LOG:Round(KeyedItem.wAvg))))
+end
+
+function ddDataDaedra:chatLinkStatsToChat(itemLink, button, control)
+	if type(itemLink) == "string" and
+	#itemLink > 0 then
+		local handled = LINK_HANDLER:FireCallbacks(LINK_HANDLER.LINK_MOUSE_UP_EVENT, itemLink, button, ZO_LinkHandler_ParseLink(itemLink))
+
+		if not handled then
+			ClearMenu()
+
+			if (button == 1 and
+			ZO_PopupTooltip_SetLink) then
+				ZO_PopupTooltip_SetLink(itemLink)
+
+			elseif (button == 2 and
+			itemLink ~= "") then
+				if isKeyedItem(itemLink) then
+					AddMenuItem(GetString(SI_ITEM_ACTION_DD_STATS_TO_CHAT), function() self:linkStatsToChat(itemLink) end)
+				end
+
+				AddMenuItem(GetString(SI_ITEM_ACTION_LINK_TO_CHAT), function() ZO_LinkHandler_InsertLink(zo_strformat(SI_TOOLTIP_ITEM_NAME, itemLink)) end)
+				ShowMenu(control)
+			end
+		end
+	end
+end
+
+function ddDataDaedra:slotControlStatsToChat()
+	if(SlotControl:GetOwningWindow() == ZO_TradingHouse) then return end
+	if(ZO_PlayerInventoryBackpack:IsHidden() and
+	ZO_PlayerBankBackpack:IsHidden() and
+	ZO_GuildBankBackpack:IsHidden() and
+	ZO_SmithingTopLevelDeconstructionPanelInventoryBackpack:IsHidden() and
+	ZO_EnchantingTopLevelInventoryBackpack:IsHidden()) then
+		return
+	end
+
+	if(SlotControl:GetParent() ~= ZO_Character) then
+		SlotControl = SlotControl:GetParent()
+	end
+
+	local ItemLink = getItemLinkFromSlotControl(SlotControl)
+	if isKeyedItem(ItemLink) then
+		zo_callLater(function() AddMenuItem(GetString(SI_ITEM_ACTION_DD_STATS_TO_CHAT), function() ddDataDaedra:linkStatsToChat(ItemLink) end, MENU_ADD_OPTION_LABEL); ShowMenu(self) end, 50)
+	end
+end
+
+---------------------------------------------------------------------------------------------------
+
+
+function ddDataDaedra:displayMsg(msgString, boolDebug)
+	local CODEX	= self.dataCairn.codex
+	local tDebug = CODEX.cDebug.getFunc()
+	local tNotify = CODEX.cNotify.getFunc()
+
+	if tDebug and
+	boolDebug then
+		zo_callLater(function() d(GetString(DD_DEBUG) .. msgString) end, 1000)
+
+	elseif tNotify and
+	not boolDebug then
+		zo_callLater(function() d(GetString(DD_MONIKER) .. msgString) end, 1000)
+	end
+end
+
+function ddDataDaedra:twilightMaiden(guildId)
+	local DATACAIRN			= self.dataCairn
+	local CODEX				= self.dataCairn.codex
+	local PRICES			= self.dataCairn.prices
+	local numGuilds			= GetNumGuilds()
+	local guildName 		= GetGuildName(guildId)
+	local StoreEvents		= GetNumGuildEvents(guildId, GUILD_HISTORY_STORE)
+	local NewSales			= 0
+
+	if guildId > numGuilds then
+		self:displayMsg(GetString(DD_TWILIGHT_COMPLETE), false)
+		return
+
+	elseif not numGuilds or
+	numGuilds < 1 or
+	not guildName or
+	guildName == "" or
+	type(guildName) ~= "string" then
+		return
+	end
+
+	local lastScan = DATACAIRN.lastScan[guildName] or 1
+	local lastSale = DATACAIRN.lastSale[guildName] or 1
+
+	for i = 1, StoreEvents, 1 do
+		local EventType, secsSinceSale, Buyer, Seller, Quantity, itemLink, Price, Tax = GetGuildEventInfo(guildId, GUILD_HISTORY_STORE, i)
+		local timeStamp = GetTimeStamp() - secsSinceSale
+
+		if EventType == GUILD_EVENT_ITEM_SOLD and
+		timeStamp > lastScan and
+		itemLink ~= "" then
+			if not lastSale or
+			timeStamp > lastSale then
+				DATACAIRN.lastSale[guildName] = (timeStamp - secsSinceSale)
+			end
+
+			NewSales	= NewSales + 1
+			Quantity 	= tonumber(Quantity)
+			Price 		= tonumber(Price)
+
+			local Quality		= parseItemLinkQuality(itemLink)
+			local SetItem 		= parseItemLinkSetItem(itemLink)
+			local Trait			= parseItemLinkTrait(itemLink)
+			local Level, VetRank = parseItemLinkLevel(itemLink)
+			local ItemId		= parseLinkValue(itemLink, 3)
+			local EnchtId		= parseLinkValue(itemLink, 6)
+			local Element		= (Price / Quantity) * Quantity
+			local Tier1, Tier2, Tier3, Tier4, Tier5, Values
+
+			Values = {
+				["Seen"] 		= 1,
+				["RawValue"] 	= Element,
+				["Weight"] 		= Quantity,
+				["wAvg"] 		= LIB_LOG:RoundTo100s(LIB_LOG:WeightedAverage(Price, Quantity)),
+				["PostPrice"]	= 0,
+			}
+
+			Tier5 	= { [EnchtId] 	= Values}
+			Tier4 	= { [VetRank] 	= Tier5 }
+			Tier3 	= { [Level] 	= Tier4 }
+			Tier2 	= { [Quality] 	= Tier3 }
+			Tier1	= { [Trait]	 	= Tier2 }
+
+			if ItemId and (not PRICES) then
+				table.insert(PRICES, ItemId, Tier1)
+
+			elseif ItemId and (not PRICES[ItemId]) then
+				table.insert(PRICES, ItemId, Tier1)
+
+			elseif ItemId and PRICES[ItemId] then
+				if not PRICES[ItemId][Trait] then
+					table.insert(PRICES[ItemId], Trait, Tier2)
+
+				elseif PRICES[ItemId][Trait] then
+					if not PRICES[ItemId][Trait][Quality] then
+						table.insert(PRICES[ItemId][Trait], Quality, Tier3)
+
+					elseif PRICES[ItemId][Trait][Quality] then
+						if not PRICES[ItemId][Trait][Quality][Level] then
+							table.insert(PRICES[ItemId][Trait][Quality], Level, Tier4)
+
+						elseif PRICES[ItemId][Trait][Quality][Level] then
+							if not PRICES[ItemId][Trait][Quality][Level][VetRank] then
+								table.insert(PRICES[ItemId][Trait][Quality][Level], VetRank, Tier5)
+
+							elseif PRICES[ItemId][Trait][Quality][Level][VetRank] then
+								if not PRICES[ItemId][Trait][Quality][Level][VetRank][EnchtId] then
+									table.insert(PRICES[ItemId][Trait][Quality][Level][VetRank], EnchtId, Values)
+
+								elseif PRICES[ItemId][Trait][Quality][Level][VetRank][EnchtId] then
+									local record = PRICES[ItemId][Trait][Quality][Level][VetRank][EnchtId]
+									if record.Seen then
+										record.Seen 	= record.Seen + 1
+										record.RawValue	= record.RawValue + Element
+										record.Weight	= record.Weight + Quantity
+										record.wAvg 	= LIB_LOG:RoundTo100s(record.RawValue / record.Weight)
+
+									else
+										record.Seen 	= 1
+										record.RawValue = Element
+										record.Weight 	= Quantity
+										record.wAvg 	= LIB_LOG:RoundTo100s(record.RawValue / record.Weight)
+										record.PostPrice = 0
+									end
+								end
+							end
+						end
+					end
+				end
+			end
+		end
+	end
+
+	if NewSales > 0 then
+--		self:displayMsg(zo_strformat(GetString(DD_TWILIGHT_NEWSALES), ZO_CommaDelimitNumber(NewSales), guildName), false)
+	end
+
+	DATACAIRN.lastScan[guildName] = GetTimeStamp()
+end
+
+function ddDataDaedra:twilightSummons()
+	local DATACAIRN = self.dataCairn
+	local scanInterval = self.dataCairn.codex.cInterval.getFunc()
+	local numGuilds = GetNumGuilds()
+
+	if self.historyScan then
+		self:displayMsg("twilightSummons shut down due to historyScan", true)
+		return
+
+	elseif numGuilds >= 1 then
+		for guildId = 1, numGuilds, 1 do
+--			self:displayMsg("Starting Twilight Maiden for " .. GetGuildName(guildId), true)
+			self:twilightMaiden(guildId)
+		end
+	end
+
+	self:displayMsg(GetString(DD_TWILIGHT_COMPLETE), true)
+end
+
+function ddDataDaedra:checkHistory()
+	local DATACAIRN = self.dataCairn
+	local numGuilds = GetNumGuilds()
+	local scanInterval = self.dataCairn.codex.cInterval.getFunc()
+
+	self.historyScan = true
+
+	if numGuilds >= 1 then
+		for guildId = 1, numGuilds, 1 do
+			local guildName = GetGuildName(guildId)
+			local numEvents = GetNumGuildEvents(guildId, GUILD_HISTORY_STORE)
+			local lastScan = DATACAIRN.lastScan[guildName]
+
+			RequestGuildHistoryCategoryNewest(guildId, GUILD_HISTORY_STORE)
+
+			if numEvents > 0 then
+				local secsSinceSale = select(2, GetGuildEventInfo(guildId, GUILD_HISTORY_STORE, numEvents))
+
+				if DoesGuildHistoryCategoryHaveMoreEvents(guildId, GUILD_HISTORY_STORE) and
+				(not lastScan or ((GetTimeStamp() - secsSinceSale) > lastScan)) then
+					self:displayMsg("Requesting guild store history page for " .. guildName, true)
+					RequestGuildHistoryCategoryOlder(guildId, GUILD_HISTORY_STORE)
+					zo_callLater(function() self:checkHistory() end, scanInterval * 1000)
+					return
+				end
+			end
+		end
+	end
+
+	self.historyScan = false
+--	self:displayMsg("Guild history scan complete.", true)
+end
+
+
+function ddDataDaedra:hooks()
+	ZO_PreHook(TRADING_HOUSE, "PostPendingItem", function() savePrice() end)
+	ZO_PreHook("ZO_InventorySlot_ShowContextMenu", function(rowControl) SlotControl = rowControl; self:slotControlStatsToChat() end)
+
+	ZO_PreHookHandler(ItemTooltip, 	'OnUpdate',		function(tooltip) self:sigilDesign(tooltip) end)
+	ZO_PreHookHandler(ItemTooltip, 	'OnCleared',	function() TooltipControl = nil end)
+	ZO_PreHookHandler(PopupTooltip, 'OnUpdate',		function(tooltip) self:inscribePopupSigilstone(tooltip) end)
+	ZO_PreHookHandler(PopupTooltip,	'OnCleared',	function() PopupControl = nil end)
+
+	ZO_PreHookHandler(ZO_SmithingTopLevelCreationPanelResultTooltip, "OnUpdate", function(tooltip) self:creationSigil(self, tooltip) end)
+	ZO_PreHookHandler(ZO_SmithingTopLevelCreationPanelResultTooltip, "OnCleared", function() ResultControl = nil end)
+
+	ZO_PreHookHandler(ZO_SmithingTopLevelImprovementPanelResultTooltip, "OnUpdate", function(tooltip) self:improvementSigil(self, tooltip) end)
+	ZO_PreHookHandler(ZO_SmithingTopLevelImprovementPanelResultTooltip, "OnCleared", function() ResultControl = nil end)
+
+	ZO_PreHookHandler(ZO_EnchantingTopLevelTooltip, "OnUpdate", function(tooltip) self:enchantingSigil(self, tooltip) end)
+	ZO_PreHookHandler(ZO_EnchantingTopLevelTooltip, "OnCleared", function() ResultControl = nil end)
+
+	ZO_PreHookHandler(ZO_ProvisionerTopLevelTooltip, "OnUpdate", function(tooltip) self:provisionerSigil(self, tooltip) end)
+	ZO_PreHookHandler(ZO_ProvisionerTopLevelTooltip, "OnCleared", function() ResultControl = nil end)
+
+	ZO_PreHookHandler(ZO_AlchemyTopLevelTooltip, "OnUpdate", function(tooltip) self:alchemySigil(self, tooltip) end)
+	ZO_PreHookHandler(ZO_AlchemyTopLevelTooltip, "OnCleared", function() ResultControl = nil end)
+
+
+	ZO_LinkHandler_OnLinkMouseUp = function(itemLink, button, control) self:chatLinkStatsToChat(itemLink, button, control) end
+	LINK_HANDLER:RegisterCallback(LINK_HANDLER.LINK_CLICKED_EVENT, function() self:inscribePopupSigilstone(self, PopupTooltip) end)
+	SMITHING.improvementPanel.spinner:RegisterCallback("OnValueChanged", function(value) ResultControl = nil self:improvementSigil(self, ZO_SmithingTopLevelImprovementPanelResultTooltip) end)
+	PostFunc = TRADING_HOUSE.SetupPendingPost
+	TRADING_HOUSE.SetupPendingPost = function() pendListing() end
+end
+
+function ddDataDaedra:liminalBridge()
+	self.dataCairn = ZO_SavedVars:NewAccountWide("ddDataCairn", SV_VERSION, nil, self.dataCairn, "Global")
+
+	self.dataCairn.codex:init()
+	TASKMASTER = LIB_LAM2:RegisterAddonPanel("ddCodex", self:mPanel())
+	LIB_LAM2:RegisterOptionControls("ddCodex", self:mControls())
+
+	local scanInterval = self.dataCairn.codex.cInterval.getFunc()
+
+	self:hooks()
+
+	self:displayMsg(GetString(DD_ONLOAD), false)
+	self.historyScan = true
+	zo_callLater(function() self:checkHistory() end, scanInterval * 1000)
+	EVENT_MANAGER:RegisterForUpdate(self.name, (scanInterval * 60 * 1000), function() self:twilightSummons() end)
+	EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED)
+end
+
+local function onAddonLoaded(eventCode, addonName)
+	if addonName == ADDON_NAME then
+--		zo_callLater(function()
+		ddDataDaedra:liminalBridge()
+--		end, 1000)
+	else
+		return
+	end
+end
+
+
+EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED, onAddonLoaded)
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/ddDataDaedra.txt b/ddDataDaedra.txt
new file mode 100644
index 0000000..ad507d3
--- /dev/null
+++ b/ddDataDaedra.txt
@@ -0,0 +1,34 @@
+## EULA: "This Add-on is not created by, affiliated with or sponsored by ZeniMax Media Inc. or its affiliates.
+## The Elder Scrolls® and related logos are registered trademarks or trademarks of ZeniMax Media Inc. in the
+## United States and/or other countries. All rights reserved."
+
+## Title: Deome's DataDaedra
+## Description: DataDaedra recommends prices for most items based on recent sales data. Now part of Deome's Addon Suite.
+## Author: D. Deome (@deome) - heydeome@gmail.com
+## APIVersion: 100014
+## Version 2.0x
+
+## SavedVariables: ddDataCairn
+## OptionalDependsOn: LibAddonMenu-2.0 LibLogos
+
+Lib\LibStub\LibStub.lua
+
+Lib\LibAddonMenu-2.0\LibAddonMenu-2.0.lua
+Lib\LibAddonMenu-2.0\controls\panel.lua
+Lib\LibAddonMenu-2.0\controls\submenu.lua
+Lib\LibAddonMenu-2.0\controls\button.lua
+Lib\LibAddonMenu-2.0\controls\checkbox.lua
+Lib\LibAddonMenu-2.0\controls\colorpicker.lua
+Lib\LibAddonMenu-2.0\controls\custom.lua
+Lib\LibAddonMenu-2.0\controls\description.lua
+Lib\LibAddonMenu-2.0\controls\dropdown.lua
+Lib\LibAddonMenu-2.0\controls\editbox.lua
+Lib\LibAddonMenu-2.0\controls\header.lua
+Lib\LibAddonMenu-2.0\controls\slider.lua
+Lib\LibAddonMenu-2.0\controls\texture.lua
+
+Lib\LibLogos\LibLogos.lua
+
+i18n\$(language).lua
+ddDataDaedra.xml
+ddDataDaedra.lua
\ No newline at end of file
diff --git a/ddDataDaedra.xml b/ddDataDaedra.xml
new file mode 100644
index 0000000..ba5cdff
--- /dev/null
+++ b/ddDataDaedra.xml
@@ -0,0 +1,39 @@
+<!------------------------------------------------------------------------------------------------
+-----------------------------------------   DataDaedra   -----------------------------------------
+---------------------------   by Deome (@deome) - heydeome@gmail.com   ---------------------------
+local									VERSION = "2.0"											--
+--																								--
+--																								--
+---------------------------------------   Deome's License   --------------------------------------
+--																								--
+-- 		Copyright (c) 2014, 2015, 2016 D. Deome (@deome) - heydeome@gmail.com					--
+--																								--
+-- 		This software is provided 'as-is', without any express or implied						--
+-- 		warranty. In no event will the author(s) be held liable for any damages					--
+-- 		arising from the use of this software. This software, and the ideas, processes, 		--
+--		functions, and all other intellectual property contained within may not be modified,	--
+--		distributed, or used in any other works without the written permission of the			--
+--		author.																					--
+--																								--
+--		Any use with permission of author must include the above license and copyright,			--
+--		and any other license and copyright notices noted within this software.			 		--
+--																								--
+-------------------------------------   ZO Obligatory Spam   -------------------------------------
+--																								--
+-- 		"This Add-on is not created by, affiliated with or sponsored by ZeniMax 		  		--
+--		Media Inc. or its affiliates. The Elder Scrolls® and related logos are registered 	 	--
+--		trademarks of ZeniMax Media Inc. in the United States and/or other countries. 			--
+--		All rights reserved."																	--
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+------------------------------------------   Fonts   ---------------------------------------------
+------------------------------------------------------------------------------------------------->
+
+<GuiXml>
+    <Font name="DataDaedraBody" font="$(STONE_TABLET_FONT)|16" />
+    <Font name="DataDaedraHeader" font="$(HANDWRITTEN_FONT)|22|soft-shadow-thick" />
+</GuiXml>
diff --git a/i18n/DE.lua b/i18n/DE.lua
new file mode 100644
index 0000000..3aaef58
--- /dev/null
+++ b/i18n/DE.lua
@@ -0,0 +1,117 @@
+--------------------------------------------------------------------------------------------------
+---------------------------------   DataDaedra - Local Strings   ---------------------------------
+---------------------------   by Deome (@deome) - heydeome@gmail.com   ---------------------------
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+---------------------------   New Strings Requiring Translation   --------------------------------
+--------------------------------------------------------------------------------------------------
+
+ZO_CreateStringId("DD_MONIKER", "DataDaedra: ")
+ZO_CreateStringId("DD_DEBUG", "DataDaedra DEBUG: ")
+ZO_CreateStringId("DD_ONLOAD", "Summoned and bound.")
+ZO_CreateStringId("DD_EASY", "Deome's Taskmaster preferences loaded.")
+ZO_CreateStringId("DD_STATS_TO_CHAT", "DataDaedra - Price Check for <<1>>: <<2>> sales, <<3>>g (wAvg).")
+ZO_CreateStringId("DD_TWILIGHT_SUMMON", "Twilight Maiden is updating sales records and prices. Reality may occasionally appear to freeze, but this is perfectly normal.")
+ZO_CreateStringId("DD_TWILIGHT_ONLOGIN", "Twilight Maiden will once again update prices when you begin your adventures.")
+ZO_CreateStringId("DD_TWILIGHT_OFFLOGIN", "Twilight Maiden will no longer update prices.")
+ZO_CreateStringId("DD_TWILIGHT_ONZONE", "Twilight Maiden will also update prices when you travel to new places.")
+ZO_CreateStringId("DD_TWILIGHT_OFFZONE", "Twilight Maiden will no longer update prices when traveling to new places.")
+ZO_CreateStringId("DD_TWILIGHT_NEWSALES", "Twilight Maiden found <<1>> new sales, out of <<2>>, in <<3>>.")
+ZO_CreateStringId("DD_TWILIGHT_COMPLETE", "Twilight Maiden has updated all prices.")
+ZO_CreateStringId("DD_TWILIGHT_DISMISS", "Twilight Maiden dismissed, and will not return unless summoned.")
+ZO_CreateStringId("DD_TASKMASTER_NAME", "Deome's DataDaedra")
+ZO_CreateStringId("DD_TASKMASTER_DISPLAYNAME", "Deome's DataDaedra - Taskmaster")
+ZO_CreateStringId("DD_TASKMASTER_AUTHOR", "Deome (@deome) - heydeome@gmail.com")
+ZO_CreateStringId("DD_TASKMASTER_COMMANDLINE", "/dd taskmaster")
+ZO_CreateStringId("DD_TASKMASTER_ENABLE_TWILIGHT_NAME", "Enable Twilight Maiden")
+ZO_CreateStringId("DD_TASKMASTER_ENABLE_TWILIGHT_TIP", "Turn this ON to enable price updates. DD will NOT update prices if this is off.")
+ZO_CreateStringId("DD_TASKMASTER_ONLOGIN_TWILIGHT_NAME", "Summon On Login")
+ZO_CreateStringId("DD_TASKMASTER_ONLOGIN_TWILIGHT_TIP", "Turn this ON, and the Twilight Maiden will update prices upon login.")
+ZO_CreateStringId("DD_TASKMASTER_ONZONE_TWILIGHT_NAME", "Summon On Zone")
+ZO_CreateStringId("DD_TASKMASTER_ONZONE_TWILIGHT_TIP", "Turn this ON, and the Twilight Maiden will update prices after each loading screen as well as after login.")
+ZO_CreateStringId("DD_TASKMASTER_SUMMON_TWILIGHT_NAME", "Summon")
+ZO_CreateStringId("DD_TASKMASTER_SUMMON_TWILIGHT_TIP", "Once summoned, the Twilight Maiden will bind pricing data to your tooltips.")
+ZO_CreateStringId("DD_TASKMASTER_EASY_BUTTON_NAME", "EASY")
+ZO_CreateStringId("DD_TASKMASTER_EASY_BUTTON_TIP", "Assigns Deome's Preferences to all settings.")
+ZO_CreateStringId("DD_TASKMASTER_RESET_NAME", "RESET")
+ZO_CreateStringId("DD_TASKMASTER_RESET_TIP", "Wipes all saved variables, including prices and settings. Same as clearing/deleting saved variables file.")
+ZO_CreateStringId("DD_TASKMASTER_MAX_SEEN_NAME", "Max (Seen) Sales")
+ZO_CreateStringId("DD_TASKMASTER_MAX_SEEN_TIP", "Maximum number of (Seen) sales used to calculate (wAvg) for each item.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_SET_NAME", "Enable Set Item Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_SET_TIP", "Turn this ON, as it will not interfere with anything. Unless, for some reason, you just want to goof off and see wAvg prices for zero value gear.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_PRICING_KEY_WARNING", "Toggling this feature will AUTOMATICALLY reset the price database.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_TRAIT_NAME", "Enable Trait Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_TRAIT_TIP", "Turn this ON, as it will not interfere with item set pricing. Unless, for some reason, you just want to goof off and see wAvg prices for zero value gear.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_QUALITY_NAME", "Enable Item Quality Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_QUALITY_TIP", "Leave this OFF if you only wish to see prices for particular traits or item sets. Crafters will want this OFF when considering trait prices")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_LEVEL_NAME", "Enable Item Level Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_LEVEL_TIP", "If, for some reason, you don't want level considered in pricing gear, leave this OFF")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_ENCHANT_NAME", "Enable Enchant Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_ENCHANT_TIP", "Leave this OFF if you don't care about pricing for individual enchantments on each piece of gear")
+ZO_CreateStringId("DD_TASKMASTER_TRADE_GUILD_NAME", "Primary Trade House")
+ZO_CreateStringId("DD_TASKMASTER_TRADE_GUILD_TIP", "Accessing guild stores will default to this guild store. Helps to prevent accidental postings to wrong guild.")
+ZO_CreateStringId("DD_TASKMASTER_WAVG_SALE_PRICE_NAME", "Default Listing Price to wAvg")
+ZO_CreateStringId("DD_TASKMASTER_WAVG_SALE_PRICE_TIP", "Enable to set listing prices to Weighted Average (wAvg) by default (saved prices will override, if enabled).")
+ZO_CreateStringId("DD_TASKMASTER_SAVE_SALE_PRICE_NAME", "Save Listing Prices in Trading House")
+ZO_CreateStringId("DD_TASKMASTER_SAVE_SALE_PRICE_TIP", "Enable if you wish DataDaedra to save listing price for items in the Trading House.")
+ZO_CreateStringId("DD_TASKMASTER_NOTIFICATIONS_NAME", "Enable Notifications")
+ZO_CreateStringId("DD_TASKMASTER_NOTIFICATIONS_TIP", "Leave this ON to receive status updates from scanning and other activities. Turn this OFF to disable chat notifications.")
+ZO_CreateStringId("DD_TASKMASTER_DEBUG_NAME", "Toggle Debug Messages")
+ZO_CreateStringId("DD_TASKMASTER_DEBUG_TIP", "New DataDaedra versions may have debug messages for developers. Leave this OFF if you don't like message spam.")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_NAME", "Toggle LGH Debug Messages")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_TIP", "Separate control for LibGuildHistory debug messages.")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_WARNING", "IF YOU THINK DATADAEDRA IS DOING NOTHING, turn this ON. Otherwise, you'll want to leave it OFF.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_1_TITLE", "Twilight Maiden")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_1_TEXT", "The Twilight Maiden is responsible for updating prices in DataDaedra. Toggle off to prevent updates from running, and use the 'Summon' button to manually restart.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_2_TITLE", "Data Reset")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_2_TEXT", "Reset Prices will wipe recorded item prices. This will no longer trigger a data refresh.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_3_TITLE", "Price Update Restrictions")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_3_TEXT", "These settings control which sales are used in price updates and how they are considered in price calculations. Restrictions are as loose as possible by default.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_TITLE", "Price Characteristics")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_TEXT", "These settings control how price updates distinguish between items (for the items that use these features).")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_WARNING", "Any changes will require a data reset, which will occur immediately. You do not need to wait for it to finish before toggling the next setting.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_HEADER_FONT_NAME", "Header Font")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_HEADER_FONT_TIP", "Header font for DataDaedra's tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_BODY_FONT_NAME", "Body Font")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_BODY_FONT_TIP", "Body font for DataDaedra's tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_NAME", "Add Item Details to Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_TIP", "Includes ItemId and other technical item values on all item tooltips. Insanely useful for developers. Will always show if tooltips are working!")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_WARNING", "Note: If you aren't seeing prices on item tooltips, turn this ON. If item details display, then tooltip Bindings are working correctly.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_MULTILINE_NAME", "Use Multi-Line Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_MULTILINE_TIP", "If tooltip prices are spilling onto an additional line, this setting will at least make them tidy.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_SEEN_NAME", "Display (Seen) on Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_SEEN_TIP", "For those who like this stat, just leave this ON. Otherwise, you may turn it OFF to remove (Seen) stats from tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_QUALITY_NAME", "Display Item Quality on Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_QUALITY_TIP", "Turn this feature ON if you would like items to state their quality in addition to quality coloring.")
+ZO_CreateStringId("DD_TASKMASTER_MAT_MISER_NAME", "Display MatMiser Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_MAT_MISER_TIP", "Enable MatMiser for pricing previews of crafted items, and pricing values for required materials.")
+ZO_CreateStringId("DD_TOOLTIP_HEADER", "DataDaedra")
+ZO_CreateStringId("DD_TOOLTIP_STAT_SEEN", "<<X:1>><<2>>|r<<3>>")
+ZO_CreateStringId("DD_TOOLTIP_STAT_WAVG", "|cFFD700<<1>>|r <<2>> (wAvg)")
+ZO_CreateStringId("DD_TOOLTIP_STAT_STACK", "|cFFD700<<1>>|r <<2>> (x<<3>>)")
+ZO_CreateStringId("DD_TOOLTIP_CRAFTING_HEADER", "DataDaedra MatMiser")
+ZO_CreateStringId("DD_TOOLTIP_CRAFTING_WAVG", "|cFFD700<<1>>|r <<2>>")
+ZO_CreateStringId("DD_TOOLTIP_QUALITY", "<<1>> Quality")
+ZO_CreateStringId("DD_TOOLTIP_REQVET", "<<1>> <<2>>")
+ZO_CreateStringId("DD_TOOLTIP_REQLVL", "LEVEL <<1>>")
+ZO_CreateStringId("DD_ICON_BULLET", "esoui/art/miscellaneous/bullet.dds")
+ZO_CreateStringId("DD_ICON_GOLD", "esoui/art/currency/currency_gold.dds")
+ZO_CreateStringId("SI_ITEM_ACTION_DD_STATS_TO_CHAT", "DataDaedra Stats to Chat")
+ZO_CreateStringId("SI_BINDING_NAME_DD_TWILIGHT", "Summon Twilight Maiden")
+ZO_CreateStringId("SI_BINDING_NAME_DD_TASKMASTER", "Summon Taskmaster")
+ZO_CreateStringId("SI_BINDING_NAME_DD_RESET_PRICES", "Taskmaster: RESET")
+
+
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   German   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/i18n/EN.lua b/i18n/EN.lua
new file mode 100644
index 0000000..d003df3
--- /dev/null
+++ b/i18n/EN.lua
@@ -0,0 +1,121 @@
+--------------------------------------------------------------------------------------------------
+---------------------------------   DataDaedra - Local Strings   ---------------------------------
+---------------------------   by Deome (@deome) - heydeome@gmail.com   ---------------------------
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+----------------------------------------   English   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+ZO_CreateStringId("DD_MONIKER", "DataDaedra: ")
+ZO_CreateStringId("DD_DEBUG", "DataDaedra DEBUG: ")
+ZO_CreateStringId("DD_ONLOAD", "Summoned and bound.")
+ZO_CreateStringId("DD_EASY", "Deome's Taskmaster preferences loaded.")
+ZO_CreateStringId("DD_STATS_TO_CHAT", "DataDaedra - Price Check for <<1>>: <<2>> sales, <<3>>g (wAvg).")
+ZO_CreateStringId("DD_TWILIGHT_SUMMON", "Twilight Maiden is updating sales records and prices. Reality may occasionally appear to freeze, but this is perfectly normal.")
+ZO_CreateStringId("DD_TWILIGHT_ONLOGIN", "Twilight Maiden will once again update prices when you begin your adventures.")
+ZO_CreateStringId("DD_TWILIGHT_OFFLOGIN", "Twilight Maiden will no longer update prices.")
+ZO_CreateStringId("DD_TWILIGHT_ONZONE", "Twilight Maiden will also update prices when you travel to new places.")
+ZO_CreateStringId("DD_TWILIGHT_OFFZONE", "Twilight Maiden will no longer update prices when traveling to new places.")
+ZO_CreateStringId("DD_TWILIGHT_NEWSALES", "Twilight Maiden found <<1>> new sales in <<2>>.")
+ZO_CreateStringId("DD_TWILIGHT_COMPLETE", "Twilight Maiden has updated all prices.")
+ZO_CreateStringId("DD_TWILIGHT_DISMISS", "Twilight Maiden dismissed, and will not return unless summoned.")
+ZO_CreateStringId("DD_TASKMASTER_NAME", "Deome's DataDaedra")
+ZO_CreateStringId("DD_TASKMASTER_DISPLAYNAME", "Deome's DataDaedra - Taskmaster")
+ZO_CreateStringId("DD_TASKMASTER_AUTHOR", "Deome (@deome) - heydeome@gmail.com")
+ZO_CreateStringId("DD_TASKMASTER_COMMANDLINE", "/dd taskmaster")
+ZO_CreateStringId("DD_TASKMASTER_INTERVAL_NAME", "Scan Interval")
+ZO_CreateStringId("DD_TASKMASTER_INTERVAL_TIP", "In minutes, select how often DD will check for new sales.")
+
+ZO_CreateStringId("DD_TASKMASTER_ENABLE_TWILIGHT_NAME", "Enable Twilight Maiden")
+ZO_CreateStringId("DD_TASKMASTER_ENABLE_TWILIGHT_TIP", "Turn this ON to enable price updates. DD will NOT update prices if this is off.")
+ZO_CreateStringId("DD_TASKMASTER_ONLOGIN_TWILIGHT_NAME", "Summon On Login")
+ZO_CreateStringId("DD_TASKMASTER_ONLOGIN_TWILIGHT_TIP", "Turn this ON, and the Twilight Maiden will update prices upon login.")
+ZO_CreateStringId("DD_TASKMASTER_ONZONE_TWILIGHT_NAME", "Summon On Zone")
+ZO_CreateStringId("DD_TASKMASTER_ONZONE_TWILIGHT_TIP", "Turn this ON, and the Twilight Maiden will update prices after each loading screen as well as after login.")
+ZO_CreateStringId("DD_TASKMASTER_SUMMON_TWILIGHT_NAME", "Summon")
+ZO_CreateStringId("DD_TASKMASTER_SUMMON_TWILIGHT_TIP", "Once summoned, the Twilight Maiden will bind pricing data to your tooltips.")
+ZO_CreateStringId("DD_TASKMASTER_EASY_BUTTON_NAME", "EASY")
+ZO_CreateStringId("DD_TASKMASTER_EASY_BUTTON_TIP", "Assigns Deome's Preferences to all settings.")
+ZO_CreateStringId("DD_TASKMASTER_RESET_NAME", "RESET")
+ZO_CreateStringId("DD_TASKMASTER_RESET_TIP", "Wipes all saved variables, including prices and settings. Same as clearing/deleting saved variables file.")
+ZO_CreateStringId("DD_TASKMASTER_MAX_SEEN_NAME", "Max (Seen) Sales")
+ZO_CreateStringId("DD_TASKMASTER_MAX_SEEN_TIP", "Maximum number of (Seen) sales used to calculate (wAvg) for each item.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_SET_NAME", "Enable Set Item Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_SET_TIP", "Turn this ON, as it will not interfere with anything. Unless, for some reason, you just want to goof off and see wAvg prices for zero value gear.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_PRICING_KEY_WARNING", "Toggling this feature will AUTOMATICALLY reset the price database.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_TRAIT_NAME", "Enable Trait Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_TRAIT_TIP", "Turn this ON, as it will not interfere with item set pricing. Unless, for some reason, you just want to goof off and see wAvg prices for zero value gear.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_QUALITY_NAME", "Enable Item Quality Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_QUALITY_TIP", "Leave this OFF if you only wish to see prices for particular traits or item sets. Crafters will want this OFF when considering trait prices")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_LEVEL_NAME", "Enable Item Level Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_LEVEL_TIP", "If, for some reason, you don't want level considered in pricing gear, leave this OFF")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_ENCHANT_NAME", "Enable Enchant Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_ENCHANT_TIP", "Leave this OFF if you don't care about pricing for individual enchantments on each piece of gear")
+ZO_CreateStringId("DD_TASKMASTER_TRADE_GUILD_NAME", "Primary Trade House")
+ZO_CreateStringId("DD_TASKMASTER_TRADE_GUILD_TIP", "Accessing guild stores will default to this guild store. Helps to prevent accidental postings to wrong guild.")
+ZO_CreateStringId("DD_TASKMASTER_WAVG_SALE_PRICE_NAME", "Default Listing Price to wAvg")
+ZO_CreateStringId("DD_TASKMASTER_WAVG_SALE_PRICE_TIP", "Enable to set listing prices to Weighted Average (wAvg) by default (saved prices will override, if enabled).")
+ZO_CreateStringId("DD_TASKMASTER_SAVE_SALE_PRICE_NAME", "Save Listing Prices in Trading House")
+ZO_CreateStringId("DD_TASKMASTER_SAVE_SALE_PRICE_TIP", "Enable if you wish DataDaedra to save listing price for items in the Trading House.")
+ZO_CreateStringId("DD_TASKMASTER_NOTIFICATIONS_NAME", "Enable Notifications")
+ZO_CreateStringId("DD_TASKMASTER_NOTIFICATIONS_TIP", "Leave this ON to receive status updates from scanning and other activities. Turn this OFF to disable chat notifications.")
+ZO_CreateStringId("DD_TASKMASTER_DEBUG_NAME", "Toggle Debug Messages")
+ZO_CreateStringId("DD_TASKMASTER_DEBUG_TIP", "New DataDaedra versions may have debug messages for developers. Leave this OFF if you don't like message spam.")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_NAME", "Toggle LGH Debug Messages")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_TIP", "Separate control for LibGuildHistory debug messages.")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_WARNING", "IF YOU THINK DATADAEDRA IS DOING NOTHING, turn this ON. Otherwise, you'll want to leave it OFF.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_1_TITLE", "Twilight Maiden")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_1_TEXT", "The Twilight Maiden is responsible for updating prices in DataDaedra. Toggle off to prevent updates from running, and use the 'Summon' button to manually restart.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_2_TITLE", "Data Reset")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_2_TEXT", "Reset Prices will wipe recorded item prices. This will no longer trigger a data refresh.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_3_TITLE", "Price Update Restrictions")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_3_TEXT", "These settings control which sales are used in price updates and how they are considered in price calculations. Restrictions are as loose as possible by default.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_TITLE", "Price Characteristics")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_TEXT", "These settings control how price updates distinguish between items (for the items that use these features).")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_WARNING", "Any changes will require a data reset, which will occur immediately. You do not need to wait for it to finish before toggling the next setting.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_HEADER_FONT_NAME", "Header Font")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_HEADER_FONT_TIP", "Header font for DataDaedra's tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_BODY_FONT_NAME", "Body Font")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_BODY_FONT_TIP", "Body font for DataDaedra's tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_NAME", "Add Item Details to Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_TIP", "Includes ItemId and other technical item values on all item tooltips. Insanely useful for developers. Will always show if tooltips are working!")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_WARNING", "Note: If you aren't seeing prices on item tooltips, turn this ON. If item details display, then tooltip Bindings are working correctly.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_MULTILINE_NAME", "Use Multi-Line Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_MULTILINE_TIP", "If tooltip prices are spilling onto an additional line, this setting will at least make them tidy.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_SEEN_NAME", "Display (Seen) on Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_SEEN_TIP", "For those who like this stat, just leave this ON. Otherwise, you may turn it OFF to remove (Seen) stats from tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_QUALITY_NAME", "Display Item Quality on Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_QUALITY_TIP", "Turn this feature ON if you would like items to state their quality in addition to quality coloring.")
+ZO_CreateStringId("DD_TASKMASTER_MAT_MISER_NAME", "Display MatMiser Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_MAT_MISER_TIP", "Enable MatMiser for pricing previews of crafted items, and pricing values for required materials.")
+ZO_CreateStringId("DD_TOOLTIP_HEADER", "DataDaedra")
+ZO_CreateStringId("DD_TOOLTIP_STAT_SEEN", "<<X:1>><<2>>|r<<3>>")
+ZO_CreateStringId("DD_TOOLTIP_STAT_WAVG", "|cFFD700<<1>>|r <<2>> (wAvg)")
+ZO_CreateStringId("DD_TOOLTIP_STAT_STACK", "|cFFD700<<1>>|r <<2>> (x<<3>>)")
+ZO_CreateStringId("DD_TOOLTIP_CRAFTING_HEADER", "DataDaedra MatMiser")
+ZO_CreateStringId("DD_TOOLTIP_CRAFTING_WAVG", "|cFFD700<<1>>|r <<2>>")
+ZO_CreateStringId("DD_TOOLTIP_QUALITY", "<<1>> Quality")
+ZO_CreateStringId("DD_TOOLTIP_REQVET", "<<1>> <<2>>")
+ZO_CreateStringId("DD_TOOLTIP_REQLVL", "LEVEL <<1>>")
+ZO_CreateStringId("DD_ICON_BULLET", "esoui/art/miscellaneous/bullet.dds")
+ZO_CreateStringId("DD_ICON_GOLD", "esoui/art/currency/currency_gold.dds")
+ZO_CreateStringId("SI_ITEM_ACTION_DD_STATS_TO_CHAT", "DataDaedra Stats to Chat")
+
+
+--------------------------------------------------------------------------------------------------
+--------------------------------------   Keybindings   -------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+ZO_CreateStringId("SI_BINDING_NAME_DD_TWILIGHT", "Summon Twilight Maiden")
+ZO_CreateStringId("SI_BINDING_NAME_DD_TASKMASTER", "Summon Taskmaster")
+ZO_CreateStringId("SI_BINDING_NAME_DD_RESET_PRICES", "Taskmaster: RESET")
+ZO_CreateStringId("SI_BINDING_NAME_DD_EASYBUTTON", "Taskmaster: EASY")
+
+
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/i18n/FR.lua b/i18n/FR.lua
new file mode 100644
index 0000000..1675525
--- /dev/null
+++ b/i18n/FR.lua
@@ -0,0 +1,117 @@
+--------------------------------------------------------------------------------------------------
+---------------------------------   DataDaedra - Local Strings   ---------------------------------
+---------------------------   by Deome (@deome) - heydeome@gmail.com   ---------------------------
+--																								--
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+--------------------------------------------------------------------------------------------------
+---------------------------   New Strings Requiring Translation   --------------------------------
+--------------------------------------------------------------------------------------------------
+
+ZO_CreateStringId("DD_MONIKER", "DataDaedra: ")
+ZO_CreateStringId("DD_DEBUG", "DataDaedra DEBUG: ")
+ZO_CreateStringId("DD_ONLOAD", "Summoned and bound.")
+ZO_CreateStringId("DD_EASY", "Deome's Taskmaster preferences loaded.")
+ZO_CreateStringId("DD_STATS_TO_CHAT", "DataDaedra - Price Check for <<1>>: <<2>> sales, <<3>>g (wAvg).")
+ZO_CreateStringId("DD_TWILIGHT_SUMMON", "Twilight Maiden is updating sales records and prices. Reality may occasionally appear to freeze, but this is perfectly normal.")
+ZO_CreateStringId("DD_TWILIGHT_ONLOGIN", "Twilight Maiden will once again update prices when you begin your adventures.")
+ZO_CreateStringId("DD_TWILIGHT_OFFLOGIN", "Twilight Maiden will no longer update prices.")
+ZO_CreateStringId("DD_TWILIGHT_ONZONE", "Twilight Maiden will also update prices when you travel to new places.")
+ZO_CreateStringId("DD_TWILIGHT_OFFZONE", "Twilight Maiden will no longer update prices when traveling to new places.")
+ZO_CreateStringId("DD_TWILIGHT_NEWSALES", "Twilight Maiden found <<1>> new sales, out of <<2>>, in <<3>>.")
+ZO_CreateStringId("DD_TWILIGHT_COMPLETE", "Twilight Maiden has updated all prices.")
+ZO_CreateStringId("DD_TWILIGHT_DISMISS", "Twilight Maiden dismissed, and will not return unless summoned.")
+ZO_CreateStringId("DD_TASKMASTER_NAME", "Deome's DataDaedra")
+ZO_CreateStringId("DD_TASKMASTER_DISPLAYNAME", "Deome's DataDaedra - Taskmaster")
+ZO_CreateStringId("DD_TASKMASTER_AUTHOR", "Deome (@deome) - heydeome@gmail.com")
+ZO_CreateStringId("DD_TASKMASTER_COMMANDLINE", "/dd taskmaster")
+ZO_CreateStringId("DD_TASKMASTER_ENABLE_TWILIGHT_NAME", "Enable Twilight Maiden")
+ZO_CreateStringId("DD_TASKMASTER_ENABLE_TWILIGHT_TIP", "Turn this ON to enable price updates. DD will NOT update prices if this is off.")
+ZO_CreateStringId("DD_TASKMASTER_ONLOGIN_TWILIGHT_NAME", "Summon On Login")
+ZO_CreateStringId("DD_TASKMASTER_ONLOGIN_TWILIGHT_TIP", "Turn this ON, and the Twilight Maiden will update prices upon login.")
+ZO_CreateStringId("DD_TASKMASTER_ONZONE_TWILIGHT_NAME", "Summon On Zone")
+ZO_CreateStringId("DD_TASKMASTER_ONZONE_TWILIGHT_TIP", "Turn this ON, and the Twilight Maiden will update prices after each loading screen as well as after login.")
+ZO_CreateStringId("DD_TASKMASTER_SUMMON_TWILIGHT_NAME", "Summon")
+ZO_CreateStringId("DD_TASKMASTER_SUMMON_TWILIGHT_TIP", "Once summoned, the Twilight Maiden will bind pricing data to your tooltips.")
+ZO_CreateStringId("DD_TASKMASTER_EASY_BUTTON_NAME", "EASY")
+ZO_CreateStringId("DD_TASKMASTER_EASY_BUTTON_TIP", "Assigns Deome's Preferences to all settings.")
+ZO_CreateStringId("DD_TASKMASTER_RESET_NAME", "RESET")
+ZO_CreateStringId("DD_TASKMASTER_RESET_TIP", "Wipes all saved variables, including prices and settings. Same as clearing/deleting saved variables file.")
+ZO_CreateStringId("DD_TASKMASTER_MAX_SEEN_NAME", "Max (Seen) Sales")
+ZO_CreateStringId("DD_TASKMASTER_MAX_SEEN_TIP", "Maximum number of (Seen) sales used to calculate (wAvg) for each item.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_SET_NAME", "Enable Set Item Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_SET_TIP", "Turn this ON, as it will not interfere with anything. Unless, for some reason, you just want to goof off and see wAvg prices for zero value gear.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_PRICING_KEY_WARNING", "Toggling this feature will AUTOMATICALLY reset the price database.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_TRAIT_NAME", "Enable Trait Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_TRAIT_TIP", "Turn this ON, as it will not interfere with item set pricing. Unless, for some reason, you just want to goof off and see wAvg prices for zero value gear.")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_QUALITY_NAME", "Enable Item Quality Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_QUALITY_TIP", "Leave this OFF if you only wish to see prices for particular traits or item sets. Crafters will want this OFF when considering trait prices")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_LEVEL_NAME", "Enable Item Level Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_LEVEL_TIP", "If, for some reason, you don't want level considered in pricing gear, leave this OFF")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_ENCHANT_NAME", "Enable Enchant Pricing")
+ZO_CreateStringId("DD_TASKMASTER_ITEM_ENCHANT_TIP", "Leave this OFF if you don't care about pricing for individual enchantments on each piece of gear")
+ZO_CreateStringId("DD_TASKMASTER_TRADE_GUILD_NAME", "Primary Trade House")
+ZO_CreateStringId("DD_TASKMASTER_TRADE_GUILD_TIP", "Accessing guild stores will default to this guild store. Helps to prevent accidental postings to wrong guild.")
+ZO_CreateStringId("DD_TASKMASTER_WAVG_SALE_PRICE_NAME", "Default Listing Price to wAvg")
+ZO_CreateStringId("DD_TASKMASTER_WAVG_SALE_PRICE_TIP", "Enable to set listing prices to Weighted Average (wAvg) by default (saved prices will override, if enabled).")
+ZO_CreateStringId("DD_TASKMASTER_SAVE_SALE_PRICE_NAME", "Save Listing Prices in Trading House")
+ZO_CreateStringId("DD_TASKMASTER_SAVE_SALE_PRICE_TIP", "Enable if you wish DataDaedra to save listing price for items in the Trading House.")
+ZO_CreateStringId("DD_TASKMASTER_NOTIFICATIONS_NAME", "Enable Notifications")
+ZO_CreateStringId("DD_TASKMASTER_NOTIFICATIONS_TIP", "Leave this ON to receive status updates from scanning and other activities. Turn this OFF to disable chat notifications.")
+ZO_CreateStringId("DD_TASKMASTER_DEBUG_NAME", "Toggle Debug Messages")
+ZO_CreateStringId("DD_TASKMASTER_DEBUG_TIP", "New DataDaedra versions may have debug messages for developers. Leave this OFF if you don't like message spam.")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_NAME", "Toggle LGH Debug Messages")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_TIP", "Separate control for LibGuildHistory debug messages.")
+ZO_CreateStringId("DD_TASKMASTER_LGH_DEBUG_WARNING", "IF YOU THINK DATADAEDRA IS DOING NOTHING, turn this ON. Otherwise, you'll want to leave it OFF.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_1_TITLE", "Twilight Maiden")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_1_TEXT", "The Twilight Maiden is responsible for updating prices in DataDaedra. Toggle off to prevent updates from running, and use the 'Summon' button to manually restart.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_2_TITLE", "Data Reset")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_2_TEXT", "Reset Prices will wipe recorded item prices. This will no longer trigger a data refresh.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_3_TITLE", "Price Update Restrictions")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_3_TEXT", "These settings control which sales are used in price updates and how they are considered in price calculations. Restrictions are as loose as possible by default.")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_TITLE", "Price Characteristics")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_TEXT", "These settings control how price updates distinguish between items (for the items that use these features).")
+ZO_CreateStringId("DD_TASKMASTER_NOTES_4_WARNING", "Any changes will require a data reset, which will occur immediately. You do not need to wait for it to finish before toggling the next setting.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_HEADER_FONT_NAME", "Header Font")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_HEADER_FONT_TIP", "Header font for DataDaedra's tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_BODY_FONT_NAME", "Body Font")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_BODY_FONT_TIP", "Body font for DataDaedra's tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_NAME", "Add Item Details to Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_TIP", "Includes ItemId and other technical item values on all item tooltips. Insanely useful for developers. Will always show if tooltips are working!")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_DETAILS_WARNING", "Note: If you aren't seeing prices on item tooltips, turn this ON. If item details display, then tooltip Bindings are working correctly.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_MULTILINE_NAME", "Use Multi-Line Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_MULTILINE_TIP", "If tooltip prices are spilling onto an additional line, this setting will at least make them tidy.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_SEEN_NAME", "Display (Seen) on Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_SEEN_TIP", "For those who like this stat, just leave this ON. Otherwise, you may turn it OFF to remove (Seen) stats from tooltip prices.")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_QUALITY_NAME", "Display Item Quality on Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_TOOLTIP_QUALITY_TIP", "Turn this feature ON if you would like items to state their quality in addition to quality coloring.")
+ZO_CreateStringId("DD_TASKMASTER_MAT_MISER_NAME", "Display MatMiser Tooltips")
+ZO_CreateStringId("DD_TASKMASTER_MAT_MISER_TIP", "Enable MatMiser for pricing previews of crafted items, and pricing values for required materials.")
+ZO_CreateStringId("DD_TOOLTIP_HEADER", "DataDaedra")
+ZO_CreateStringId("DD_TOOLTIP_STAT_SEEN", "<<X:1>><<2>>|r<<3>>")
+ZO_CreateStringId("DD_TOOLTIP_STAT_WAVG", "|cFFD700<<1>>|r <<2>> (wAvg)")
+ZO_CreateStringId("DD_TOOLTIP_STAT_STACK", "|cFFD700<<1>>|r <<2>> (x<<3>>)")
+ZO_CreateStringId("DD_TOOLTIP_CRAFTING_HEADER", "DataDaedra MatMiser")
+ZO_CreateStringId("DD_TOOLTIP_CRAFTING_WAVG", "|cFFD700<<1>>|r <<2>>")
+ZO_CreateStringId("DD_TOOLTIP_QUALITY", "<<1>> Quality")
+ZO_CreateStringId("DD_TOOLTIP_REQVET", "<<1>> <<2>>")
+ZO_CreateStringId("DD_TOOLTIP_REQLVL", "LEVEL <<1>>")
+ZO_CreateStringId("DD_ICON_BULLET", "esoui/art/miscellaneous/bullet.dds")
+ZO_CreateStringId("DD_ICON_GOLD", "esoui/art/currency/currency_gold.dds")
+ZO_CreateStringId("SI_ITEM_ACTION_DD_STATS_TO_CHAT", "DataDaedra Stats to Chat")
+ZO_CreateStringId("SI_BINDING_NAME_DD_TWILIGHT", "Summon Twilight Maiden")
+ZO_CreateStringId("SI_BINDING_NAME_DD_TASKMASTER", "Summon Taskmaster")
+ZO_CreateStringId("SI_BINDING_NAME_DD_RESET_PRICES", "Taskmaster: RESET")
+
+
+--------------------------------------------------------------------------------------------------
+-----------------------------------------   French   ---------------------------------------------
+--------------------------------------------------------------------------------------------------
+
+
+
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------------------
\ No newline at end of file