local GlobalAddonName, ExRT = ...

ExRT.F.FUNC_FILE_LOADED = true

local UnitName, GetTime, GetCursorPosition, UnitIsUnit = UnitName, GetTime, GetCursorPosition, UnitIsUnit
local select, floor, tonumber, tostring, string_sub, string_find, string_len, bit_band, type, unpack, pairs, format, strsplit = select, floor, tonumber, tostring, string.sub, string.find, string.len, bit.band, type, unpack, pairs, format, strsplit
local string_gsub, string_match = string.gsub, string.match
local RAID_CLASS_COLORS, COMBATLOG_OBJECT_TYPE_MASK, COMBATLOG_OBJECT_CONTROL_MASK, COMBATLOG_OBJECT_REACTION_MASK, COMBATLOG_OBJECT_AFFILIATION_MASK, COMBATLOG_OBJECT_SPECIAL_MASK = RAID_CLASS_COLORS, COMBATLOG_OBJECT_TYPE_MASK, COMBATLOG_OBJECT_CONTROL_MASK, COMBATLOG_OBJECT_REACTION_MASK, COMBATLOG_OBJECT_AFFILIATION_MASK, COMBATLOG_OBJECT_SPECIAL_MASK
local UnitGroupRolesAssigned = UnitGroupRolesAssigned or ExRT.NULLfunc
local GetRaidRosterInfo = GetRaidRosterInfo
local GetItemInfo, GetItemInfoInstant  = C_Item and C_Item.GetItemInfo or GetItemInfo,  C_Item and C_Item.GetItemInfoInstant or GetItemInfoInstant
local GetSpecialization = GetSpecialization
local GetSpecializationInfo = C_SpecializationInfo and C_SpecializationInfo.GetSpecializationInfo or GetSpecializationInfo
local SendChatMessage = C_ChatInfo and C_ChatInfo.SendChatMessage or SendChatMessage

if not GetSpecialization and ExRT.isClassic then
	GetSpecialization = function()
		local n,m = 1,1
		for spec=1,3 do
			local selectedNum = 0
			for talPos=1,22 do
				local name, iconTexture, tier, column, rank, maxRank, isExceptional, available = GetTalentInfo(spec, talPos)
				if name and maxRank > 0 and rank > 0 then
					selectedNum = selectedNum + 1
				end
			end
			if selectedNum > m then
				n = spec
				m = selectedNum
			end
		end
		return n
	end
end

do
	local antiSpamArr = {}
	function ExRT.F.AntiSpam(numantispam,addtime)
		local t = GetTime()
		if not antiSpamArr[numantispam] or antiSpamArr[numantispam] < t then
			antiSpamArr[numantispam] = t + addtime
			return true
		else
			return false
		end
	end
	function ExRT.F.ResetAntiSpam(numantispam)
		antiSpamArr[numantispam] = nil
	end
end

do
	--Used GLOBALS: CUSTOM_CLASS_COLORS

	local classColorArray = nil
	function ExRT.F.classColor(class)
		classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
		if classColorArray and classColorArray.colorStr then
			return classColorArray.colorStr
		else
			return "ffbbbbbb"
		end
	end

	function ExRT.F.classColorNum(class)
		classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
		if classColorArray then
			return classColorArray.r,classColorArray.g,classColorArray.b
		else
			return 0.8,0.8,0.8
		end
	end

	function ExRT.F.classColorByGUID(guid)
		local class,_ = ""
		if guid and guid ~= "" and guid ~= "0000000000000000" then
			_,class = GetPlayerInfoByGUID(guid)
		end
		return ExRT.F.classColor(class)
	end
end

function ExRT.F.clearTextTag(text,SpellLinksEnabled)
	if text then
		text = string_gsub(text,"|c........","")
		text = string_gsub(text,"|r","")
		text = string_gsub(text,"|T.-:0|t ","")
		text = string_gsub(text,"|HExRT:.-|h(.-)|h","%1")
		if SpellLinksEnabled then
			text = string_gsub(text,"|H(spell:.-)|h(.-)|h","|cff71d5ff|H%1|h[%2]|h|r")
		else
			text = string_gsub(text,"|H(spell:.-)|h(.-)|h","%2")
		end
		return text
	end
end

function ExRT.F.splitLongLine(text,maxLetters,SpellLinksEnabled)
	maxLetters = maxLetters or 250
	local result = {}
	repeat
		local lettersNow = maxLetters
		if SpellLinksEnabled then
			local lastC = 0
			local lastR = 0
			for i=1,(maxLetters-1) do
				local word = string.sub(text,i,i+1)
				if word == "|c" then
					lastC = i
				elseif word == "|r" then
					lastR = i
				end
			end
			if lastC > 0 and lastC > lastR then
				lettersNow = lastC - 1
			end
		end

		local utf8pos = 1
		local textLen = string.len(text)
		while true do
			local char = string.sub(text,utf8pos,utf8pos)
			local c = char:byte()

			local lastPos = utf8pos

			if c > 0 and c <= 127 then
				utf8pos = utf8pos + 1
			elseif c >= 194 and c <= 223 then
				utf8pos = utf8pos + 2
			elseif c >= 224 and c <= 239 then
				utf8pos = utf8pos + 3
			elseif c >= 240 and c <= 244 then
				utf8pos = utf8pos + 4
			else
				utf8pos = utf8pos + 1
			end

			if utf8pos > lettersNow then
				lettersNow = lastPos - 1
				break
			elseif utf8pos >= textLen then
				break
			end
		end
		result[#result + 1] = string.sub(text,1,lettersNow)
		text = string.sub(text,lettersNow+1)
	until string.len(text) < maxLetters
	if string.len(text) > 0 then
		result[#result + 1] = text
	end
	return unpack(result)
end

function ExRT.F:SetScaleFix(scale)
	local l = self:GetLeft()
	local t = self:GetTop()
	local s = self:GetScale()
	if not l or not t or not s then return end

	s = scale / s

	self:SetScale(scale)
	local f = self:GetScript("OnDragStop")

	self:ClearAllPoints()
	self:SetPoint("TOPLEFT",UIParent,"BOTTOMLEFT",l / s,t / s)

	if f then f(self) end
end

function ExRT.F:SetScaleFixTR(scale)
	--local l = self:GetLeft() + self:GetWidth() * self:GetEffectiveScale()
	local l = self:GetRight()
	local t = self:GetTop()
	local s = self:GetScale()
	if not l or not t or not s then return end

	s = scale / s

	self:SetScale(scale)
	local f = self:GetScript("OnDragStop")

	self:ClearAllPoints()
	self:SetPoint("TOPRIGHT",UIParent,"BOTTOMLEFT",l / s,t / s)

	if f then f(self) end
end

function ExRT.F:GetCursorPos()
	local x_f,y_f = GetCursorPosition()
	local s = self.GetEffectiveScale and self:GetEffectiveScale() or self:GetParent():GetEffectiveScale()
	x_f, y_f = x_f/s, y_f/s
	local x,y = self:GetLeft(),self:GetTop()
	x = x_f-x
	y = (y_f-y)*(-1)
	return x,y
end

do
	local function FindAllParents(self,obj)
		while obj do
			if obj == self then
				return true
			end
			obj = obj:GetParent()
		end
	end
	function ExRT.F:IsInFocus(x,y,childs)
		if not x then
			x,y = ExRT.F.GetCursorPos(self)
		end
		local obj
		if GetMouseFoci then
			obj = GetMouseFoci()[1]
		else
			obj = GetMouseFocus()
		end
		if x > 0 and y > 0 and x < self:GetWidth() and y < self:GetHeight() and (obj == self or (childs and FindAllParents(self,obj))) then
			return true
		end
	end
end

function ExRT.F:LockMove(isLocked,touchTexture,dontTouchMouse)
	if isLocked then
		if touchTexture then touchTexture:SetColorTexture(0,0,0,0.3) end
		self:SetMovable(true)
		if not dontTouchMouse then self:EnableMouse(true) end
	else
		if touchTexture then touchTexture:SetColorTexture(0,0,0,0) end
		self:SetMovable(false)
		if not dontTouchMouse then self:EnableMouse(false) end
	end
end

local MAX_RAID_GROUP = 5
if ExRT.isClassic and not ExRT.isBC then
	MAX_RAID_GROUP = 8
end
local DIFF_TO_MAX_GROUP = {
	[8] = 1,	--party mythic
	[1] = 1,	--party normal
	[2] = 1,	--party hc
	[14] = 6,	--raid normal
	[15] = 6,	--raid hc
	[16] = 4,	--raid mythic
	[3] = 2,	--10ppl
	[5] = 2,	--10ppl
	[9] = 8,	--40ppl
	[186] = 8,	--classic 40ppl
	[148] = 4,	--classic 20ppl
	[185] = 4,	--classic 20ppl
	[175] = 2,	--bc 10ppl
	[176] = 5,	--bc 25ppl
	[151] = 6,	--lfr
	[17] = 6,	--lfr
	[7] = 5,	--lfr [legacy]
	[33] = 6,	--timewalk raid
	[18] = 8,	--event 40ppl
	[193] = 2,	--10ppl hc
	[194] = 5,	--25ppl hc
}
function ExRT.F.GetRaidDiffMaxGroup()
	local _,instance_type,difficulty = GetInstanceInfo()
	if (instance_type == "party" or instance_type == "scenario") and not IsInRaid() then
		return 1
	elseif instance_type ~= "raid" then
		return 8
	elseif difficulty and DIFF_TO_MAX_GROUP[difficulty] then
		return DIFF_TO_MAX_GROUP[difficulty]
	else
		return MAX_RAID_GROUP
	end
end

function ExRT.F.GetDifficultyForCooldownReset()
	local _,_,difficulty = GetInstanceInfo()
	if difficulty == 3 or difficulty == 4 or difficulty == 5 or difficulty == 6 or difficulty == 7 or difficulty == 14 or difficulty == 15 or difficulty == 16 or difficulty == 17 or (ExRT.isLK and (difficulty == 175 or difficulty == 176 or difficulty == 193 or difficulty == 194)) then
		return true
	end
	return false
end

function ExRT.F.Round(i)
	return floor(i+0.5)
end

function ExRT.F.NumberInRange(i,mi,mx,incMi,incMx)
	if i and ((incMi and i >= mi) or (not incMi and i > mi)) and ((incMx and i <= mx) or (not incMx and i < mx)) then
		return true
	end
end

function ExRT.F.delUnitNameServer(unitName)
	unitName = strsplit("-",unitName)
	return unitName
end

function ExRT.F.UnitCombatlogname(unit)
	local name,server = UnitName(unit or "?")
	if issecretvalue and issecretvalue(name) then
		return
	end
	if name and server and server~="" then
		name = name .. "-" .. server
	end
	return name
end

do
	local old_types = {
		Player = 0,
		Creature = 3,
		Pet = 4,
		Vehicle = 5,
		GameObject = 6,		--NEW
		Vignette = 7,		--NEW
		Item = 8,		--NEW Item:976:0:4000000003A91C1A
		Uniq = 9,		--NEW
	}
	function ExRT.F.GetUnitTypeByGUID(guid)
		if guid then
			local _type = string_match(guid,"^([A-z]+)%-")
			if _type then
				return old_types[_type]
			end
		end
	end
end

function ExRT.F.UnitIsPlayerOrPet(guid)
	local id = ExRT.F.GetUnitTypeByGUID(guid)
	if id == 0 or id == 4 then
		return true
	end
end

function ExRT.F.GetUnitInfoByUnitFlag(unitFlag,infoType)
	--> TYPE
	if infoType == 1 then
		return bit_band(unitFlag,COMBATLOG_OBJECT_TYPE_MASK)
		--[1024]="player", [2048]="NPC", [4096]="pet", [8192]="GUARDIAN", [16384]="OBJECT"

	--> CONTROL
	elseif infoType == 2 then
		return bit_band(unitFlag,COMBATLOG_OBJECT_CONTROL_MASK)
		--[256]="by players", [512]="by NPC",

	--> REACTION
	elseif infoType == 3 then
		return bit_band(unitFlag,COMBATLOG_OBJECT_REACTION_MASK)
		--[16]="FRIENDLY", [32]="NEUTRAL", [64]="HOSTILE"

	--> Controller affiliation
	elseif infoType == 4 then
		return bit_band(unitFlag,COMBATLOG_OBJECT_AFFILIATION_MASK)
		--[1]="player", [2]="PARTY", [4]="RAID", [8]="OUTSIDER"

	--> Special
	elseif infoType == 5 then
		return bit_band(unitFlag,COMBATLOG_OBJECT_SPECIAL_MASK)
		--Not all !  [65536]="TARGET", [131072]="FOCUS", [262144]="MAINTANK", [524288]="MAINASSIST"
	end
end

function ExRT.F.UnitIsFriendlyByUnitFlag(unitFlag)
	if ExRT.F.GetUnitInfoByUnitFlag(unitFlag,2) == 256 then
		return true
	end
end

function ExRT.F.UnitIsFriendlyByUnitFlag2(unitFlag)
	local reaction = ExRT.F.GetUnitInfoByUnitFlag(unitFlag or 0,3)
	if reaction == 16 then
		return true
	elseif reaction == 32 then
		if ExRT.F.GetUnitInfoByUnitFlag(unitFlag,2) == 256 then
			return true
		end
	end
end

function ExRT.F.dprint(...)
	return nil
end
function ExRT.F.dtime(...)
	return nil
end
if ExRT.isDev then	--debug or debug ultra
	ExRT.F.dprint = function(...)
		print(...)
	end
	local debugprofilestop = debugprofilestop
	local lastTime = nil
	ExRT.F.dtime = function(arg,...)
		if arg and lastTime then
			arg[#arg+1] = {debugprofilestop() - lastTime,...}
		else
			lastTime = debugprofilestop()
		end
	end
end

local GetSpellLink = C_Spell and C_Spell.GetSpellLink or GetSpellLink
function ExRT.F.LinkSpell(SpellID,SpellLink)
	if not SpellLink then
		SpellLink = GetSpellLink(SpellID)
	end
	if SpellLink then
		if ChatEdit_GetActiveWindow() then
			ChatEdit_InsertLink(SpellLink)
		else
			ChatFrame_OpenChat(SpellLink)
		end
	end
end

function ExRT.F.LinkItem(itemID, itemLink)
	if not itemLink then
		if not itemID then 
			return 
		end
		itemLink = select(2,GetItemInfo(itemID))
	end
	if not itemLink then
		return
	end
	if IsModifiedClick("DRESSUP") then
		return DressUpItemLink(itemLink)
	else
		if ChatEdit_GetActiveWindow() then
			ChatEdit_InsertLink(itemLink)
		else
			ChatFrame_OpenChat(itemLink)
		end
	end
end

function ExRT.F.shortNumber(num)
	if num < 1000 then
		return tostring(num)
	elseif num < 1000000 then
		return format("%.1fk",num/1000)
	elseif num < 1000000000 then
		return format("%.2fm",num/1000000)
	else
		return format("%.3fM",num/1000000000)
	end
end

function ExRT.F.classIconInText(class,size)
	if CLASS_ICON_TCOORDS[class] then
		size = size or 0
		if class == "EVOKER" then
			return "|Tinterface\\icons\\classicon_evoker:"..size..":"..size.."|t"
		else
			return "|TInterface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES:"..size..":"..size..":0:0:256:256:".. floor(CLASS_ICON_TCOORDS[class][1]*256) ..":"..floor(CLASS_ICON_TCOORDS[class][2]*256) ..":"..floor(CLASS_ICON_TCOORDS[class][3]*256) ..":"..floor(CLASS_ICON_TCOORDS[class][4]*256) .."|t"
		end
	end
end

function ExRT.F.GUIDtoID(guid)
	local type,_,serverID,instanceID,zoneUID,id,spawnID = strsplit("-", guid or "")
	return tonumber(id or 0)
end

function ExRT.F.table_copy(table1,table2)
	table.wipe(table2)
	for key,val in pairs(table1) do
		table2[key] = val
	end
end

function ExRT.F.table_copy2(table1)
	local table2 = {}
	for key,val in pairs(table1) do
		if type(val) == 'table' then
			table2[key] = ExRT.F.table_copy2(val)
		else
			table2[key] = val
		end
	end
	return table2
end

function ExRT.F.table_wipe(arr)
	if not arr or type(arr) ~= "table" then
		return
	end
	for key,val in pairs(arr) do
		if type(val) == "table" then
			ExRT.F.table_wipe(val)
		end
		arr[key] = nil
	end
end

function ExRT.F.table_find(arr,subj,pos)
	if pos then
		for j=1,#arr do
			if arr[j][pos] == subj then
				return j
			end
		end
	else
		for j=1,#arr do
			if arr[j] == subj then
				return j
			end
		end
	end
end

function ExRT.F.table_find2(arr,subj)
	for key,val in pairs(arr) do
		if val == subj then
			return key
		end
	end
end

function ExRT.F.table_find3(arr,subj,pos)
	for j=1,#arr do
		if arr[j][pos] == subj then
			return arr[j]
		end
	end
end

function ExRT.F.table_len(arr)
	local len = 0
	for _ in pairs(arr) do
		len = len + 1
	end
	return len
end

function ExRT.F.table_add(arr,add)
	for i=1,#add do
		arr[#arr+1] = add[i]
	end
end

function ExRT.F.table_add2(arr,add)
	for key,val in pairs(add) do
		arr[key] = val
	end
end

function ExRT.F.table_keys(arr)
	local r = {}
	for key,val in pairs(arr) do
		r[#r+1] = key
	end
	return r
end

do
	local function swap(array, index1, index2)
		array[index1], array[index2] = array[index2], array[index1]
	end
	local math_random = math.random
	function ExRT.F.table_shuffle(array)
		local counter = #array
		while counter > 1 do
			local index = math_random(counter)
			swap(array, index, counter)
			counter = counter - 1
		end
	end
end

do
	local printDiff = false
	local printTable = nil
	local function cmp(t1,t2,r,p)
		local c,t = 0,0
		if type(t1) ~= "table" or type(t2) ~= "table" then
			return c, t
		end
		p = p or "."
		for k,v in pairs(t1) do
			if type(v) == "table" then
				if type(t2[k]) == "table" then
					local c2,t2 = cmp(v,t2[k],false,p..k..".")
					c = c + c2
					t = t + t2
				else
					t = t + 1
					if printTable then
						printTable[p..k] = true
					elseif printDiff then
						print(p..k)
					end
				end
			else
				t = t + 1
				if t1[k] == t2[k] then
					c = c + 1
				elseif type(v) == "number" and type(t2[k]) == "number" and tostring(v) == tostring(t2[k]) then
					c = c + 1
				elseif printTable then
					printTable[p..k] = true
				elseif printDiff then
					print(p..k)
				end
			end
		end
		if not r then
			local c2,t2 = cmp(t2,t1,true,p)
			c = c + c2
			t = t + t2
		end
		return c, t
	end
	function ExRT.F.table_compare(t1,t2,showDiff)
		printDiff = showDiff
		if type(printDiff) == "table" then
			printTable = printDiff
			printDiff = nil
		else
			printTable = nil
		end
		local c, t = cmp(t1,t2)
	
		return c / max(1,t), c, t
	end
end

function ExRT.F.table_rewrite(t1,t2)
	local toRemove = {}
	for k,v in pairs(t1) do
		if not t2[k] then
			toRemove[k] = true
		elseif type(v) == "table" and type(t2[k]) == "table" then
			ExRT.F.table_rewrite(v,t2[k])
		else
			t1[k] = t2[k]
		end
	end
	for k,v in pairs(toRemove) do
		t1[k] = nil
	end
	for k,v in pairs(t2) do
		if not t1[k] then
			t1[k] = v
		end
	end
end

function ExRT.F.table_random(t)
	local keys_num = 0
	for k,v in pairs(t) do
		keys_num = keys_num + 1
	end
	if keys_num == 0 then return end
	local key_need = math.random(1,keys_num)
	keys_num = 0
	for k,v in pairs(t) do
		keys_num = keys_num + 1
		if keys_num == key_need then
			return v
		end
	end
end

local sort_f = function(a,b) return a[1]<b[1] end
function ExRT.F.table_to_string(t)
	if type(t)~="table" then return end
	local keys = {}
	local res = {}
	for q,w in pairs(t) do
		if type(q)~="function" and type(q)~="table" and not (w=="") then
			keys[#keys+1]={tostring(q),w}
		end
	end
	sort(keys,sort_f)
	for i=1,#keys do
		local v = keys[i][2]
		res[#res+1] = keys[i][1] .. "=" .. (type(v)=="table" and ExRT.F.table_to_string(v) or type(v)=="function" and "<f>" or tostring(v))
	end
	local str = "{"..table.concat(res,",").."}"
	return str
end

function ExRT.F.table_keys_to_string(t,sep)
	local str = ""
	for k in pairs(t) do
		str = str .. (str ~= "" and (sep or " ") or "") .. k
	end
	return str
end

function ExRT.F.tohex(num,size)
	return format("%0"..(size or "1").."X",num)
end

function ExRT.F.UnitInGuild(unit)
	local sunit = ExRT.F.delUnitNameServer(unit)
	local gplayers = GetNumGuildMembers() or 0
	for i=1,gplayers do
		local name = GetGuildRosterInfo(i)
		if name and ExRT.F.delUnitNameServer(name) == sunit then
			return true
		end
	end
	if UnitIsInMyGuild(unit) or UnitIsInMyGuild(sunit) then
		return true
	end
	return false
end

function ExRT.F.chatType(toSay)
	local isInInstance = IsInGroup(LE_PARTY_CATEGORY_INSTANCE)
	local isInParty = IsInGroup()
	local isInRaid = IsInRaid()
	local playerName = nil
	local chat_type = (isInInstance and "INSTANCE_CHAT") or (isInRaid and "RAID") or (isInParty and "PARTY")
	if not chat_type and not toSay then
		chat_type = "WHISPER"
		playerName = UnitName("player") 
	elseif not chat_type then
		chat_type = "SAY"
	end
	return chat_type, playerName
end

function ExRT.F.IsBonusOnItem(link,bonus)
	if link then 
		local _,itemID,enchant,gem1,gem2,gem3,gem4,suffixID,uniqueID,level,specializationID,upgradeType,instanceDifficultyID,numBonusIDs,restLink = strsplit(":",link,15)
		if restLink then
			local bonuses = {strsplit(":",strsplit("|h",restLink),nil)}
			numBonusIDs = tonumber(numBonusIDs) or 0
			local isTable = type(bonus) == "table"
			for i = 1, numBonusIDs do
				local bonusID = tonumber(bonuses[i]) or -999
				if (isTable and bonus[bonusID]) or (not isTable and bonusID == bonus) then
					return true
				end
			end
		end
	end
end

function ExRT.F.GetItemBonuses(link)
	if link then 
		local _,itemID,enchant,gem1,gem2,gem3,gem4,suffixID,uniqueID,level,specializationID,upgradeType,instanceDifficultyID,numBonusIDs,restLink = strsplit(":",link:match("|H.-|h") or link,15)
		numBonusIDs = tonumber(numBonusIDs or "?") or 0
		local bonusStr = ""
		for i=1,numBonusIDs do
			local bonus = select(i,strsplit(":",restLink))
			if bonus then
				bonusStr = bonusStr .. bonus .. ":"
			end
		end
		bonusStr = strtrim(bonusStr,":")
		return bonusStr,numBonusIDs
	end
	return "",0
end
--/dump GMRT.F.GetItemBonuses(select(2,GameTooltip:GetItem()))

function ExRT.F.IsPlayerRLorOfficer(unitName)
	local shortName = ExRT.F.delUnitNameServer(unitName)
	for i=1,GetNumGroupMembers() do
		local name,rank = GetRaidRosterInfo(i)
		if UnitIsUnit(unitName,"raid"..i) or UnitIsUnit(shortName,"raid"..i) then
			if rank > 0 then
				return rank
			else
				return false
			end
		end
	end

	-- nil: not in party or raid
	-- false: no rl, no officer
	-- 1: officer
	-- 2: rl
end

if ExRT.isMN then
	function ExRT.F.IsPlayerRLorOfficer(unitName)
		unitName = Ambiguate(unitName,"none") or unitName
		if UnitIsGroupLeader(unitName) then
			return 2
		elseif UnitIsGroupAssistant(unitName) then
			return 1
		else
			return false
		end
	end
end

function ExRT.F.GetPlayerParty(unitName)
	for i=1,GetNumGroupMembers() do
		local name,_,subgroup = GetRaidRosterInfo(i)
		if (not C_Secrets or not C_Secrets.ShouldUnitComparisonBeSecret(name,unitName)) and name and UnitIsUnit(name,unitName) then
			return subgroup
		end
	end
	return 0
end

function ExRT.F.GetOwnPartyNum()
	for i=1,GetNumGroupMembers() do
		local name,_,subgroup = GetRaidRosterInfo(i)
		if (not C_Secrets or not C_Secrets.ShouldUnitComparisonBeSecret(name,'player')) and name and UnitIsUnit(name,'player') then
			return subgroup
		end
	end
	return 1
end
if ExRT.isMN then
	function ExRT.F.GetOwnPartyNum()
		local shortName = UnitName'player'
		for i=1,GetNumGroupMembers() do
			local name,_,subgroup = GetRaidRosterInfo(i)
			if (not canaccessvalue or canaccessvalue(name)) and name and shortName == ExRT.F.delUnitNameServer(name) then
				return subgroup
			end
		end
		return 1
	end
end


function ExRT.F.CreateAddonMsg(...)
	local result = ""
	for i=1,select('#',...) do
		local a = select(i,...)
		result = result..(result ~= "" and "\t" or "")..tostring(a)
	end
	return result
end

function ExRT.F.GetPlayerRole(checkNotInGroup)
	local role = UnitGroupRolesAssigned('player')
	if (not role or role == "NONE") and checkNotInGroup and GetSpecializationInfo then
		role = select(5,GetSpecializationInfo(GetSpecialization() or 0))
	end
	if role == "HEALER" then
		local _,class = UnitClass('player')
		return role, (class == "PALADIN" or class == "MONK") and "MHEALER" or "RHEALER"
	elseif role ~= "DAMAGER" then
		--TANK, NONE
		return role
	else
		local _,class = UnitClass('player')
		local isMelee = (class == "WARRIOR" or class == "PALADIN" or class == "ROGUE" or class == "DEATHKNIGHT" or class == "MONK" or class == "DEMONHUNTER")
		if class == "DRUID" then
			isMelee = GetSpecialization() ~= 1
		elseif class == "SHAMAN" then
			isMelee = GetSpecialization() == 2
		elseif class == "HUNTER" then
			isMelee = GetSpecialization() == 3
		end
		if isMelee then
			return role, "MDD"
		else
			return role, "RDD"
		end
	end
end

function ExRT.F.GetUnitRole(unit)
	local role = UnitGroupRolesAssigned(unit)
	if role == "HEALER" then
		local _,class = UnitClass(unit)
		return role, (class == "PALADIN" or class == "MONK") and "MHEALER" or "RHEALER"
	elseif role ~= "DAMAGER" then
		--TANK, NONE
		return role
	else
		local _,class = UnitClass(unit)
		local isMelee = (class == "WARRIOR" or class == "PALADIN" or class == "ROGUE" or class == "DEATHKNIGHT" or class == "MONK" or class == "DEMONHUNTER")
		if class == "DRUID" then
			isMelee = not (UnitPowerType(unit) == 8)	--astral power
		elseif class == "SHAMAN" then
			isMelee = UnitPowerMax(unit) >= 150
		elseif class == "HUNTER" then
			isMelee = (ExRT.A.Inspect and UnitName(unit) and ExRT.A.Inspect.db.inspectDB[UnitName(unit)] and ExRT.A.Inspect.db.inspectDB[UnitName(unit)].spec) == 255
		end
		if isMelee then
			return role, "MDD"
		else
			return role, "RDD"
		end
	end
end
if ExRT.isClassic and not ExRT.isWoD then
	function ExRT.F.GetPlayerRole()
		local role = UnitGroupRolesAssigned('player')
		if role == "HEALER" then
			local _,class = UnitClass('player')
			return role, (class == "PALADIN" or class == "MONK") and "MHEALER" or "RHEALER"
		elseif role ~= "DAMAGER" then
			--TANK, NONE
			return role
		else
			local _,class = UnitClass('player')
			local isMelee = (class == "WARRIOR" or class == "PALADIN" or class == "ROGUE" or class == "DEATHKNIGHT" or class == "MONK" or class == "DEMONHUNTER")
			if class == "DRUID" then
				isMelee = GetSpecialization() ~= 1
			elseif class == "SHAMAN" then
				isMelee = GetSpecialization() == 2
			elseif class == "HUNTER" then
				isMelee = false
			end
			if isMelee then
				return role, "MDD"
			else
				return role, "RDD"
			end
		end
	end
	
	function ExRT.F.GetUnitRole(unit)
		local role = UnitGroupRolesAssigned(unit)
		if role == "HEALER" then
			local _,class = UnitClass(unit)
			return role, (class == "PALADIN" or class == "MONK") and "MHEALER" or "RHEALER"
		elseif role ~= "DAMAGER" then
			--TANK, NONE
			return role
		else
			local _,class = UnitClass(unit)
			local isMelee = (class == "WARRIOR" or class == "PALADIN" or class == "ROGUE" or class == "DEATHKNIGHT" or class == "MONK" or class == "DEMONHUNTER")
			if class == "DRUID" then
				isMelee = not (UnitPowerType(unit) == 8)	--astral power
			elseif class == "SHAMAN" then
				isMelee = UnitPowerMax(unit) >= 150
			elseif class == "HUNTER" then
				isMelee = false
			end
			if isMelee then
				return role, "MDD"
			else
				return role, "RDD"
			end
		end
	end
end

function ExRT.F.TextureToText(textureName,widthInText,heightInText,textureWidth,textureHeight,leftTexCoord,rightTexCoord,topTexCoord,bottomTexCoord)
	return "|T"..textureName..":"..(widthInText or 0)..":"..(heightInText or 0)..":0:0:"..textureWidth..":"..textureHeight..":"..
		format("%d",leftTexCoord*textureWidth)..":"..format("%d",rightTexCoord*textureWidth)..":"..format("%d",topTexCoord*textureHeight)..":"..format("%d",bottomTexCoord*textureHeight).."|t"
end
function ExRT.F.GetRaidTargetText(icon,size)
	size = size or 0
	return ExRT.F.TextureToText([[Interface\TargetingFrame\UI-RaidTargetingIcons]],size,size,256,256,((icon-1)%4)/4,((icon-1)%4+1)/4,floor((icon-1)/4)/4,(floor((icon-1)/4)+1)/4)
end

function ExRT.F.IterateMediaData(mediaType)
	local list
	if LibStub then
		local loaded,media = pcall(LibStub,"LibSharedMedia-3.0")
		if loaded and media then
			list = media:HashTable(mediaType)
		end
	end
	return next, list or {}
end

--[[
	for index, name, subgroup, class, guid, rank, level, online, isDead, combatRole in ExRT.F.IterateRoster do
		<...>
	end
]]
function ExRT.F.IterateRoster(maxGroup,index)
	index = (index or 0) + 1
	maxGroup = maxGroup or 8

	if IsInRaid() then
		if index > GetNumGroupMembers() then
			return
		end
		local name, rank, subgroup, level, class, fileName, zone, online, isDead, role, isML, combatRole = GetRaidRosterInfo(index)
		if subgroup > maxGroup then
			return ExRT.F.IterateRoster(maxGroup,index)
		end
		local guid = UnitGUID("raid"..index)
		name = name or ""
		return index, name, subgroup, fileName, guid, rank, level, online, isDead, combatRole, "raid"..index
	else
		local name, rank, subgroup, level, class, fileName, online, isDead, combatRole, _

		local unit = index == 1 and "player" or "party"..(index-1)

		local guid = UnitGUID(unit)
		if not guid then
			return
		end

		subgroup = 1
		name = GetUnitName(unit, true) or ""
		class, fileName = UnitClass(unit)

		if UnitIsGroupLeader(unit) then
			rank = 2
		else
			rank = 1
		end

		level = UnitLevel(unit)

		if UnitIsConnected(unit) then
			online = true
		end

		if UnitIsDeadOrGhost(unit) then
			isDead = true
		end

		combatRole = UnitGroupRolesAssigned(unit)

		return index, name, subgroup, fileName, guid, rank, level, online, isDead, combatRole, unit
	end
end

function ExRT.F.vpairs(t)
	local prev
	local function it()
		local k,v = next(t,prev)
		prev = k
		return v
	end
	return it
end

function ExRT.F:SafeCall(func, ...)
	local res, arg1, arg2, arg3, arg4, arg5, arg6, arg7 = xpcall(func, geterrorhandler(), ...)
	if res then
		return arg1, arg2, arg3, arg4, arg5, arg6, arg7
	end
end

do
	-- UTF8

	-- returns the number of bytes used by the UTF-8 character at byte i in s
	-- also doubles as a UTF-8 character validator
	local function utf8charbytes(s, i)
		-- argument defaults
		i = i or 1

		-- argument checking
		if type(s) ~= "string" then
			error("bad argument #1 to 'utf8charbytes' (string expected, got ".. type(s).. ")")
		end
		if type(i) ~= "number" then
			error("bad argument #2 to 'utf8charbytes' (number expected, got ".. type(i).. ")")
		end

		local c = strbyte(s, i)

		-- determine bytes needed for character, based on RFC 3629
		-- validate byte 1
		if c > 0 and c <= 127 then
			-- UTF8-1
			return 1

		elseif c >= 194 and c <= 223 then
			-- UTF8-2
			local c2 = strbyte(s, i + 1)

			if not c2 then
				error("UTF-8 string terminated early")
			end

			-- validate byte 2
			if c2 < 128 or c2 > 191 then
				error("Invalid UTF-8 character")
			end

			return 2

		elseif c >= 224 and c <= 239 then
			-- UTF8-3
			local c2 = strbyte(s, i + 1)
			local c3 = strbyte(s, i + 2)

			if not c2 or not c3 then
				error("UTF-8 string terminated early")
			end

			-- validate byte 2
			if c == 224 and (c2 < 160 or c2 > 191) then
				error("Invalid UTF-8 character")
			elseif c == 237 and (c2 < 128 or c2 > 159) then
				error("Invalid UTF-8 character")
			elseif c2 < 128 or c2 > 191 then
				error("Invalid UTF-8 character")
			end

			-- validate byte 3
			if c3 < 128 or c3 > 191 then
				error("Invalid UTF-8 character")
			end

			return 3

		elseif c >= 240 and c <= 244 then
			-- UTF8-4
			local c2 = strbyte(s, i + 1)
			local c3 = strbyte(s, i + 2)
			local c4 = strbyte(s, i + 3)

			if not c2 or not c3 or not c4 then
				error("UTF-8 string terminated early")
			end

			-- validate byte 2
			if c == 240 and (c2 < 144 or c2 > 191) then
				error("Invalid UTF-8 character")
			elseif c == 244 and (c2 < 128 or c2 > 143) then
				error("Invalid UTF-8 character")
			elseif c2 < 128 or c2 > 191 then
				error("Invalid UTF-8 character")
			end

			-- validate byte 3
			if c3 < 128 or c3 > 191 then
				error("Invalid UTF-8 character")
			end

			-- validate byte 4
			if c4 < 128 or c4 > 191 then
				error("Invalid UTF-8 character")
			end

			return 4

		else
			error("Invalid UTF-8 character")
		end
	end

	function ExRT.F.utf8len(s)
		local pos = 1
		local bytes = strlen(s)
		local len = 0

		while pos <= bytes do
			len = len + 1
			pos = pos + utf8charbytes(s, pos)
		end

		return len
	end

	-- functions identically to string.sub except that i and j are UTF-8 characters
	-- instead of bytes
	function ExRT.F.utf8sub(s, i, j)
		-- argument defaults
		j = j or -1

		local pos = 1
		local bytes = strlen(s)
		local len = 0

		-- only set l if i or j is negative
		local l = (i >= 0 and j >= 0) or ExRT.F.utf8len(s)
		local startChar = (i >= 0) and i or l + i + 1
		local endChar   = (j >= 0) and j or l + j + 1

		-- can't have start before end!
		if startChar > endChar then
			return ""
		end

		-- byte offsets to pass to string.sub
		local startByte, endByte = 1, bytes

		while pos <= bytes do
			len = len + 1

			if len == startChar then
				startByte = pos
			end

			pos = pos + utf8charbytes(s, pos)

			if len == endChar then
				endByte = pos - 1
				break
			end
		end

		return strsub(s, startByte, endByte)
	end
end

function ExRT.F.GetFirstTableInText(str)
	local strlen = str:len()
	local i = 1
	local deep = 0
	local start
	local inStr
	local inWideStr
	local wideStrEqCount = 0
	while i <= strlen do
		local b = str:byte(i)
		if not start and not inStr and b == 123 then
			start = i
		elseif start and not inStr and b == 123 then
			deep = deep + 1
		elseif start and not inStr and b == 125 then
			if deep <= 0 then
				return str:sub(start,i)
			else
				deep = deep - 1
			end
		elseif not inStr and b == 34 then	--"
			inStr = i
		elseif inStr and not inWideStr and b == 92 then	--\
			i = i + 1
		elseif inStr and not inWideStr and b == 34 then	--"
			inStr = false
		elseif not inStr and b == 91 then	-- [ = [
			local k = i + 1
			local eqc = 0
			while k <= strlen do
				local c1 = str:byte(k)
				if c1 == 61 then
					eqc = eqc + 1
				elseif c1 == b then
					inStr = i
					inWideStr = i
					wideStrEqCount = eqc
					break
				else
					break
				end
				k = k + 1
			end
		elseif inStr and inWideStr and b == 93 then	-- ] = ]
			local k = i + 1
			local eqc = 0
			while k <= strlen do
				local c1 = str:byte(k)
				if c1 == 61 then
					eqc = eqc + 1
				elseif c1 == b then
					if eqc == wideStrEqCount then
						i = k
						inStr = false
						inWideStr = false
					end
					break
				else
					break
				end
				k = k + 1
			end
		end
		i = i + 1
	end
end

do
	local chatWindow = nil
	local activeChat = "RAID"
	local activeName = ""
	local UpdateLines = nil
	local function CreateChatWindow()
		chatWindow = ELib:Template("ExRTDialogModernTemplate",UIParent)
		_G["MRTToChatWindow"] = chatWindow
		chatWindow:SetSize(400,300)
		chatWindow:SetPoint("CENTER")
		chatWindow:SetFrameStrata("DIALOG")
		chatWindow:SetClampedToScreen(true)
		chatWindow:EnableMouse(true)
		chatWindow:SetMovable(true)
		chatWindow:RegisterForDrag("LeftButton")
		chatWindow:SetDontSavePosition(true)
		chatWindow:SetScript("OnDragStart", function(self) 
			self:StartMoving() 
		end)
		chatWindow:SetScript("OnDragStop", function(self) 
			self:StopMovingOrSizing() 
		end)

		chatWindow.border = ExRT.lib:Shadow(chatWindow,20)

		chatWindow.title:SetText(ExRT.L.ChatwindowName)

		chatWindow.box = ExRT.lib:MultiEdit(chatWindow):Size(230,265):Point(10,-23):Font('x',11)

		local chats = {
			{"ME",ExRT.L.ChatwindowChatSelf},
			{"SAY",ExRT.L.ChatwindowChatSay},
			{"PARTY",ExRT.L.ChatwindowChatParty},
			{"INSTANCE_CHAT",ExRT.L.ChatwindowChatInstance},
			{"RAID",ExRT.L.ChatwindowChatRaid},
			{"WHISPER",ExRT.L.ChatwindowChatWhisper},
			{"TARGET",ExRT.L.ChatwindowChatWhisperTarget},
			{"GUILD",ExRT.L.ChatwindowChatGuild},
			{"OFFICER",ExRT.L.ChatwindowChatOfficer},
		}

		chatWindow.dropDown = ExRT.lib:DropDown(chatWindow,130,#chats):Size(130):Point(255,-60):SetText(ExRT.L.ChatwindowChatRaid)
		chatWindow.dropDownText = ExRT.lib:Text(chatWindow,ExRT.L.ChatwindowChannel,10):Size(350,14):Point("BOTTOMLEFT",chatWindow.dropDown,"TOPLEFT",5,2):Color():Shadow()
		for i=1,#chats do
			local chatData = chats[i]
			chatWindow.dropDown.List[i] = {
				text = chatData[2],
				notCheckable = true,
				justifyH = "CENTER",
				arg1 = chatData[1],
				arg2 = chatData[2],
				func = function (this,arg1,arg2)
					chatWindow.dropDown:SetText(arg2)
					ExRT.lib:DropDownClose()
					activeChat = arg1
				end
			}
		end

		chatWindow.target = ExRT.lib:Edit(chatWindow):Size(130,20):Point(255,-115):OnChange(function (self)
			activeName = self:GetText()
		end)
		chatWindow.targetText = ExRT.lib:Text(chatWindow,ExRT.L.ChatwindowNameEB,10):Size(350,14):Point("BOTTOMLEFT",chatWindow.target,"TOPLEFT",5,2):Bottom():Color():Shadow()

		chatWindow.button = ExRT.lib:Button(chatWindow,ExRT.L.ChatwindowSend):Size(130,22):Point(255,-150):OnClick(function (self)
			local lines = {strsplit("\n", chatWindow.box.EditBox:GetText())}
			local channel = activeChat
			local whisper = activeName
			if channel == "TARGET" then
				channel = "WHISPER"
				whisper = ExRT.F.UnitCombatlogname("target")
				if not whisper then
					return
				end
			end
			if channel == "ME" then
				for i=1,#lines do
					if lines[i] ~= "" then
						print(lines[i])
					end
				end
				chatWindow:Hide()
				return
			end
			if whisper == "" then
				whisper = nil
			end
			for i=1,#lines do
				if lines[i] ~= "" then
					SendChatMessage(lines[i],channel,nil,whisper)
				end
			end
			chatWindow:Hide()
		end)

		chatWindow.helpText = ExRT.lib:Text(chatWindow,ExRT.L.ChatwindowHelp,10):Size(130,100):Point("TOP",chatWindow.button,"BOTTOM",0,-10):Top():Color():Shadow()

		chatWindow.chk1 = ExRT.lib:Check(chatWindow,"Option 1"):Point(255,-260):OnClick(function()
			UpdateLines()
		end)
	end
	function UpdateLines()
		local lines = chatWindow.lines
		if not lines or type(lines)~="table" then
			return
		end
		local editData = ""
		local linesCount = #lines
		local clearTags = chatWindow.clearTags
		local option1 = chatWindow.option1enabled and chatWindow.chk1:GetChecked() and "%1" or ""
		for i=1,linesCount do
			local thisLine = lines[i]
			if thisLine ~= "" then
				thisLine = thisLine:gsub("@1@(.-)@1#",option1)
				if clearTags then
					thisLine = ExRT.F.clearTextTag(thisLine)
				end
				if strlen(thisLine) > 254 then
					thisLine = strjoin("\n",ExRT.F.splitLongLine(thisLine,254))
				end
				editData = editData .. thisLine
				if i ~= linesCount then
					editData = editData .. "\n"
				end
			end
		end
		chatWindow.box.EditBox:SetText(editData)
	end
	function ExRT.F:ToChatWindow(lines,clearTags,option1Name)
		if not lines or type(lines)~="table" then
			return
		end
		if not chatWindow then
			CreateChatWindow()
		end
		chatWindow.lines = lines
		chatWindow.clearTags = clearTags
		chatWindow.option1enabled = option1Name
		if option1Name then
			chatWindow.chk1.text:SetText(option1Name)
			chatWindow.chk1:SetChecked(false)
			chatWindow.chk1:Show()
		else
			chatWindow.chk1:Hide()
		end
		UpdateLines()
		chatWindow:Show()
	end
end

do
	local alertWindow = nil
	local alertFunc = nil
	local alertArg1 = nil
	local function CreateWindow()
		alertWindow = ExRT.lib:Popup():Size(500,65)
		alertWindow:SetFrameStrata("FULLSCREEN_DIALOG")

		alertWindow.EditBox = ExRT.lib:Edit(alertWindow):Size(480,16):Point("TOP",0,-20)

		alertWindow.OK = ExRT.lib:Button(alertWindow,ACCEPT):Size(130,20):Point("TOP",0,-40):OnClick(function (self)
			alertWindow:Hide()
			local input = alertWindow.EditBox:GetText()
			alertFunc(alertArg1,input)
		end)

		alertWindow.EditBox:SetScript("OnEnterPressed",function (self)
			self:GetParent().OK:Click("LeftButton")
		end)
	end
	function ExRT.F.ShowInput(text,func,arg1,onlyNum,defText,funcOnEdit)
		if not alertWindow then
			CreateWindow()
		end
		alertWindow.OK:Enable()
		alertWindow.title:SetText(text)
		alertWindow.EditBox:SetScript("OnTextChanged",funcOnEdit)
		alertWindow.EditBox:SetText(defText or "")
		alertWindow:ClearAllPoints()
		alertWindow:SetPoint("CENTER",UIParent,0,0)
		alertFunc = func
		alertArg1 = arg1
		if onlyNum then
			alertWindow.EditBox:SetNumeric(true)
		else
			alertWindow.EditBox:SetNumeric(false)
		end
		alertWindow:Show()
		alertWindow.EditBox:SetFocus()
	end
	function ExRT.F.ShowText(text)
		if not alertWindow then
			CreateWindow()
		end
		alertWindow.title:SetText("")
		alertWindow:ClearAllPoints()
		alertWindow:SetPoint("CENTER",UIParent,0,0)
		alertWindow.EditBox:SetNumeric(false)
		alertWindow.EditBox:SetText(text)
		alertWindow:Show()
		alertWindow.EditBox:SetFocus()
		alertFunc = ExRT.NULLfunc
	end
end

do
	local alertWindow = nil
	local alertFunc = nil
	local alertArg1 = nil
	local ce = 0
	local function CreateEdit()
		ce = ce + 1
		local e = alertWindow.EditBox[ce]
		if not e then
			e = ELib:Edit(alertWindow):Size(400,16):Point("TOPLEFT",90,-20-(ce-1)*20)
			alertWindow.EditBox[ce] = e

			e:SetScript("OnEnterPressed",function (self)
				self:GetParent().OK:Click("LeftButton")
			end)
		end
		e:Show()

		return alertWindow.EditBox[ce]
	end
	local function CreateWindow()
		alertWindow = ExRT.lib:Popup():Size(500,65)
		alertWindow:SetFrameStrata("FULLSCREEN_DIALOG")

		alertWindow.EditBox = {}

		alertWindow.OK = ExRT.lib:Button(alertWindow,ACCEPT):Size(130,20):Point("BOTTOM",0,3):OnClick(function (self)
			alertWindow:Hide()
			local r = {}
			for i=1,#alertWindow.EditBox do
				local e = alertWindow.EditBox[i]
				local input = e:GetText()
				r[i] = input
			end
			alertFunc(r)
		end)
	end
	function ExRT.F.ShowInput2(text,func,...)
		if not alertWindow then
			CreateWindow()
		end
		ce = 0
		alertWindow.title:SetText(text)
		for i=1,select("#",...) do
			local opt = select(i,...)
			
			local e = CreateEdit()
			e:LeftText(type(opt) == "table" and opt.text or opt)
			e:SetScript("OnTextChanged",type(opt) == "table" and opt.funcOnEdit or nil)
			e:Tooltip(type(opt) == "table" and opt.tip or nil)
			e:SetText(type(opt) == "table" and opt.defText or "")
			if type(opt) == "table" and opt.onlyNum then
				e:SetNumeric(true)
			else
				e:SetNumeric(false)
			end
		end
		alertFunc = func

		alertWindow:ClearAllPoints()
		alertWindow:SetPoint("CENTER",UIParent,0,0)
		alertWindow:SetHeight(45+20*ce)
		alertWindow:Show()
		alertWindow.EditBox[1]:SetFocus()
	end
end

---------------> Chat links hook <---------------
do
	local chatLinkFormat = "|HMRT:%s:0|h|cffffff00[MRT: %s]|r|h"
	local funcTable = {}
	local function createChatHook()
		local SetHyperlink = ItemRefTooltip.SetHyperlink
		function ItemRefTooltip:SetHyperlink(link, ...)
			local funcName = link:match("^MRT:([^:]+):")
			if funcName then
				local func = funcTable[funcName]
				if not func then
					return
				end
				func()
			else
				SetHyperlink(self, link, ...)
			end
		end
	end

	function ExRT.F.CreateChatLink(funcName,func,stringName)
		if createChatHook then createChatHook() createChatHook = nil end
		if not funcName or not stringName or type(func) ~= "function" then
			return ""
		end
		funcTable[funcName] = func
		return chatLinkFormat:format(funcName,stringName)
	end
end
---------------> Export Window <---------------
do
	local exportWindow
	function ExRT.F:Export(stringData,hideTextInfo,windowName,onChangeFunc)
		if not exportWindow then
			exportWindow = ELib:Popup(ExRT.L.Export):Size(650,615)
			exportWindow.Edit = ELib:MultiEdit(exportWindow):Point("TOP",0,-20):Size(640,575)
			exportWindow.TextInfo = ELib:Text(exportWindow,ExRT.L.ExportInfo,11):Color():Point("BOTTOM",0,3):Size(640,15):Bottom():Left()
			exportWindow:SetScript("OnHide",function(self)
				self.Edit:SetText("")
			end)
			exportWindow.Next = ExRT.lib:Button(exportWindow,">>>"):Size(100,16):Point("BOTTOMRIGHT",0,0):OnClick(function (self)
				self.now = self.now + 1
				self:SetText(">>> "..self.now.."/"..#exportWindow.hugeText)
				exportWindow.Edit:SetText(exportWindow.hugeText[self.now])
				exportWindow.Edit.EditBox:HighlightText()
				exportWindow.Edit.EditBox:SetFocus()
				if self.now == #exportWindow.hugeText then
					self:Hide()
				end
			end)
		end
		exportWindow.title:SetText(windowName or ExRT.L.Export)
		exportWindow.Edit.OnTextChanged = onChangeFunc
		exportWindow:NewPoint("CENTER",UIParent,0,0)
		exportWindow.TextInfo:SetShown(not hideTextInfo)
		exportWindow:Show()
		if #stringData > 200000 then
			exportWindow.hugeText = {}
			while stringData and stringData ~= "" do
				local newText = stringData:sub(1,200000)..strsplit("\n",stringData:sub(200001))
				exportWindow.hugeText[#exportWindow.hugeText+1] = newText
				stringData = select(2,strsplit("\n",stringData:sub(200001),2))
			end
			exportWindow.Next.now = 0
			exportWindow.Next:Show()
			exportWindow.Next:Click()
		else
			exportWindow.hugeText = nil
			exportWindow.Next:Hide()
			exportWindow.Edit:SetText(stringData)
			exportWindow.Edit.EditBox:HighlightText()
			exportWindow.Edit.EditBox:SetFocus()
		end
	end

end

do
	local exportWindow
	local pendingToShow
	function ExRT.F:Export2(stringData)
		if not exportWindow then
			exportWindow = ExRT.lib:Popup("Export"):Size(650,50)
			exportWindow.Edit = ExRT.lib:Edit(exportWindow):Point("TOP",0,-20):Size(640,25)
			exportWindow:SetScript("OnHide",function(self)
				self.Edit:SetText("")
				self.onEnterFunc = nil
				if pendingToShow then
					stringData = select(2,next(pendingToShow))
					if not stringData then
						pendingToShow = nil
						return
					end
					tremove(pendingToShow, 1)
					C_Timer.After(0,function()
						exportWindow.Edit:SetText(stringData)
						exportWindow:Show()
					end)
				end
			end)
			exportWindow.Edit:SetScript("OnEditFocusGained", function(self)
				self:HighlightText()
			end)
			exportWindow.Edit:SetScript("OnMouseUp", function(self, button)
				self:HighlightText()
				if button == "RightButton" then
					self:GetParent():Hide()
				end
			end)
			exportWindow.Edit:SetScript("OnKeyUp", function(self, c)
				if (c == "c" or c == "C") and IsControlKeyDown() then
					self:GetParent():Hide()
				end
			end)
			exportWindow.Edit:SetScript("OnEnterPressed",function(self)
				if self:GetParent().onEnterFunc then
					self:GetParent().onEnterFunc(self:GetText())
					self:GetParent():Hide()
				end
			end)
			function exportWindow:OnShow()
				self.Edit:SetFocus()
			end  
		elseif exportWindow:IsShown() then
			if not pendingToShow then
				pendingToShow = {}
			end
			pendingToShow[#pendingToShow+1] = stringData
			return

		end

		if type(stringData) == "function" then
			exportWindow.onEnterFunc = stringData
			stringData = ""
		else
			exportWindow.onEnterFunc = nil
		end

		if type(stringData) == "table" then
			stringData = table.concat(ExRT.F.TableToText(stringData))
		elseif type(stringData) ~= "string" then
			stringData = tostring(stringData)
		end

		exportWindow:NewPoint("CENTER",UIParent,0,0)
		exportWindow.Edit:SetText(stringData)
		exportWindow:Show()
	end
end
---------------> Profiling Window <---------------
do
	local profilingWindow
	function ExRT.F:ProfilingWindow()
		if not profilingWindow then
			profilingWindow = ExRT.lib:Popup("Profiling"):Size(700,300)
			local self = profilingWindow

			profilingWindow.decorationLine = ELib:DecorationLine(self,true,"BACKGROUND",-5):Point("TOPLEFT",self,0,-15):Point("BOTTOMRIGHT",self,"TOPRIGHT",0,-35)
		
			profilingWindow.list = ELib:ScrollTableList(self,300,80,80,80,80,0):Size(700,300-35-25):Point("TOP",0,-35):FontSize(11):HideBorders()
		
			profilingWindow.headertext1 = ELib:Text(self,"  Event"):Point("LEFT",self.list,2,0):Point("TOP",self.decorationLine,0,0):Size(300,20):Left():Middle():Color():Shadow()
			profilingWindow.headertext2 = ELib:Text(self,"Total, ms"):Point("LEFT",self.headertext1,"RIGHT",0,0):Point("TOP",self.decorationLine,0,0):Size(80,20):Left():Middle():Color():Shadow()
			profilingWindow.headertext3 = ELib:Text(self,"Count"):Point("LEFT",self.headertext2,"RIGHT",0,0):Point("TOP",self.decorationLine,0,0):Size(80,20):Left():Middle():Color():Shadow()
			profilingWindow.headertext4 = ELib:Text(self,"Peak"):Point("LEFT",self.headertext3,"RIGHT",0,0):Point("TOP",self.decorationLine,0,0):Size(80,20):Left():Middle():Color():Shadow()
			profilingWindow.headertext5 = ELib:Text(self,"Per 1, ms"):Point("LEFT",self.headertext4,"RIGHT",0,0):Point("TOP",self.decorationLine,0,0):Size(80,20):Left():Middle():Color():Shadow()
			profilingWindow.headertext6 = ELib:Text(self,"Per sec, ms"):Point("LEFT",self.headertext5,"RIGHT",0,0):Point("TOP",self.decorationLine,0,0):Size(80,20):Left():Middle():Color():Shadow()

			local t = 0
			profilingWindow:SetScript("OnUpdate",function(self,elapsed)
				t = t + elapsed
				if t < 0.5 then
					return
				end
				t = t % 0.5

				profilingWindow.nextBoss:SetEnabled(not ExRT.F:IsProfilingBoss())

				if not ExRT.Profiling.Start then
					return
				end

				local r,total = {},{"Total",0,"","","",0}
				local now = (ExRT.Profiling.End or debugprofilestop()) - ExRT.Profiling.Start
				for event in pairs(ExRT.Profiling.T) do
					local t = ExRT.Profiling.T[event]
					local c = ExRT.Profiling.C[event]
					local m = ExRT.Profiling.M[event]
			
					r[#r+1] = {event,format("%.1f",t),c,format("%.1f",m),format("%.1f",t/c),format("%.1f",t/now*1000),sort=t}

					total[2] = total[2] + t
				end
				sort(r,function(a,b) return a.sort>b.sort end)
				total[6] = format("%.1f",total[2] / now*1000)
				total[2] = format("%.1f",total[2])
				tinsert(r,1,total)

				if ExRT.F:IsProfilingBoss() and not ExRT.Profiling.BossStarted then
					wipe(r)
				end
		
				profilingWindow.list.L = r
				profilingWindow.list:Update()

				profilingWindow.startBut:SetText(ExRT.Profiling.Enabled and "Stop profiling" or "Start profiling")
			end)

			profilingWindow.startBut = ELib:Button(profilingWindow,"Start profiling"):Size(200,20):Point("BOTTOMLEFT",2,2):OnClick(function()
				ExRT.F:StartStopProfiling()
				t = 0.5
			end)
			profilingWindow.exportBut = ELib:Button(profilingWindow,"Export to string"):Size(200,20):Point("LEFT",profilingWindow.startBut,"RIGHT",2,0):OnClick(function()
				ExRT.F:GetProfiling()
			end)
			profilingWindow.nextBoss = ELib:Button(profilingWindow,"Next boss encounter"):Size(200,20):Point("LEFT",profilingWindow.exportBut,"RIGHT",2,0):OnClick(function()
				ExRT.F:StartProfilingBoss()
			end)
		end

		profilingWindow:NewPoint("TOPLEFT",UIParent,5,-5)
		profilingWindow:Show()
	end
end


---------------> Import/Export data <---------------
do
	local function StringToText(str)
		if str:find("\n") then
			local n = 0
			if str:find("%]$") then
				n = n + 1
			end
			while str:find("%["..string.rep("=",n).."%[") or str:find("%]"..string.rep("=",n).."%]") do
				n = n + 1
			end
			return "["..string.rep("=",n).."["..str.."]"..string.rep("=",n).."]", true
		else
			return "\""..str:gsub("\\","\\\\"):gsub("\"","\\\"").."\""
		end
	end
	
	local function IterateTable(t)
		local prev
		local index = 1
		local indexMax
		local isIndexDone
		local function it()
			if not indexMax then
				local v = t[index]
				if v then
					index = index + 1
					return index-1, v, true
				else
					indexMax = index - 1
				end
			end
			local k,v = next(t,prev)
			prev = k
			while k and type(k)=="number" and k >= 1 and k <= indexMax do
				k,v = next(t,prev)
				prev = k
			end
			return k, v, false
		end
		return it
	end
	
	function ExRT.F.TableToText(t,e,b)
		b = b or {}
		b[t] = true
		e = e or {"{"}
		local ignoreIndex = false
		for k,v,isIndex in IterateTable(t) do
			local newline = ""
			local ignore = true
			if type(v) == "boolean" or type(v) == "number" or type(v) == "string" or type(v) == "table" then
				ignore = false
			end
			if type(v) == "table" and b[v] then
				ignore = true
			end
			if ignore then
				ignoreIndex = true
			elseif isIndex and not ignoreIndex then
			elseif type(k)=="number" then
				newline = newline .. "["..k.."]="
			elseif type(k)=="string" then
				if k:match("[A-Za-z_][A-Za-z_0-9]*") == k then
					newline = newline .. k .. "="
				else
					local kstr, ismultiline = StringToText(k)
					newline = newline .. "["..(ismultiline and " " or "")..kstr..(ismultiline and " " or "").."]="
				end
			elseif type(k)=="boolean" then
				newline = newline .. "["..(k and "true" or "false").."]="
			else
				ignore = true
			end
			if not ignore then
				local tableToExplore
				if type(v)=="number" then
					newline = newline .. v .. ","
				elseif type(v)=="string" then
					newline = newline .. StringToText(v)..","
				elseif type(v)=="boolean" then
					newline = newline ..(v and "true" or "false")..","
				elseif type(v)=="table" then
					newline = newline .."{"
					tableToExplore = v
				end
				e[#e+1] = newline
				if tableToExplore then
					ExRT.F.TableToText(tableToExplore,e,b)
					e[#e] = e[#e] .. ","
				end
			end
		end
		e[#e] = e[#e]:gsub(",$","")
		e[#e+1] = "}"
		return e
	end

	local string_byte = string.byte
	function ExRT.F.TextToTable(str,map,offset)
		if not map and string_byte(str, 1) == 123 then
			str = str:sub(2,-2)	--Expect valid table here
		end
		local strlen = str:len()
		local i = 1
		local prev = 1
		map = map or {}
		offset = offset or 0
	
		local inTable, inString, inWideString
		local startTable, wideStringEqCount = 1, 0
	
		while i <= strlen do
			local b1 = string_byte(str, i)
			if not inString and not inTable and b1 == 123 then
				inTable = 0
				startTable = i
			elseif not inString and inTable and b1 == 123 then
				inTable = inTable + 1
			elseif not inString and inTable and b1 == 125 then
				if inTable == 0 then
					map[startTable+offset] = i + offset
					map[startTable+0.5+offset] = 1
					inTable = false
				else
					inTable = inTable - 1
				end
			elseif not inString and b1 == 34 then	--"
				if map[i+offset+0.5] == 2 then
					i = map[i+offset] - offset
				else
					inString = i
				end
			elseif inString and not inWideString and b1 == 92 then	--\
				i = i + 1
			elseif inString and not inWideString and b1 == 34 then	--"
				map[inString+offset] = i + offset
				map[inString+0.5+offset] = 2
				inString = false
			elseif not inString and b1 == 91 then	-- [ = [
				if map[i+offset+0.5] == 3 then
					i = map[i+offset] - offset
				else
					local k = i + 1
					local eqc = 0
					while k <= strlen do
						local c1 = string_byte(str, k)
						if c1 == 61 then
							eqc = eqc + 1
						elseif c1 == b1 then
							inString = i
							inWideString = i
							i = k
							wideStringEqCount = eqc
							break
						else
							break
						end
						k = k + 1
					end
				end
			elseif inString and inWideString and b1 == 93 then	-- ] = ]
				local k = i + 1
				local eqc = 0
				while k <= strlen do
					local c1 = string_byte(str, k)
					if c1 == 61 then
						eqc = eqc + 1
					elseif c1 == b1 then
						if eqc == wideStringEqCount then
							i = k
							map[inWideString+offset] = i + offset
							map[inWideString+0.5+offset] = 3
							inString = false
							inWideString = false
						end
						break
					else
						break
					end
					k = k + 1
				end
			end
			if not inString and not inTable and (b1 == 44 or i == strlen) then	--,
				map[-prev-offset] = i - (b1 == 44 and 1 or 0) + offset
				prev = i + 1
			end
			i = i + 1
		end
	
		local res = {}
		local numKey = 1
		i = 1
		while i <= strlen do
			if map[-i-offset] then
				local s, e = i, map[-i-offset] - offset
				local k = s
				local key, value
				local isError
				prev = k
				while k <= e do
					if map[k+offset] then
						if map[k+0.5+offset] == 1 then
							value = ExRT.F.TextToTable( str:sub(k+1,map[k+offset]-offset-1) ,map,k+offset)
						elseif map[k+0.5+offset] == 2 then
							value = str:sub(k + 1,map[k+offset]-offset-1):gsub("\\\"","\""):gsub("\\\\","\\")
						elseif map[k+0.5+offset] == 3 then
							value = str:sub(k,map[k+offset]-offset):gsub("^%[=*%[",""):gsub("%]=*%]$","")
						end
						k = map[k+offset] + 1 - offset
					else
						local b1 = string_byte(str, k)
						if b1 == 61 then	--=
							if value then
								key = value
								value = nil
							else
								key = str:sub(prev, k-1):trim()
								if key:find("^%[") and key:find("%]$") then
									key = key:gsub("^%[",""):gsub("%]$","")
									if tonumber(key) then
										key = tonumber(key)
									end
								elseif key == "true" then
									key = true
								elseif key == "false" then
									key = false
								elseif tonumber(key) then
									key = tonumber(key)
								else
									key = key:match("[A-Za-z_][A-Za-z_0-9]*")
								end
								if not key then
									isError = true
									break
								end
							end
							prev = k + 1
						elseif k == e and not value then
							value = str:sub(prev, k):trim()
							if value == "true" then
								value = true
							elseif value == "false" then
								value = false
							else
								value = tonumber(value)
							end
						end
						k = k + 1
					end
				end
				if not isError then
					if not key then
						key = numKey
						numKey = numKey + 1
					end
					res[key] = value
				end
				i = map[-i-offset] - offset
			end
			i = i + 1
		end
		return res
	end

	function ExRT.F.CreateImportExportWindows()
		local function ImportOnUpdate(self, elapsed)
			self.tmr = self.tmr + elapsed
			if self.tmr >= 0.1 then
				self.tmr = 0
				self:SetScript("OnUpdate",nil)
				local str = table.concat(self.buff):trim()
				self.parent:Hide()

				self.buff = {}
				self.buffPos = 0
		
				if self.parent.ImportFunc then
					self.parent:ImportFunc(str)
				end
			end
		end
		
		local importWindow = ELib:Popup(ExRT.L.Import.." "..ExRT.L.ImportHelp):Size(650,100)
		importWindow.Edit = ELib:MultiEdit(importWindow):Point("TOP",0,-20):Size(640,75)
		importWindow:SetScript("OnHide",function(self)
			self.Edit:SetText("")	
		end)
		importWindow:SetScript("OnShow",function(self)
			self.Edit.EditBox.buffPos = 0
			self.Edit.EditBox.tmr = 0
			self.Edit.EditBox.buff = {}
			self.Edit.EditBox:SetFocus()
		end)
		importWindow.Edit.EditBox:SetMaxBytes(1)
		importWindow.Edit.EditBox:SetScript("OnChar", function(self, c)
			self.buffPos = self.buffPos + 1
			self.buff[self.buffPos] = c
			self:SetScript("OnUpdate",ImportOnUpdate)
		end)
		importWindow.Edit.EditBox.parent = importWindow
		
		
		local exportWindow = ELib:Popup(ExRT.L.Export):Size(650,50)
		exportWindow.Edit = ELib:Edit(exportWindow):Point("TOP",0,-20):Size(640,25)
		exportWindow:SetScript("OnHide",function(self)
			self.Edit:SetText("")	
		end)
		exportWindow.Edit:SetScript("OnEditFocusGained", function(self)
			self:HighlightText()
		end)
		exportWindow.Edit:SetScript("OnMouseUp", function(self, button)
			self:HighlightText()
			if button == "RightButton" then
				self:GetParent():Hide()
			end
		end)
		exportWindow.Edit:SetScript("OnKeyUp", function(self, c)
			if (c == "c" or c == "C") and IsControlKeyDown() then
				self:GetParent():Hide()
			end
		end)
		function exportWindow:OnShow()
			self.Edit:SetFocus()
		end

		return importWindow, exportWindow
	end
end

-------------------> Data <--------------------

ExRT.GDB.ClassSpecializationIcons = {
	[62] = "Interface\\Icons\\Spell_Holy_MagicalSentry",
	[63] = "Interface\\Icons\\Spell_Fire_FireBolt02",
	[64] = "Interface\\Icons\\Spell_Frost_FrostBolt02",
	[65] = "Interface\\Icons\\Spell_Holy_HolyBolt",
	[66] = "Interface\\Icons\\Ability_Paladin_ShieldoftheTemplar",
	[70] = "Interface\\Icons\\Spell_Holy_AuraOfLight",
	[71] = "Interface\\Icons\\Ability_Warrior_SavageBlow",
	[72] = "Interface\\Icons\\Ability_Warrior_InnerRage",
	[73] = "Interface\\Icons\\Ability_Warrior_DefensiveStance",
	[102] = "Interface\\Icons\\Spell_Nature_StarFall",
	[103] = "Interface\\Icons\\Ability_Druid_CatForm",
	[104] = "Interface\\Icons\\Ability_Racial_BearForm",
	[105] = "Interface\\Icons\\Spell_Nature_HealingTouch",
	[250] = "Interface\\Icons\\Spell_Deathknight_BloodPresence",
	[251] = "Interface\\Icons\\Spell_Deathknight_FrostPresence",
	[252] = "Interface\\Icons\\Spell_Deathknight_UnholyPresence",
	[253] = "INTERFACE\\ICONS\\ability_hunter_bestialdiscipline",
	[254] = "Interface\\Icons\\Ability_Hunter_FocusedAim",
	[255] = "INTERFACE\\ICONS\\ability_hunter_camouflage",
	[256] = "Interface\\Icons\\Spell_Holy_PowerWordShield",
	[257] = "Interface\\Icons\\Spell_Holy_GuardianSpirit",
	[258] = "Interface\\Icons\\Spell_Shadow_ShadowWordPain",
	[259] = "Interface\\Icons\\Ability_Rogue_DeadlyBrew",
	[260] = "Interface\\Icons\\INV_Sword_30",
	[261] = "Interface\\Icons\\Ability_Stealth",
	[262] = "Interface\\Icons\\Spell_Nature_Lightning",
	[263] = "Interface\\Icons\\Spell_Shaman_ImprovedStormstrike",
	[264] = "Interface\\Icons\\Spell_Nature_MagicImmunity",
	[265] = "Interface\\Icons\\Spell_Shadow_DeathCoil",
	[266] = "Interface\\Icons\\Spell_Shadow_Metamorphosis",
	[267] = "Interface\\Icons\\Spell_Shadow_RainOfFire",
	[268] = "Interface\\Icons\\spell_monk_brewmaster_spec",
	[269] = "Interface\\Icons\\spell_monk_windwalker_spec",
	[270] = "Interface\\Icons\\spell_monk_mistweaver_spec",
	[577] = "Interface\\Icons\\ability_demonhunter_specdps",
	[581] = "Interface\\Icons\\ability_demonhunter_spectank",
	[1467] = "Interface\\Icons\\classicon_evoker_devastation",
	[1468] = "Interface\\Icons\\classicon_evoker_preservation",
	[1473] = "Interface\\Icons\\classicon_evoker_augmentation",
	[1480] = "Interface\\Icons\\classicon_demonhunter_void",
}

ExRT.GDB.ClassList = {
	"WARRIOR",
	"PALADIN",
	"HUNTER",
	"ROGUE",
	"PRIEST",
	"DEATHKNIGHT",
	"SHAMAN",
	"MAGE",
	"WARLOCK",
	"MONK",
	"DRUID",
	"DEMONHUNTER",
	"EVOKER",
}

ExRT.GDB.ClassSpecializationList = {
	["WARRIOR"] = {71, 72, 73},
	["PALADIN"] = {65, 66, 70},
	["HUNTER"] = {253, 254, 255},
	["ROGUE"] = {259, 260, 261},
	["PRIEST"] = {256, 257, 258},
	["DEATHKNIGHT"] = {250, 251, 252},
	["SHAMAN"] = {262, 263, 264},
	["MAGE"] = {62, 63, 64},
	["WARLOCK"] = {265, 266, 267},
	["MONK"] = {268, 269, 270},
	["DRUID"] = {102, 103, 104, 105},
	["DEMONHUNTER"] = {577, 581, 1480},
	["EVOKER"] = {1467, 1468, 1473},
}

ExRT.GDB.ClassArmorType = {
	WARRIOR="PLATE",
	PALADIN="PLATE",
	HUNTER="MAIL",
	ROGUE="LEATHER",
	PRIEST="CLOTH",
	DEATHKNIGHT="PLATE",
	SHAMAN="MAIL",
	MAGE="CLOTH",
	WARLOCK="CLOTH",
	MONK="LEATHER",
	DRUID="LEATHER",
	DEMONHUNTER="LEATHER",
	EVOKER="MAIL",
}

ExRT.GDB.ClassSpecializationRole = {
	[62] = 'RANGE',
	[63] = 'RANGE',
	[64] = 'RANGE',
	[65] = 'HEAL',
	[66] = 'TANK',
	[70] = 'MELEE',
	[71] = 'MELEE',
	[72] = 'MELEE',
	[73] = 'TANK',
	[102] = 'RANGE',
	[103] = 'MELEE',
	[104] = 'TANK',
	[105] = 'HEAL',
	[250] = 'TANK',
	[251] = 'MELEE',
	[252] = 'MELEE',
	[253] = 'RANGE',
	[254] = 'RANGE',
	[255] = 'MELEE',
	[256] = 'HEAL',
	[257] = 'HEAL',
	[258] = 'RANGE',
	[259] = 'MELEE',
	[260] = 'MELEE',
	[261] = 'MELEE',
	[262] = 'RANGE',
	[263] = 'MELEE',
	[264] = 'HEAL',
	[265] = 'RANGE',
	[266] = 'RANGE',
	[267] = 'RANGE',
	[268] = 'TANK',
	[269] = 'MELEE',
	[270] = 'HEAL',
	[577] = 'MELEE',
	[581] = 'TANK',
	[1467] = 'RANGE',
	[1468] = 'HEAL',
	[1473] = 'RANGE',
	[1480] = 'MELEE',
}

ExRT.GDB.ClassID = {
	WARRIOR=1,
	PALADIN=2,
	HUNTER=3,
	ROGUE=4,
	PRIEST=5,
	DEATHKNIGHT=6,
	SHAMAN=7,
	MAGE=8,
	WARLOCK=9,
	MONK=10,
	DRUID=11,
	DEMONHUNTER=12,
	EVOKER=13,
}

if ExRT.isCata and not ExRT.isMoP then
	ExRT.GDB.ClassSpecializationList = {
		WARRIOR = {746,815,845},	--Arms,Fury,Protection
		PALADIN = {831,839,855},	--Holy,Protection,Retribution
		HUNTER = {811,807,809},	--Beast Mastery,Marksmanship,Survival
		ROGUE = {182,181,183},	--Assassination,Combat,Subtlety
		PRIEST = {760,813,795},	--Discipline,Holy,Shadow
		DEATHKNIGHT = {398,399,400},	--Blood,Frost,Unholy
		SHAMAN = {261,263,262},	--Elemental,Enhancement,Restoration
		MAGE = {799,851,823},	--Arcane,Fire,Frost
		WARLOCK = {871,867,865},	--Affliction,Demonology,Destruction
		DRUID = {752,750,748},	--Balance,Feral Combat,Restoration
	}
	 
	ExRT.GDB.ClassSpecializationIcons = {
		[181] = 132090,
		[182] = 132292,
		[183] = 132320,
		[261] = 136048,
		[262] = 136052,
		[263] = 136051,
		[398] = 135770,
		[399] = 135773,
		[400] = 135775,
		[746] = 132355,
		[748] = 136041,
		[750] = 132276,
		[752] = 136096,
		[760] = 135940,
		[795] = 136207,
		[799] = 135932,
		[807] = 236179,
		[809] = 461113,
		[811] = 461112,
		[813] = 237542,
		[815] = 132347,
		[823] = 135846,
		[831] = 135920,
		[839] = 236264,
		[845] = 132341,
		[851] = 135810,
		[855] = 135873,
		[865] = 136186,
		[867] = 136172,
		[871] = 136145,
	}
	 
	ExRT.GDB.ClassSpecializationRole = {
		[181] = "MELEE",
		[182] = "MELEE",
		[183] = "MELEE",
		[261] = "RANGE",
		[262] = "HEAL",
		[263] = "MELEE",
		[398] = "TANK",
		[399] = "MELEE",
		[400] = "MELEE",
		[746] = "MELEE",
		[748] = "HEAL",
		[750] = "MELEE",
		[752] = "RANGE",
		[760] = "HEAL",
		[795] = "RANGE",
		[799] = "RANGE",
		[807] = "RANGE",
		[809] = "RANGE",
		[811] = "RANGE",
		[813] = "HEAL",
		[815] = "MELEE",
		[823] = "RANGE",
		[831] = "HEAL",
		[839] = "TANK",
		[845] = "TANK",
		[851] = "RANGE",
		[855] = "MELEE",
		[865] = "RANGE",
		[867] = "RANGE",
		[871] = "RANGE",
	}
end


if ExRT.isClassic then
	--GetClassInfo
	local classLocalizateEngine = {}
	if LocalizedClassList then
		local classList = LocalizedClassList()
		MergeTable(classLocalizateEngine, classList)
	elseif FillLocalizedClassList then
		FillLocalizedClassList(classLocalizateEngine)
	end

	ExRT.Classic.GetClassInfo = function(id) 
		return classLocalizateEngine[ ExRT.GDB.ClassList[id] ] or "unk" 
	end

	--GetSpecializationInfoByID
	local specializationData = {
		[62] = {name="Arcane",class=8,role="DAMAGER",desc="Manipulates raw Arcane magic, destroying enemies with overwhelming power.|n|nPreferred Weapon: Staff, Wand, Dagger, Sword",icon=135932},
		[63] = {name="Fire",class=8,role="DAMAGER",desc="Focuses the pure essence of Fire magic, assaulting enemies with combustive flames.|n|nPreferred Weapon: Staff, Wand, Dagger, Sword",icon=135810},
		[64] = {name="Frost",class=8,role="DAMAGER",desc="Freezes enemies in their tracks and shatters them with Frost magic.|n|nPreferred Weapon: Staff, Wand, Dagger, Sword",icon=135846},
		[65] = {name="Holy",class=2,role="HEALER",desc="Invokes the power of the Light to heal and protect allies and vanquish evil from the darkest corners of the world.|n|nPreferred Weapon: Sword, Mace, and Shield",icon=135920},
		[66] = {name="Protection",class=2,role="TANK",desc="Uses Holy magic to shield $Ghimself:herself; and defend allies from attackers.|n|nPreferred Weapon: Sword, Mace, Axe, and Shield",icon=236264},
		[70] = {name="Retribution",class=2,role="DAMAGER",desc="A righteous crusader who judges and punishes opponents with weapons and Holy magic.|n|nPreferred Weapon: Two-Handed Sword, Mace, Axe",icon=135873},
		[71] = {name="Arms",class=1,role="DAMAGER",desc="A battle-hardened master of weapons, using mobility and overpowering attacks to strike $Ghis:her; opponents down.|n|nPreferred Weapon: Two-Handed Axe, Mace, Sword",icon=132355},
		[72] = {name="Fury",class=1,role="DAMAGER",desc="A furious berserker unleashing a flurry of attacks to carve $Ghis:her; opponents to pieces.|n|nPreferred Weapons: Dual Two-Handed Axes, Maces, Swords",icon=132347},
		[73] = {name="Protection",class=1,role="TANK",desc="A stalwart protector who uses a shield to safeguard $Ghimself:herself; and $Ghis:her; allies.|n|nPreferred Weapon: Axe, Mace, Sword, and Shield",icon=132341},
		[74] = {name="Ferocity",class=0,role="DAMAGER",desc="Driven by a frenzied persistence to pursue prey, these beasts stop at nothing to achieve victory; even death is temporary for these predators.",icon=236159},
		[79] = {name="Cunning",class=0,role="DAMAGER",desc="",icon=132150},
		[81] = {name="Tenacity",class=0,role="TANK",desc="",icon=132121},
		[102] = {name="Balance",class=11,role="DAMAGER",desc="Can shapeshift into a powerful Moonkin, balancing the power of Arcane and Nature magic to destroy enemies.|n|nPreferred Weapon: Staff, Dagger, Mace",icon=136096},
		[103] = {name="Feral",class=11,role="DAMAGER",desc="Takes on the form of a great cat to deal damage with bleeds and bites.|n|nPreferred Weapon: Staff, Polearm",icon=132115},
		[104] = {name="Guardian",class=11,role="TANK",desc="Takes on the form of a mighty bear to absorb damage and protect allies.|n|nPreferred Weapon: Staff, Polearm",icon=132276},
		[105] = {name="Restoration",class=11,role="HEALER",desc="Channels powerful Nature magic to regenerate and revitalize allies.|n|nPreferred Weapon: Staff, Dagger, Mace",icon=136041},
		[250] = {name="Blood",class=6,role="TANK",desc="A dark guardian who manipulates and corrupts life energy to sustain $Ghimself:herself; in the face of an enemy onslaught.|n|nPreferred Weapon: Two-Handed Axe, Mace, Sword",icon=135770},
		[251] = {name="Frost",class=6,role="DAMAGER",desc="An icy harbinger of doom, channeling runic power and delivering vicious weapon strikes.|n|nPreferred Weapons: Dual Axes, Maces, Swords",icon=135773},
		[252] = {name="Unholy",class=6,role="DAMAGER",desc="A master of death and decay, spreading infection and controlling undead minions to do $Ghis:her; bidding.|n|nPreferred Weapon: Two-Handed Axe, Mace, Sword",icon=135775},
		[253] = {name="Beast Mastery",class=3,role="DAMAGER",desc="A master of the wild who can tame a wide variety of beasts to assist $Ghim:her; in combat.|n|nPreferred Weapon: Bow, Crossbow, Gun",icon=461112},
		[254] = {name="Marksmanship",class=3,role="DAMAGER",desc="A master sharpshooter who excels in bringing down enemies from afar.|n|nPreferred Weapon: Bow, Crossbow, Gun",icon=236179},
		[255] = {name="Survival",class=3,role="DAMAGER",desc="An adaptive ranger who favors using explosives, animal venom, and coordinated attacks with their bonded beast.|n|nPreferred Weapon: Polearm, Staff",icon=461113},
		[256] = {name="Discipline",class=5,role="HEALER",desc="Uses magic to shield allies from taking damage as well as heal their wounds.|n|nPreferred Weapon: Staff, Wand, Dagger, Mace",icon=135940},
		[257] = {name="Holy",class=5,role="HEALER",desc="A versatile healer who can reverse damage on individuals or groups and even heal from beyond the grave.|n|nPreferred Weapon: Staff, Wand, Dagger, Mace",icon=237542},
		[258] = {name="Shadow",class=5,role="DAMAGER",desc="Uses sinister Shadow magic and terrifying Void magic to eradicate enemies.|n|nPreferred Weapon: Staff, Wand, Dagger, Mace",icon=136207},
		[259] = {name="Assassination",class=4,role="DAMAGER",desc="A deadly master of poisons who dispatches victims with vicious dagger strikes.|n|nPreferred Weapons: Daggers",icon=236270},
		[260] = {name="Outlaw",class=4,role="DAMAGER",desc="A ruthless fugitive who uses agility and guile to stand toe-to-toe with enemies.|n|nPreferred Weapons: Axes, Maces, Swords, Fist Weapons",icon=236286},
		[261] = {name="Subtlety",class=4,role="DAMAGER",desc="A dark stalker who leaps from the shadows to ambush $Ghis:her; unsuspecting prey.|n|nPreferred Weapons: Daggers",icon=132320},
		[262] = {name="Elemental",class=7,role="DAMAGER",desc="A spellcaster who harnesses the destructive forces of nature and the elements.|n|nPreferred Weapon: Mace, Dagger, and Shield",icon=136048},
		[263] = {name="Enhancement",class=7,role="DAMAGER",desc="A totemic warrior who strikes foes with weapons imbued with elemental power.|n|nPreferred Weapons: Dual Axes, Maces, Fist Weapons",icon=237581},
		[264] = {name="Restoration",class=7,role="HEALER",desc="A healer who calls upon ancestral spirits and the cleansing power of water to mend allies' wounds.|n|nPreferred Weapon: Mace, Dagger, and Shield",icon=136052},
		[265] = {name="Affliction",class=9,role="DAMAGER",desc="A master of shadow magic who specializes in drains and damage-over-time spells.|n|nPreferred Weapon: Staff, Wand, Dagger, Sword",icon=136145},
		[266] = {name="Demonology",class=9,role="DAMAGER",desc="A commander of demons who twists the souls of $Ghis:her; army into devastating power.|n|nPreferred Weapon: Staff, Wand, Dagger, Sword",icon=136172},
		[267] = {name="Destruction",class=9,role="DAMAGER",desc="A master of chaos who calls down fire to burn and demolish enemies.|n|nPreferred Weapon: Staff, Wand, Dagger, Sword",icon=136186},
		[268] = {name="Brewmaster",class=10,role="TANK",desc="A sturdy brawler who uses unpredictable movement and mystical brews to avoid damage and protect allies.|n|nPreferred Weapon: Staff, Polearm",icon=608951},
		[269] = {name="Windwalker",class=10,role="DAMAGER",desc="A martial artist without peer who pummels foes with hands and fists.|n|nPreferred Weapons: Fist Weapons, Axes, Maces, Swords",icon=608953},
		[270] = {name="Mistweaver",class=10,role="HEALER",desc="A healer who masters the mysterious art of manipulating life energies aided by the wisdom of the Jade Serpent.|n|nPreferred Weapon: Staff, Mace, Sword",icon=608952},
		[535] = {name="Ferocity",class=0,role="DAMAGER",desc="Driven by a rabid persistence to pursue prey, these carnivorous beasts stop at nothing to achieve victory; even death is temporary for these predators.",icon=236159},
		[536] = {name="Cunning",class=0,role="DAMAGER",desc="",icon=132150},
		[537] = {name="Tenacity",class=0,role="TANK",desc="",icon=132121},
		[577] = {name="Havoc",class=12,role="DAMAGER",desc="A brooding master of warglaives and the destructive power of Fel magic.|n|nPreferred Weapons: Warglaives, Swords, Axes, Fist Weapons",icon=1247264},
		[581] = {name="Vengeance",class=12,role="TANK",desc="Embraces the demon within to incinerate enemies and protect their allies.|n|nPreferred Weapons: Warglaives, Swords, Axes, Fist Weapons",icon=1247265},
		[1467] = {name="Devastation",class=13,role="DAMAGER",desc="Releases innate power as chaotic Red flames or focused Blue magic to bathe the battlefield in destruction. Preferred Weapon: Staff, Sword, Dagger, Mace",icon=4511811},
		[1468] = {name="Preservation",class=13,role="HEALER",desc="Calls upon the Emerald Dream to rejuvenate life, and the Bronze sands of time to prevent harm. Preferred Weapon: Staff, Sword, Dagger, Mace",icon=4511812},
		[1473] = {name="Augmentation",class=13,role="DAMAGER",desc="Imbues allies with the might of the Black dragons, and bends time & fate in their favor with Bronze magic. Preferred Weapon: Staff, Sword, Dagger, Mace",icon=5198700},
	}

	ExRT.Classic.GetSpecializationInfoByID = function(id) 
		local data = specializationData[id] or ExRT.NULL
		return id, data.name, data.desc, data.icon, data.role, ExRT.GDB.ClassList[data.class]
	end
end

ExRT.GDB.JournalInstance = {
{0,64,238,63,240,234,227,239,231,237,233,241,229,228,236,232,226,230,311,316,246,0,741,742,743,744},	--Classic
{1,255,259,256,248,261,262,260,254,257,258,253,252,250,247,251,249,0,745,750,747,748,749,751,746,752},	--Burning Crusade
{2,285,286,281,282,279,277,273,272,275,274,283,271,280,284,278,276,0,760,754,759,755,756,753,758,757,761},	--Wrath of the Lich King
{3,64,63,77,65,70,66,68,71,67,69,76,184,185,186,0,73,72,78,74,75,187},	--Cataclysm
{4,312,313,302,303,321,311,316,246,324,0,322,320,317,330,362,369},	--Mists of Pandaria
{5,385,537,547,558,536,476,556,559,0,457,477,557,669},	--Warlords of Draenor
{6,716,767,762,721,727,707,740,726,777,800,860,900,945,0,768,822,959,786,861,875,946},	--Legion
{7,1012,1001,1041,968,1002,1023,1022,1021,1036,1030,1178,0,1028,1031,1176,1177,1179,1180},	--Battle for Azeroth
{8,1189,1186,1182,1185,1183,1184,1188,1187,1194,0,1190,1193,1195,1192},	--Shadowlands
{9,1197,1203,1198,1199,1196,1202,1201,1204,1209,0,1200,1207,1208,1205},	--Dragonflight
{-1,65,68,313,537,556,767,762,721,740,800,1001,968,1022,1021,1197,1203,1198,1199,1196,1202,1201,1204,1209,0,1200,1207,1208,1205,n=EXPANSION_NAME9,s=4},	--Current Season
{-1,1270,1271,1274,1269,1182,1184,1023,71,n=EXPANSION_NAME10,s=1},	--Current Season
{10,1268,1267,1210,1269,1271,1272,1270,1274,1298,1303,0,1273,1296,1278,1302},	--The War Within
{11,1299,1300,1304,1311,1309,1315,1316,1313,0,1307,1308,1312,1314},	--Midnight
}
--/run local s="" for i=1,100 do local id=EJ_GetInstanceByIndex(i,false) if not id then break end s=s..id.."," end GExRT.F:Export2(s)

ExRT.GDB.MapIDToJournalInstance = {
[3029]=1319,[2939]=1314,[2930]=1312,[2923]=1313,[2915]=1316,[2913]=1308,[2912]=1307,[2874]=1315,[2859]=1309,[2830]=1303,[2825]=1311,[2813]=1304,[2811]=1300,[2810]=1302,[2805]=1299,[2792]=1301,[2774]=1278,
[2773]=1298,[2769]=1296,[2669]=1274,[2662]=1270,[2661]=1272,[2660]=1271,[2657]=1273,[2652]=1269,[2651]=1210,[2649]=1267,[2648]=1268,[2579]=1209,[2574]=1205,[2569]=1208,[2559]=1192,[2549]=1207,[2527]=1204,
[2526]=1201,[2522]=1200,[2521]=1202,[2520]=1196,[2519]=1199,[2516]=1198,[2515]=1203,[2481]=1195,[2451]=1197,[2450]=1193,[2441]=1194,[2296]=1190,[2293]=1187,[2291]=1188,[2290]=1184,[2289]=1183,[2287]=1185,
[2286]=1182,[2285]=1186,[2284]=1189,[2217]=1180,[2164]=1179,[2097]=1178,[2096]=1177,[2070]=1176,[1877]=1030,[1864]=1036,[1862]=1021,[1861]=1031,[1861]=1031,[1841]=1022,[1822]=1023,[1771]=1002,[1763]=968,
[1762]=1041,[1754]=1001,[1753]=945,[1712]=946,[1677]=900,[1676]=875,[1651]=860,[1648]=861,[1594]=1012,[1571]=800,[1544]=777,[1530]=786,[1520]=959,[1520]=959,[1520]=959,[1516]=726,[1501]=740,[1493]=707,
[1492]=727,[1477]=721,[1466]=762,[1458]=767,[1456]=716,[1448]=669,[1358]=559,[1279]=556,[1228]=557,[1228]=557,[1209]=476,[1208]=536,[1205]=457,[1195]=558,[1182]=547,[1176]=537,[1175]=385,[1136]=369,[1098]=362,
[1011]=324,[1009]=330,[1008]=317,[1007]=246,[1004]=316,[1001]=311,[996]=322,[996]=322,[994]=321,[967]=187,[962]=303,[961]=302,[960]=313,[959]=312,[940]=186,[939]=185,[938]=184,[859]=76,[757]=75,[755]=69,
[754]=74,[725]=67,[724]=761,[720]=78,[671]=72,[670]=71,[669]=73,[668]=276,[658]=278,[657]=68,[650]=284,[649]=757,[645]=66,[644]=70,[643]=65,[632]=280,[631]=758,[624]=753,[619]=271,[616]=756,[615]=755,[608]=283,
[604]=274,[603]=759,[602]=275,[601]=272,[600]=273,[599]=277,[595]=279,[585]=249,[580]=752,[578]=282,[576]=281,[575]=286,[574]=285,[568]=77,[565]=746,[564]=751,[560]=251,[558]=247,[557]=250,[556]=252,[555]=253,
[554]=258,[553]=257,[552]=254,[550]=749,[548]=748,[547]=260,[546]=262,[545]=261,[544]=747,[543]=248,[542]=256,[540]=259,[534]=750,[533]=754,[532]=745,[531]=744,[509]=743,[469]=742,[429]=1277,[429]=1277,
[429]=1277,[409]=741,[389]=226,[349]=232,[329]=1292,[329]=1292,[269]=255,[249]=760,[230]=228,[229]=229,[209]=241,[129]=233,[109]=237,[90]=231,[70]=239,[48]=227,[47]=234,[43]=240,[36]=63,[34]=238,[33]=64,
}

ExRT.GDB.EncountersList = {
	{350,652,653,654,655,656,657,658,659,660,661,662},
	{129,519,520,2009,522,521,2010,2011,524,523,525,526,2012,527},
	{130,2002,2003,2004,2005},
	{132,1969,1966,1967,1989,1968},
	{133,2026,2024,2025},
	{136,2030,2027,2029,2028},
	{138,1987,1985,1984,1986},
	{140,1994,1996,1995,1998},
	{142,528,2013,530,529,2014,2015,532,531,533,534,2016,535},
	{153,1978,1983,1980,1988,1981},
	{156,1126,1127,1128,1129},
	{157,1971,1972,1973},
	{160,1974,1976,1977,1975},
	{168,2018,2019,2020},
	{171,2022,2023,2021},
	{183,2006,2007},
	{184,1999,2001,2000},
	{185,1992,1993,1990},
	{213,1443,1444,1445,1446},
	{219,593,594,595,596,597,598,599,600},
	{220,492,488,486,487,490,491,493},
	{221,1667,1668,1669,1675,1676,1670,1671,1672},
	{225,1144,1145,1146},
	{226,379,378,380,381,382},
	{230,547,548,549,551,552,553,554,1887},
	{233,785,784,786,787,788,789,790,791,792,793},
	{234,343,344,345,346,350,347,348,349,361,362,363,364,365,366,367,368},
	{242,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245},
	{246,1935,1936,1937,1938},
	{247,718,719,720,721,722,723},
	{250,267,268,269,270,271,272,274,273,275},
	{256,1889,1890},
	{258,1902,1903,1904},
	{260,1908,1909,1910,1911},
	{261,1922,1923,1924},
	{262,1945,1946,1947,1948},
	{263,1942,1943,1944},
	{265,1939,1940,1941},
	{266,1925,1926,1927,1928,1929},
	{267,1930,1931,1932,1933,1934},
	{269,1913,1914,1915,1916},
	{272,1899,1900,250,1901},
	{273,1919,1920,1921},
	{274,1905,1906,1907},
	{277,1052,1053,1054,1055},
	{279,585,586,587,588,589,590,591,592},
	{280,422,423,427,424,425,426,428,429},
	{282,1033,1250,1332},
	{283,1040,1038,1039,1037,1036},
	{291,1064,1065,1063,1062,1060,1081},
	{293,1051,1050,1048,1049},
	{297,1080,1076,1075,1077,1074,1079,1078},
	{300,1662,1663,1664,1665,1666},
	{301,1656,438,1659,1660,1661},
	{302,444,446,447,448,449,450},
	{306,451,452,453,454,455,456,457,458,459,460,461,462,463},
	{310,1069,1070,1071,1073,1072},
	{317,473,474,476,475,477,478,472,479,480,481,482,483,484,1885},
	{322,1045,1044,1046,1047},
	{324,1056,1059,1058,1057},
	{325,1043,1041,1042},
	{333,1189,1190,1191,1192,1193,1194},
	{337,1178,1179,1188,1180,1181,1182},
	{347,1891,1892,1893},
	{348,1894,1895,1897,1898},
	{398,1272,1273,1274},
	{399,1337,1340,1339},
	{401,1881,1882,1883,1884,1271},
	{429,1418,1417,1416,1439},
	{431,1422,1421,1420},
	{435,1423,1424,1425},
	{437,1397,1405,1406,1419},
	{439,1412,1413,1414},
	{443,1303,1304,1305,1306},
	{453,1442,1509,1510,1441},
	{457,1465,1502,1447,1464},
	{476,1426,1427,1428,1429,1430},
	{554,1563,1564,1571,1587},
	{573,1655,1653,1652,1654},
	{574,1677,1688,1679,1682},
	{593,1686,1685,1678,1714},
	{595,1749,1748,1750,1754},
	{601,1698,1699,1700,1701},
	{606,1715,1732,1736},

	{616,1761,1758,1759,1760,1762},
	{620,1746,1757,1751,1752,1756},
	{624,1755,1770,1801},

	{703,1805,1806,1807,1808,1809},
	{708,1822,1823,1824},
	{710,1815,1850,1816,1817,1818},
	{713,1810,1811,1812,1813,1814},
	{731,1790,1791,1792,1793},
	{732,1845,1846,1847,1848,1851,1852,1855,1856},
	{733,1836,1837,1838,1839},
	{749,1825,1826,1827,1828,1829},
	{751,1832,1833,1834,1835},
	{761,1868,1869,1870},

	{790,1879,1880,1888,1917,1950,1951,1952,1953,1949},

	{809,1957,1954,1961,1960,1964,1965,1959,2017,2031},

	{845,2055,2057,2039,2053},		

	{903,2065,2066,2067,2068},	

	{934,2084,2085,2086,2087},
	{936,2093,2094,2095,2096},
	{974,2101,2102,2103,2104},
	{1010,2105,2106,2107,2108},
	{1015,2113,2114,2115,2116,2117},
	{1041,2111,2118,2112,2123},
	{1162,2098,2097,2109,2099,2100},
	{1038,2124,2125,2126,2127},
	{1039,2130,2131,2132,2133},
	{1004,2139,2142,2140,2143},
	{1490,2290,2292,2312,2291,2257,2258,2259,2260},

	{1666,2387,2388,2389,2390},
	{1674,2382,2384,2385,2386},
	{1669,2397,2392,2393},	
	{1663,2401,2380,2403,2381},
	{1693,2357,2356,2358,2359},
	{1683,2391,2365,2366,2364,2404},
	{1679,2395,2394,2400,2396},
	{1675,2360,2361,2362,2363},

	{2096,2570,2568,2567,2569},
	{2071,2555,2556,2557,2558,2559},
	{2093,2637,2636,2581,2580},
	{2080,2613,2612,2610,2611},
	{2097,2562,2563,2564,2565},
	{2095,2609,2606,2623},
	{2073,2582,2585,2583,2584},
	{2082,2615,2616,2617,2618},
	{2190,2666,2667,2668,2669,2670,2671,2672,2672,2673},

	{2316,2816,2861,2836},	--The Rookery:Dung
	{2308,2847,2835,2848},	--Priory of the Sacred Flame:Dung
	{2303,2829,2826,2787,2788},	--Darkflame Cleft:Dung
	{2341,2854,2880,2888,2883},	--The Stonevault:Dung
	{2357,2926,2906,2901},	--Ara-Kara, City of Echoes:Dung
	{2335,2900,2931,2929,2930},	--Cinderbrew Meadery:Dung
	{2359,2837,2838,2839},	--The Dawnbreaker:Dung
	{2343,2907,2908,2905,2909},	--City of Threads:Dung
	{2387,3020,3019,3053,3054},	--Operation: Floodgate:Dung
	{2449,3107,3108,3109},	--Eco-Dome Al'dani:Dung
	{1989,2425,2441,2424,2440,2437,2426,2419,2442},	--Tazavesh, the Veiled Market:Dung

	{2494,3056,3057,3058,3059},	--Windrunner Spire:Dung
	{2511,3071,3072,3073,3074},	--Magisters' Terrace:Dung
	{2433,3101,3102,3103,3105},	--Murder Row:Dung
	{2514,3207,3208,3209},	--Den of Nalorakk:Dung
	{2500,3199,3200,3201,3202},	--The Blinding Vale:Dung
	{2501,3212,3213,3214},	--Maisara Caverns:Dung
	{2556,3328,3332,3333},	--Nexus-Point Xenas:Dung
	{2572,3285,3286,3287},	--Voidscar Arena:Dung

	{232,663,664,665,666,667,668,669,670,671,672},
	{287,610,611,612,613,614,615,616,617},
	{319,709,710,711,712,713,714,715,716,717},
	{331,651},
	{330,649,650},
	{332,623,624,625,626,627,628},
	{334,730,731,732,733},
	{329,618,619,620,621,622},
	{339,601,602,603,604,605,606,607,608,609},
	{335,724,725,726,727,728,729},
	{162,1107,1110,1116,1117,1112,1115,1113,1109,1121,1118,1111,1108,1120,1119,1114},
	{155,1090},
	{141,1094},
	{147,1132,1136,1139,1142,1140,1137,1131,1135,1141,1133,1138,1134,1143,1130},
	{172,1088,1087,1086,1089,1085},
	{248,1084},
	{186,1101,1100,1099,1096,1104,1097,1102,1095,1103,1098,1105,1106},
	{200,1150},
	{285,1027,1024,1022,1023,1025,1026},
	{294,1030,1032,1028,1029,1082},
	{328,1035,1034},
	{367,1197,1204,1205,1206,1200,1185,1203},
	{409,1292,1294,1295,1296,1297,1298,1291,1299},
	{471,1395,1390,1434,1436,1500,1407},
	{474,1507,1504,1463,1498,1499,1501},
	{456,1409,1505,1506,1431},
	{508,1577,1575,1570,1565,1578,1573,1572,1574,1576,1559,1560,1579,1580},
	{556,1602,1598,1624,1604,1622,1600,1606,1603,1595,1594,1599,1601,1593,1623},

        {610,1721,1706,1720,1722,1719,1723,1705},--HM
	{596,1696,1691,1693,1694,1689,1692,1690,1713,1695,1704},--BF
	{661,1778,1785,1787,1798,1786,1783,1788,1794,1777,1800,1784,1795,1799},--HFC
	{777,1853,1841,1873,1854,1876,1877,1864},--EN
	{806,1958,1962,2008},--tov
	{764,1849,1865,1867,1871,1862,1886,1842,1863,1872,1866},--nighthold
	{850,2032,2048,2036,2037,2050,2054,2052,2038,2051},--tos
	{909,2076,2074,2064,2070,2075,2082,2069,2088,2073,2063,2092},--antorus
	{1148,2144,2141,2136,2128,2134,2145,2135,2122},--uldir
	{1358,2265,2263,2284,2266,2285,2271,2268,2272,2276,2280,2281},	--bfd
	{1345,2269,2273},	--storms
	{1512,2298,2305,2289,2304,2303,2311,2293,2299},	--ethernal place
	{1582,2329,2327,2334,2328,2336,2333,2331,2335,2343,2345,2337,2344}, --nyalotha
	{1735,2398,2418,2402,2383,2405,2406,2412,2399,2417,2407},	--castle Nathria
	{1998,2423,2433,2429,2432,2434,2430,2436,2431,2422,2435},	--sod
	{2047,2512,2540,2553,2544,2539,2542,2529,2546,2543,2549,2537},	--sfo

	{2119,2587,2639,2590,2592,2635,2605,2614,2607},	--voti
	{2166,2688,2682,2687,2693,2680,2689,2683,2684,2685},	--a
	{2232,2820,2709,2737,2731,2728,2708,2824,2786,2677},	--d

	{2292,2902,2917,2898,2918,2919,2920,2921,2922},	--Nerub-ar Palace:Raid
	{2406,3009,3010,3011,3012,3013,3014,3015,3016},	--Liberation of Undermine:Raid
	{2460,3129,3131,3130,3132,3122,3133,3134,3135},	--Manaforge Omega

	{2529,3176,3177,3179,3178,3180,3181},	--The Voidspire:Raid
	{2532,3306},	--The Dreamrift:Raid
	{2533,3182,3183},	--March on Quel'Danas:Raid
}

function ExRT.F.EJ_AutoScan()
	local TIER_MIN = 11

	local NEW_DATA = {
		encounterIDtoEJ = {},
		EncountersList_dung = {},
		EncountersList_raid = {},
		MapIDToJournalInstance = {},
		JournalInstance = {-2},
	}

	local encounterMap = {}
	local dungeonPosInsert = 1
	for i=1,#ExRT.GDB.EncountersList do
		local dung = ExRT.GDB.EncountersList[i]
		if dung[1] == 232 then
			dungeonPosInsert = i
		end
		for j=2,#dung do
			encounterMap[ dung[j] ] = true
		end
	end
	local instanceMap = {}
	for i=1,#ExRT.GDB.JournalInstance do
		local tier = ExRT.GDB.JournalInstance[i]
		for j=2,#tier do
			instanceMap[ tier[j] ] = true
		end
	end

	for i=TIER_MIN,EJ_GetNumTiers() do
		EJ_SelectTier(i)

		for j=1,2 do
			local isRaid = j == 1 and true or false

			local instanceIndex = 1
			while EJ_GetInstanceByIndex(instanceIndex,isRaid) do
				local instanceID, iname, description, bgImage, buttonImage1, loreImage, buttonImage2, dungeonAreaMapID, link, shouldDisplayDifficulty, mapID = EJ_GetInstanceByIndex(instanceIndex,isRaid)
	
				EJ_SelectInstance(instanceID)
				
				local isNewInstance = true

				local EncountersList_new = {dungeonAreaMapID}
				if dungeonAreaMapID == 0 then
					isNewInstance = false	--ignore world bosses
				end
	
				local encounterIndex = 1
				while EJ_GetEncounterInfoByIndex(encounterIndex, instanceID) do
					local name, description, journalEncounterID, rootSectionID, link, journalInstanceID, dungeonEncounterID, instanceID = EJ_GetEncounterInfoByIndex(encounterIndex, instanceID)

					EncountersList_new[#EncountersList_new+1] = dungeonEncounterID
					if dungeonEncounterID and encounterMap[dungeonEncounterID] then
						isNewInstance = false
					end

					if dungeonEncounterID and not ExRT.GDB.encounterIDtoEJ[dungeonEncounterID] then
						NEW_DATA.encounterIDtoEJ[dungeonEncounterID] = journalEncounterID
					end
	
					encounterIndex = encounterIndex + 1
				end

				if isNewInstance then
					if isRaid then
						tinsert(NEW_DATA.EncountersList_raid, EncountersList_new)
					elseif isNewInstance then
						tinsert(NEW_DATA.EncountersList_dung, EncountersList_new)
					end

					for k=2,#EncountersList_new do
						encounterMap[ EncountersList_new[k] ] = true
					end

					--print('EncountersList','added',iname,encounterIndex-1)
				end

				if mapID and not ExRT.GDB.MapIDToJournalInstance[mapID] then
					NEW_DATA.MapIDToJournalInstance[mapID] = instanceID

					--print('MapIDToJournalInstance','added',iname)
				end

				if not instanceMap[instanceID] then
					instanceMap[instanceID] = true

					tinsert(NEW_DATA.JournalInstance, 2, instanceID)

					--print('JournalInstance','added',iname)
				end
	
				instanceIndex = instanceIndex + 1
			end
		end
	end

	VMRT.Addon.EJ_CHECK_VER = ExRT.clientUIinterface
	VMRT.Addon.EJ_DATA = NEW_DATA
	VMRT.Addon.EJ_CHECK_VER_PTR = ExRT.clientBuildVersion

	ExRT.F.EJ_LoadData()
end
function ExRT.F.EJ_LoadData()
	if not VMRT.Addon.EJ_DATA then
		return
	end
	local NEW_DATA = VMRT.Addon.EJ_DATA

	local encounterMap = {}
	local dungeonPosInsert = 1
	for i=1,#ExRT.GDB.EncountersList do
		local dung = ExRT.GDB.EncountersList[i]
		if dung[1] == 232 then
			dungeonPosInsert = i
		end
		for j=2,#dung do
			encounterMap[ dung[j] ] = true
		end
	end

	for i=1,#NEW_DATA.EncountersList_raid do
		local new_dung = NEW_DATA.EncountersList_raid[i]
		if new_dung[2] and not encounterMap[ new_dung[2] ] then
			tinsert(ExRT.GDB.EncountersList, new_dung)
		end
	end
	for i=1,#NEW_DATA.EncountersList_dung do
		local new_dung = NEW_DATA.EncountersList_dung[i]
		if new_dung[2] and not encounterMap[ new_dung[2] ] then
			tinsert(ExRT.GDB.EncountersList, dungeonPosInsert, new_dung)
			dungeonPosInsert = dungeonPosInsert + 1
		end
	end

	for k,v in pairs(NEW_DATA.MapIDToJournalInstance) do
		if not ExRT.GDB.MapIDToJournalInstance[k] then
			ExRT.GDB.MapIDToJournalInstance[k] = v
		end
	end
	for k,v in pairs(NEW_DATA.encounterIDtoEJ) do
		if not ExRT.GDB.encounterIDtoEJ[k] then
			ExRT.GDB.encounterIDtoEJ[k] = v
		end
	end
	if #NEW_DATA.JournalInstance > 1 then
		tinsert(ExRT.GDB.JournalInstance,NEW_DATA.JournalInstance)
	end
end


local ACTUAL_RAID = 1735
local ACTUAL_DUNG = 1666
if UnitLevel'player' > 80 then
	ACTUAL_DUNG = 2494
	ACTUAL_RAID = 2529
elseif UnitLevel'player' > 70 then
	ACTUAL_DUNG = 2316
	ACTUAL_RAID = 2292
elseif UnitLevel'player' > 60 then
	ACTUAL_DUNG = 2096
	ACTUAL_RAID = 2119
end

do
	local function StringVerToNumber(ver)
		local i = 0
		local r = 0
		for n in ver:gmatch("%d+") do
			r = r + tonumber(n) * (10 ^ i)
			i = i - 2
		end
		return r
	end
	local ver_now = StringVerToNumber(GetBuildInfo())
	for i=#ExRT.GDB.EncountersList,1,-1 do
		local t = ExRT.GDB.EncountersList[i]
		if type(t[1]) == "string" then
			if StringVerToNumber(t[1]) > ver_now then
				tremove(ExRT.GDB.EncountersList, i)
			else
				tremove(t, 1)
			end
		elseif t[1] == 2096 then
			--stop loop for old data
			break
		end
	end
	for i=#ExRT.GDB.JournalInstance,1,-1 do
		local t = ExRT.GDB.JournalInstance[i]
		if type(t[1]) == "string" then
			if StringVerToNumber(t[1]) > ver_now then
				tremove(ExRT.GDB.JournalInstance, i)
			else
				tremove(t, 1)
			end
		else
			for j=#t,2,-1 do
				if type(t[j]) == "string" then
					if StringVerToNumber(t[j]) > ver_now then
						tremove(t, j)
					end
					tremove(t, j)
				end
			end
		end
	end
end

function ExRT.F.GetEncountersList(onlyRaid,onlyActual,reverse,onlyDung)
	local new = {}

	local isActual,isRaid
	for _,v in ipairs(ExRT.GDB.EncountersList) do
		if v[1] == 232 then
			isRaid = true
			isActual = false
			if onlyDung then break end
		elseif v[1] == ACTUAL_DUNG then
			isActual = true
		elseif v[1] == ACTUAL_RAID then
			isActual = true
		end
		if (not onlyActual or isActual) and (not onlyRaid or isRaid) then
			new[#new+1] = v
		end
	end
	if reverse then
		local len = #new
		for i=1,floor(len/2) do
			new[i], new[len+1-i] = new[len+1-i], new[i]
		end
	end
	return new
end