Quantcast

Merge branch 'v2.2.0'

Alar of Daggerspine [01-12-15 - 02:43]
Merge branch 'v2.2.0'
Filename
CHANGELOG.txt
GarrisonCommander.lua
GarrisonCommander.toc
GarrisonCommander.xml
doc.txt
example.js
wowhead.lua
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index a05d856..d6c9494 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -6,7 +6,7 @@ Fix: Was spamming "released" on main window closing
 Fix: Another step in hide and seek with Master Plan. Use GC Interface now works also with MP 0.22.1. This fix also reenables Garrison Mission Manager
 Fix: A minor incompatibility wuth some addons was causing them to display very small menus in some options pages. Thanks to Goldshire for pointing it
 * 2.1.2
-Fix: Mission should appear sorted as requested bith on startup and after a mission completion
+Fix: Mission should appear sorted as requested both on startup and after a mission completion
 Fix: Removed a couple fo rare lua error
 * 2.1.1
 Feature: Countered mechanics are now shown in standard mission button both in big and small screen mode
@@ -14,9 +14,9 @@ Feature: New sort method: mission age
 Fix: Changed key for "skip auto fill" from shift to ctrl. Now it works
 Fix: In mission page, counter ability were not shown in follower icon
 * 2.1.0
-Feature: new layout is now optional, you can revert to 1.1.8 leayout disabling "big screen"
+Feature: new layout is now optional, you can revert to 1.1.8 layout disabling "big screen"
 Feature: Mission page autopopulation is now optional
-Feature: If Master Plan is detecte, you can choose which layout you want between GC's one and MP's one
+Feature: If Master Plan is detected, you can choose which layout you want between GC's one and MP's one
 Fix: error "Message: ...rface\AddOns\GarrisonCommander\GarrisonCommander.lua:930: attempt to compare number with nil"
 * 2.0.1
 Fixed: RU,KR,CH (both traditional and simplified) locales where broken
diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua
index 7a08015..c7e2218 100644
--- a/GarrisonCommander.lua
+++ b/GarrisonCommander.lua
@@ -1,14 +1,24 @@
 local me, ns = ...
 local _G=_G
-local addon=LibStub("LibInit"):NewAddon(me,'AceHook-3.0','AceTimer-3.0','AceEvent-3.0') --#Addon
+local pp=print
+--@debug@
+	LoadAddOn("Blizzard_DebugTools")
+--@end-debug@
+local addon=LibStub("LibInit"):NewAddon(me,'AceHook-3.0','AceTimer-3.0','AceEvent-3.0','AceBucket-3.0') --#Addon
 local AceGUI=LibStub("AceGUI-3.0")
 local D=LibStub("LibDeformat-3.0")
 local C=addon:GetColorTable()
 local L=addon:GetLocale()
 local print=addon:Wrap("Print")
-local xprint=function(...) print("DBG",...) end
 local trace=addon:Wrap("Trace")
 local xprint=function() end
+local xdump=function() end
+local xtrace=function() end
+--@debug@
+--xprint=function(...) print("DBG",...) end
+--xdump=function(d,t) print(t) DevTools_Dump(d) end
+--xtrace=trace
+--@end-debug@
 local pairs=pairs
 local select=select
 local next=next
@@ -27,12 +37,12 @@ local bigscreen=true
 local GMM=false
 local MP=false
 local MPGoodGuy=false
-local ttcalled=false
-local rendercalled=false
 local MPSwitch
 local dbg=false
-
---@debug@
+local trc=false
+local pin=false
+local baseHeight
+local minHeight
 if (LibDebug) then LibDebug() end
 local function tcopy(obj, seen)
 	if type(obj) ~= 'table' then return obj end
@@ -87,71 +97,21 @@ local function capitalize(s)
 	s=tostring(s)
 	return strupper(s:sub(1,1))..strlower(s:sub(2))
 end
--- Name is here just for doc, I will be using the localized one
-
-local _abilities={
-	{
-		["name"] = "Wild Aggression",
-		["icon"] = "Interface\\ICONS\\Spell_Nature_Reincarnation.blp",
-	}, -- [1]
-	{
-		["name"] = "Massive Strike",
-		["icon"] = "Interface\\ICONS\\Ability_Warrior_SavageBlow.blp",
-	}, -- [2]
-	{
-		["name"] = "Group Damage",
-		["icon"] = "Interface\\ICONS\\Spell_Fire_SelfDestruct.blp",
-	}, -- [3]
-	{
-		["name"] = "Magic Debuff",
-		["icon"] = "Interface\\ICONS\\Spell_Shadow_ShadowWordPain.blp",
-	}, -- [4]
-	nil, -- [5]
-	{
-		["name"] = "Danger Zones",
-		["icon"] = "Interface\\ICONS\\spell_Shaman_Earthquake.blp",
-	}, -- [6]
-	{
-		["name"] = "Minion Swarms",
-		["icon"] = "Interface\\ICONS\\Spell_DeathKnight_ArmyOfTheDead.blp",
-	}, -- [7]
-	{
-		["name"] = "Powerful Spell",
-		["icon"] = "Interface\\ICONS\\Spell_Shadow_ShadowBolt.blp",
-	}, -- [8]
-	{
-		["name"] = "Deadly Minions",
-		["icon"] = "Interface\\ICONS\\Achievement_Boss_TwinOrcBrutes.blp",
-	}, -- [9]
-	{
-		["name"] = "Timed Battle",
-		["icon"] = "Interface\\ICONS\\SPELL_HOLY_BORROWEDTIME.BLP",
-	}, -- [10]
-}
-local abilities={}
-
-local function getAbilityName(texture)
-	for i=1,#abilities do
-		if (abilities[i] and abilities[i].icon==texture) then
-			return abilities[i].name
-		end
-	end
-	return "unknown"
-end
 --- upvalues
+--
 local AVAILABLE=AVAILABLE -- "Available"
 local BUTTON_INFO=GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS.. " " .. GARRISON_MISSION_PERCENT_CHANCE
 local ENVIRONMENT_SUBHEADER=ENVIRONMENT_SUBHEADER -- "Environment"
 local G=C_Garrison
-local GARRISON_BUILDING_SELECT_FOLLOWER_TITLE=GARRISON_BUILDING_SELECT_FOLLOWER_TITLE -- "Select a Follower";
-local GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP=GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP -- "Click here to assign a Follower";
-local GARRISON_FOLLOWERS=GARRISON_FOLLOWERS -- "Followers"
-local GARRISON_FOLLOWER_CAN_COUNTER=GARRISON_FOLLOWER_CAN_COUNTER -- "This follower can counter:"
-local GARRISON_FOLLOWER_EXHAUSTED=GARRISON_FOLLOWER_EXHAUSTED -- "Recovering (1 Day)"
-local GARRISON_FOLLOWER_INACTIVE=GARRISON_FOLLOWER_INACTIVE --"Inactive"
-local GARRISON_FOLLOWER_IN_PARTY=GARRISON_FOLLOWER_IN_PARTY
-local GARRISON_FOLLOWER_ON_MISSION=GARRISON_FOLLOWER_ON_MISSION -- "On Mission"
-local GARRISON_FOLLOWER_WORKING=GARRISON_FOLLOWER_WORKING -- "Working
+--local GARRISON_BUILDING_SELECT_FOLLOWER_TITLE=GARRISON_BUILDING_SELECT_FOLLOWER_TITLE -- "Select a Follower";
+--local GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP=GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP -- "Click here to assign a Follower";
+--local GARRISON_FOLLOWERS=GARRISON_FOLLOWERS -- "Followers"
+--local GARRISON_FOLLOWER_CAN_COUNTER=GARRISON_FOLLOWER_CAN_COUNTER -- "This follower can counter:"
+--local GARRISON_FOLLOWER_EXHAUSTED=GARRISON_FOLLOWER_EXHAUSTED -- "Recovering (1 Day)"
+--local GARRISON_FOLLOWER_INACTIVE=GARRISON_FOLLOWER_INACTIVE --"Inactive"
+--local GARRISON_FOLLOWER_IN_PARTY=GARRISON_FOLLOWER_IN_PARTY
+--local GARRISON_FOLLOWER_ON_MISSION=GARRISON_FOLLOWER_ON_MISSION -- "On Mission"
+--local GARRISON_FOLLOWER_WORKING=GARRISON_FOLLOWER_WORKING -- "Working
 local GARRISON_MISSION_PERCENT_CHANCE="%d%%"-- GARRISON_MISSION_PERCENT_CHANCE
 local GARRISON_MISSION_SUCCESS=GARRISON_MISSION_SUCCESS -- "Success"
 local GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS=GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS -- "%d Follower mission";
@@ -164,6 +124,7 @@ local GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY=GARRISON_FOLLOWER_MAX_UPGRADE_QUALIT
 local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL -- 100

 local LEVEL=LEVEL -- Level
+local MISSING=ADDON_MISSING
 local NOT_COLLECTED=NOT_COLLECTED -- not collected
 local GMF=GarrisonMissionFrame
 local GMFFollowerPage=GMF.FollowerTab
@@ -171,9 +132,6 @@ local GMFFollowers=GarrisonMissionFrameFollowers
 local GMFMissionPage=GMF.MissionTab.MissionPage
 local GMFMissionPageFollowers = GMFMissionPage.Followers
 local GMFMissions=GarrisonMissionFrameMissions
-local GMFMissionsTab1=GarrisonMissionFrameMissionsTab1
-local GMFMissionsTab2=GarrisonMissionFrameMissionsTab2
-local GMFMissionsTab3=GarrisonMissionFrameMissionsTab2
 local GMFRewardPage=GMF.MissionComplete
 local GMFRewardSplash=GMFMissions.CompleteDialog
 local GMFMissionsListScrollFrameScrollChild=GarrisonMissionFrameMissionsListScrollFrameScrollChild
@@ -181,12 +139,9 @@ local GMFMissionsListScrollFrame=GarrisonMissionFrameMissionsListScrollFrame
 local GMFFollowersListScrollFrameScrollChild=GarrisonMissionFrameFollowersListScrollFrameScrollChild
 local GMFFollowersListScrollFrame=GarrisonMissionFrameFollowersListScrollFrame
 local GMFMissionListButtons=GMF.MissionTab.MissionList.listScroll.buttons
-local GMFTab1=GarrisonMissionFrameTab1
-local GMFTab2=GarrisonMissionFrameTab2
-local GMFTab3=_G.GarrisonMissionFrameTab3
 local GarrisonFollowerTooltip=GarrisonFollowerTooltip
 local GarrisonMissionFrameMissionsListScrollFrame=GarrisonMissionFrameMissionsListScrollFrame
-local IGNORE_UNAIVALABLE_FOLLOWERS=IGNORE.. ' ' .. UNAVAILABLE .. ' ' .. GARRISON_FOLLOWERS
+local IGNORE_UNAIVALABLE_FOLLOWERS=IGNORE.. ' ' .. UNAVAILABLE
 local IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL=IGNORE.. ' ' .. GARRISON_FOLLOWER_INACTIVE .. ',' .. GARRISON_FOLLOWER_ON_MISSION ..',' .. GARRISON_FOLLOWER_WORKING.. ' ' .. GARRISON_FOLLOWERS
 local PARTY=PARTY -- "Party"
 local SPELL_TARGET_TYPE1_DESC=capitalize(SPELL_TARGET_TYPE1_DESC) -- any
@@ -214,6 +169,11 @@ local function splitFormat(base)
 	local G2=G:sub(1,i-1)..m1..G:sub(s+1)
 	return G1,G2
 end
+local function ShowTT(this)
+	GameTooltip:SetOwner(this, "ANCHOR_TOPRIGHT")
+	GameTooltip:SetText(this.tooltip)
+	GameTooltip:Show()
+end

 local GARRISON_DURATION_DAY,GARRISON_DURATION_DAYS=splitFormat(GARRISON_DURATION_DAYS) -- "%d |4day:days;";
 local GARRISON_DURATION_DAY_HOURS,GARRISON_DURATION_DAYS_HOURS=splitFormat(GARRISON_DURATION_DAYS_HOURS) -- "%d |4day:days; %d hr";
@@ -221,8 +181,8 @@ local GARRISON_DURATION_HOURS=GARRISON_DURATION_HOURS -- "%d hr";
 local GARRISON_DURATION_HOURS_MINUTES=GARRISON_DURATION_HOURS_MINUTES -- "%d hr %d min";
 local GARRISON_DURATION_MINUTES=GARRISON_DURATION_MINUTES -- "%d min";
 local GARRISON_DURATION_SECONDS=GARRISON_DURATION_SECONDS -- "%d sec";
-local AGE_HOURS="First seen " .. GARRISON_DURATION_HOURS_MINUTES .. " ago"
-local AGE_DAYS="First seen " .. GARRISON_DURATION_DAYS_HOURS .. " ago"
+local AGE_HOURS="Expires in " .. GARRISON_DURATION_HOURS_MINUTES
+local AGE_DAYS="Expires in " .. GARRISON_DURATION_DAYS_HOURS


 -- Panel sizes
@@ -236,6 +196,8 @@ local FLSIZE=400
 local BIGBUTTON=BIGSIZEW-GCSIZE
 local SMALLBUTTON=BIGSIZEW-GCSIZE
 local GCF
+local GMC
+local GMCUsedFollowers={}
 local GCFMissions
 local GCFBusyStatus
 local GameTooltip=GameTooltip
@@ -250,6 +212,10 @@ local GarrisonMissionButton_SetRewards=GarrisonMissionButton_SetRewards
 local GetItemInfo=GetItemInfo
 local type=type
 local ITEM_QUALITY_COLORS=ITEM_QUALITY_COLORS
+function addon:GetDifficultyColors(perc,usePurple)
+	local q=self:GetDifficultyColor(perc,usePurple)
+	return q.r,q.g,q.b
+end
 function addon:GetDifficultyColor(perc,usePurple)
 	if(perc >90) then
 		return QuestDifficultyColors['standard']
@@ -260,7 +226,7 @@ function addon:GetDifficultyColor(perc,usePurple)
 	elseif(perc >20) then
 		return QuestDifficultyColors['impossible']
 	else
-		return not usePurple and QuestDifficultyColors['trivial'] or C.Purple
+		return not usePurple and C.Silver or C.Fuchsia
 	end
 end
 if (LibDebug) then LibDebug() end
@@ -278,6 +244,7 @@ local followersCacheIndex={}
 local dirty=false
 local cache
 local dbcache
+local db
 local n=setmetatable({},{
 	__index = function(t,k)
 		local name=addon:GetFollowerData(k,'fullname')
@@ -317,6 +284,39 @@ local function genIteratorByThreat(missionID,threat,tbl)
 	end
 end

+--- Quick backdrop
+--
+local function addBackdrop(f)
+	local backdrop = {
+		bgFile="Interface\\TutorialFrame\\TutorialFrameBackground",
+		edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
+		tile=true,
+		tileSize=16,
+		edgeSize=16,
+		insets={bottom=7,left=7,right=7,top=7}
+	}
+	f:SetBackdrop(backdrop)
+end
+
+--generic table scan
+
+local function inTable(table, value)
+	if (type(table)~='table') then return false end
+	if (#table > 0) then
+		for i=1,#table do
+			if (value==table[i]) then return true end
+		end
+	else
+		for k,v in pairs(table) do
+			if v == value then
+				return true
+			end
+		end
+	end
+	return false
+end
+
+
 --- Parties storage
 --
 --
@@ -324,12 +324,7 @@ local parties=setmetatable({},{
 	__index=function(t,k) rawset(t,k,{members={},perc=0,full=false}) return t[k] end
 })
 local function inParty(missionID,followerID)
-	local members=parties[missionID].members
-	if (dbg) then print("Party check",missionID) end
-	for i=1,#members do
-		if (dbg) then print("Checking",members[i],"against",followerID) end
-		if (members[i]==followerID) then return true end
-	end
+	return inTable(parties[missionID].members,followerID)
 end
 --- Follower Missions Info
 --
@@ -339,11 +334,11 @@ local followerMissions=setmetatable({},{

 --
 -- Temporary party management
-local openParty,isInParty,pushFollower,removeFollower,closeParty,roomInParty,storeFollowers,dumpParty
+local openParty,partyIgnore,isPartyIgnored,isInParty,pushFollower,removeFollower,fillParty,closeParty,roomInParty,storeFollowers,dumpParty,isPartyEmpty

 do
-	local ID,frames,members,maxFollowers=0,{},{},1
-	---@function [parent=#local] openParty
+	local ID,frames,members,maxFollowers,ignored=0,{},{},1,{}
+	---@function [parent=#party] openParty
 	function openParty(missionID,followers)
 		if (#frames > 0 or #members > 0) then
 			error(format("Unbalanced openParty/closeParty %d %d",#frames,#members))
@@ -355,28 +350,41 @@ do
 		end
 		ID=missionID
 	end
-	---@function [parent=#local] isInParty
+
+	---@function [parent=#party] partyIgnore
+	function partyIgnore(followerID,soft)
+		ignored[followerID]=soft and 1 or 2
+	end
+	---@function [parent=#party] isPartyIgnored
+	function isPartyIgnored(followerID)
+		return ignored[followerID]
+	end
+
+	---@function [parent=#party] isInParty
 	function isInParty(followerID)
-		for i=1,maxFollowers do
-			if (followerID==members[i]) then return true end
-		end
+		return inTable(members,followerID)
 	end

-	---@function [parent=#local] roomInParty
+	---@function [parent=#party] roomInParty
 	function roomInParty()
 		return maxFollowers-#members
 	end

-	---@function [parent=#local] dumpParty
+	---@function [parent=#party] isPartyEmpty
+	function isPartyEmpty()
+		return maxFollowers>0 and #members==0
+	end
+
+	---@function [parent=#party] dumpParty
 	function dumpParty()
 		for i=1,3 do
 			if (members[i]) then
-				print(i,addob:GetFollowerData(members[i],'fullname'))
+				xprint(i,addon:GetFollowerData(members[i],'fullname'))
 			end
 		end
 	end

-	---@function [parent=#local] pushFollower
+	---@function [parent=#party] pushFollower
 	function pushFollower(followerID)
 		if (followerID:sub(1,2) ~= '0x') then trace(followerID .. "is not an id") end
 		if (roomInParty()>0) then
@@ -391,7 +399,7 @@ do
 			end
 		end
 	end
-	---@function [parent=#local] removeFollowers
+	---@function [parent=#party] removeFollowers
 	function removeFollower(followerID)
 		for i=1,maxFollowers do
 			if (followerID==members[i]) then
@@ -404,7 +412,7 @@ do
 		end
 	end

-	---@function [parent=#local] storeFollowers
+	---@function [parent=#party] storeFollowers
 	function storeFollowers(table)
 		wipe(table)
 		for i=1,#members do
@@ -412,8 +420,22 @@ do
 		end
 		return #table
 	end
+	---@function [parent=#party] fillParty
+	function fillParty()
+		if roomInParty() < 1 then return end
+		for followerID,soft in pairs(ignored) do
+			if soft==1 then
+				if not isInParty(followerID) then
+					pushFollower(followerID)
+				end
+				if (roomInParty()<=0) then
+					break
+				end
+			end
+		end
+	end

-	---@function [parent=#local] closeParty
+	---@function [parent=#party] closeParty
 	function closeParty()
 		local perc=select(4,G.GetPartyMissionInfo(ID))
 		for i=1,3 do
@@ -433,7 +455,8 @@ do
 		end
 		wipe(frames)
 		wipe(members)
-		return perc
+		wipe(ignored)
+		return perc or 0
 	end
 end
 --
@@ -441,14 +464,12 @@ end
 local origGarrisonMissionButton_OnEnter = _G.GarrisonMissionButton_OnEnter
 function _G.GarrisonMissionButton_OnEnter(this,button)
 	origGarrisonMissionButton_OnEnter(this,button)
+	--@debug@
 	if (this.info.inProgress) then
 		GameTooltip:AddDoubleLine("ID:",this.info.missionID)
-		for i=1,#this.info.followers do
-			GameTooltip:AddDoubleLine("ID:",this.info.followers[i])
-			GameTooltip:AddDoubleLine("Name:",addon:GetFollowerData(this.info.followers[i],'fullname'))
-		end
 		GameTooltip:Show()
 	end
+	--@end-debug@
 end
 --@end-debug@
 -- These local will became conf var
@@ -508,34 +529,70 @@ function addon.Garrison_SortMissions_Followers(missionsList)
 	end
 	table.sort(missionsList, comparison);
 end
+function addon.Garrison_SortMissions_Xp(missionsList)
+	local comparison
+	do
+		function comparison(mission1, mission2)
+			local p1=addon:GetMissionData(mission1.missionID,'globalXp')
+			local p2=addon:GetMissionData(mission2.missionID,'globalXp')
+			if (p1==p2) then
+				return strcmputf8i(mission1.name, mission2.name) < 0
+			else
+				return p2 < p1
+			end
+		end
+	end
+	table.sort(missionsList, comparison);
+end

 function addon:OnInitialized()
 --@debug@
 	xprint("OnInitialized")
-	LoadAddOn("Blizzard_DebugTools")
-	self:DebugEvents()
 --@end-debug@
+--@alpha@
+	self:Popup(L["You are using an Alpha version of Garrison Commander. Please post bugs on Curse if you find them"],10)
+--@end-alpha@
+	for _,b in ipairs(GMFMissionsListScrollFrame.buttons) do
+		local scale=0.8
+		local f,h,s=b.Title:GetFont()
+		b.Title:SetFont(f,h*scale,s)
+		local f,h,s=b.Summary:GetFont()
+		b.Summary:SetFont(f,h*scale,s)
+	end
 	self:CreatePrivateDb()
+	db=self.db.global
 	self:SafeRegisterEvent("GARRISON_MISSION_STARTED")
 	self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE")
 	self:SafeRegisterEvent("GARRISON_MISSION_NPC_CLOSED",function(...) GCF:Hide() end)
 	self:SafeHookScript("GarrisonMissionFrame","OnShow","SetUp",true)
+	self:AddLabel("Appearance")
 	self:AddToggle("MOVEPANEL",true,L["Unlock Panel"])
+	self:AddToggle("BIGSCREEN",true,L["Use big screen"],L["Disabling this will give you the interface from 1.1.8, given or taken. Need to reload interface"])
+	self:AddToggle("PIN",true,L["Show Garrison Commander menu"],L["Disable if you dont want the full Garrison Commander Header."])
+	self:AddLabel("Mission Panel")
 	self:AddToggle("IGM",true,IGNORE_UNAIVALABLE_FOLLOWERS,IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL)
-	self:AddToggle("IGP",true,L['Ignore "maxed" followers'],L["Level 100 epic followers are not used for match making unless they are needed to fill up the roster."])
-	self:AddToggle("NOFILL",false,L["Do not prefill mission page"],L["Disables automatic population of mission page screen. You can also press control while clicking to disable it for a single mission"])
+	self:AddToggle("IGP",true,L['Ignore "maxed"'],L["Level 100 epic followers are not used for xp only missions."])
+	self:AddToggle("NOFILL",false,L["No mission prefill"],L["Disables automatic population of mission page screen. You can also press control while clicking to disable it for a single mission"])
 	self:AddSelect("MSORT","Garrison_SortMissions_Original",
 	{
 		Garrison_SortMissions_Original=L["Original method"],
 		Garrison_SortMissions_Chance=L["Success Chance"],
 		Garrison_SortMissions_Followers=L["Number of followers"],
 		Garrison_SortMissions_Age=L["Days since first seen"],
+		Garrison_SortMissions_Xp=L["Global approx. xp reward"],
 	},
 	L["Sort missions by:"],L["Original sort restores original sorting method, whatever it was (If you have another addon sorting mission, it should kick in again)"])
-	self:AddToggle("BIGSCREEN",true,L["Use big screen"],L["Disabling this will give you the interface from 1.1.8, given or taken. Need to reload interface"])
 	bigscreen=self:GetBoolean("BIGSCREEN")
+	self:AddLabel("Followers Panel")
 	self:AddSlider("MAXMISSIONS",5,1,8,L["Mission shown for follower"],nil,1)
 	self:AddSlider("MINPERC",50,0,100,L["Minimun chance success under which ignore missions"],nil,5)
+	self:AddPrivateAction("ShowMissionControl",L["Mission control"],L["You can choose some criteria and have GC autosumbit missions for you"])
+--@debug@
+	self:AddLabel("Developers options")
+	self:AddToggle("DBG",false, "Enable Debug")
+	self:AddToggle("TRC",false, "Enable Trace")
+--@end-debug@
+
 	self:Trigger("MSORT")
 	return true
 end
@@ -547,6 +604,7 @@ function addon:CheckMP()
 			return
 		end
 		if GetAddOnMetadata("MasterPlan","Version")>="0.23" then
+			-- New compatible version
 			self:AddToggle("CKMP",true,L["Use GC Interface"],L["Switches between Garrison Commander and Master Plan mission interface. Tested with MP >0.23"])
 			MPGoodGuy=true
 			MPSwitch=true
@@ -567,14 +625,24 @@ function addon:ApplyIGM(value)
 	self:RefreshMission()
 end
 function addon:ApplyCKMP(value)
+	self:Clock()
 	if (MasterPlanMissionList) then
 		if (value) then
 			MasterPlanMissionList:Hide()
 		else
 			MasterPlanMissionList:Show()
 		end
-		self:RefreshMission()
 	end
+	self:RefreshMission()
+end
+function addon:ApplyDBG(value)
+	dbg=value
+end
+function addon:ApplyPIN(value)
+	pin=value
+end
+function addon:ApplyTRC(value)
+	trc=value
 end
 function addon:ApplyBIGSCREEN(value)
 		if (value) then
@@ -623,8 +691,6 @@ function addon:RestoreTooltip()
 	end
 end

-
-
 --[[
 	[12]={
 		description="Iron Horde raiders have descended on nearby draenei villages. Find the raiders' camp and raid it. Turnabout, they say, is fair play.",
@@ -723,66 +789,47 @@ function addon:FillCounters(missionID,mission)
 	local slots=mission.slots
 	local missioncounters=counters[missionID]
 	wipe(missioncounters)
-	for id,d in pairs(G.GetBuffedFollowersForMission(missionID)) do
-		local rank=self:GetFollowerData(id,'rank')
-		local quality=self:GetFollowerData(id,'quality')
-		local bias= G.GetFollowerBiasForMission(missionID,id);
-		for i,l in pairs(d) do
-			-- i is meaningful
-			-- l.counterIcon
-			-- l.name
-			-- l.counterName
-			-- l.icon
-			-- l.description
-			tinsert(missioncounters,{k=cleanicon(l.icon),mechanic=true,name=l.name,followerID=id,bias=bias,rank=rank,quality=quality,icon=l.icon})
-			followerMissions[id][missionID]=1+ (tonumber(followerMissions[id][missionID]) or 0)
-		end
-	end
-	for id,d in pairs(G.GetFollowersTraitsForMission(missionID)) do
-		local bias= G.GetFollowerBiasForMission(missionID,id);
-		local rank=self:GetFollowerData(id,'rank')
-		local quality=self:GetFollowerData(id,'quality')
-		for i,l in pairs(d) do
-			--l.traitID
-			--l.icon
-			followerMissions[id][missionID]=1+ (tonumber(followerMissions[id][missionID]) or 0)
-			tinsert(missioncounters,{k=cleanicon(l.icon),trait=true,name=l.traitID,followerID=id,bias=bias,rank=rank,quality=quality,icon=l.icon})
-		end
-	end
-	table.sort(missioncounters,cmp)
-	local cf=wipe(counterFollowerIndex[missionID])
-	local ct=wipe(counterThreatIndex[missionID])
-	for i=1,#missioncounters do
-		tinsert(cf[missioncounters[i].followerID],i)
-		tinsert(ct[missioncounters[i].k],i)
-	end
-end
-function addon:Check(missionID)
-
-end
-function addon:ThreatDisplayer()
-	TF="0x00000000000C2C1B"
-	if (not AXE) then
-		local AXE=CreateFrame("Frame","AXE",UIParent,"GarrisonAbilityLargeCounterTemplate")
-		AXI=CreateFrame("Frame","AXI",UIParent,"GarrisonAbilityCounterTemplate")
-	end
-	if (not BUBU) then
-		CreateFrame("CheckButton","BUBU",AXE,"UICheckButtonTemplate")
-	end
-
-	BUBU:SetPoint("CENTER")
-	BUBU:SetChecked(true)
-	BUBU:GetCheckedTexture():SetVertexColor(1,0,0)
-
-	AXE:SetPoint("CENTER",-100.0)
-	AXI:SetPoint("CENTER",100,0)
-	AXE:Show()
-	AXI:Show()
-	local id=154
-	local env=select(5,C_Garrison.GetMissionInfo(id))
-	AXI.Icon:SetTexture(env)
-	AXI.Border:SetVertexColor(1,0,0)
+	local t=G.GetBuffedFollowersForMission(missionID)
+	if t then
+		for id,d in pairs(t) do
+			local rank=self:GetFollowerData(id,'rank')
+			local quality=self:GetFollowerData(id,'quality')
+			local bias= G.GetFollowerBiasForMission(missionID,id);
+			for i,l in pairs(d) do
+				-- i is meaningful
+				-- l.counterIcon
+				-- l.name
+				-- l.counterName
+				-- l.icon
+				-- l.description
+				tinsert(missioncounters,{k=cleanicon(l.icon),mechanic=true,name=l.name,followerID=id,bias=bias,rank=rank,quality=quality,icon=l.icon})
+				followerMissions[id][missionID]=1+ (tonumber(followerMissions[id][missionID]) or 0)
+			end
+		end
+	end
+	t= G.GetFollowersTraitsForMission(missionID)
+	if t then
+		for id,d in pairs(t) do
+			local bias= G.GetFollowerBiasForMission(missionID,id);
+			local rank=self:GetFollowerData(id,'rank')
+			local quality=self:GetFollowerData(id,'quality')
+			for i,l in pairs(d) do
+				--l.traitID
+				--l.icon
+				followerMissions[id][missionID]=1+ (tonumber(followerMissions[id][missionID]) or 0)
+				tinsert(missioncounters,{k=cleanicon(l.icon),trait=true,name=l.traitID,followerID=id,bias=bias,rank=rank,quality=quality,icon=l.icon})
+			end
+		end
+		table.sort(missioncounters,cmp)
+		local cf=wipe(counterFollowerIndex[missionID])
+		local ct=wipe(counterThreatIndex[missionID])
+		for i=1,#missioncounters do
+			tinsert(cf[missioncounters[i].followerID],i)
+			tinsert(ct[missioncounters[i].k],i)
+		end
+	end
 end
+
 --[[
 Matchmaker debug for Spell Check
 Slots
@@ -890,6 +937,28 @@ local function best(fid1,fid2,counters)
 	end
 	return fid1
 end
+local epicMountTrait=221
+local extraTrainingTrait=80 --all followers +35
+local fastLearnerTrait=29 -- only this follower +50
+local hearthStoneProTrait=236 -- all followers +36
+local scavengerTrait=79 -- More resources
+function addon:AddTraitsToParty(missionID,mission,skipBusy,skipMaxed)
+	local t=counters[missionID]
+	if (t) then
+		for i=1,#t do
+			local follower=t[i]
+			if (follower.trait and not isPartyIgnored(follower.followerID) and not isInParty(follower.followerID)) then
+				if mission.resources > 0 and follower.name==scavengerTrait then
+					pushFollower(follower.followerID)
+				elseif mission.xpOnly  and (follower.name==extraTrainingTrait or follower.name==hearthStoneProTrait) then
+					pushFollower(follower.followerID)
+				elseif mission.durationSeconds > GARRISON_LONG_MISSION_TIME  and follower.name==epicMountTrait then
+					pushFollower(follower.followerID)
+				end
+			end
+		end
+	end
+end
 function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed)
 	local perc=select(4,G.GetPartyMissionInfo(missionID)) -- If percentage is already 100, I'll try and add the most useless character
 	local candidateMissions=10000
@@ -906,7 +975,7 @@ function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed)
 		for i=1,totFollowers do
 			local data=followersCache[i]
 			local followerID=data.followerID
-			if (not self:IsIgnored(followerID,missionID) and not(skipMaxed and data.maxed) and not isInParty(followerID) and self:GetFollowerStatusForMission(followerID,skipBusy)) then
+			if (not isPartyIgnored(followerID) and not isInParty(followerID) and not self:IsIgnored(followerID,missionID) and not(skipMaxed and data.maxed and mission.xpOnly) and not isInParty(followerID) and self:GetFollowerStatusForMission(followerID,skipBusy)) then
 				local missions=#followerMissions[followerID]
 				local rank=data.rank
 				local quality=data.quality
@@ -926,7 +995,7 @@ function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed)
 							break --continue
 						end
 					end
-					-- This candidate is not improving success chance, minimize
+					-- This candidate is not improving success chance or we are already at 100%, minimize
 					if (i < totFollowers  and data.maxed) then
 						break  -- Pointless using a maxed follower if we  have more follower to try
 					end
@@ -968,60 +1037,64 @@ function addon:MatchMaker(missionID,mission,party)
 	if (GMFRewardSplash:IsShown()) then return end
 	if (not mission) then mission=self:GetMissionData(missionID) end
 	if (not party) then party=parties[missionID] end
-	local skipBusy=addon:GetBoolean("IGM")
+	local skipBusy=self:GetBoolean("IGM")
 	local skipMaxed=self:GetBoolean("IGP")
-	dbg=missionID==(tonumber(_G.MW) or 0)
+	dbg=dbg or missionID==(tonumber(_G.MW) or 0)
 	local slots=mission.slots
 	local missionCounters=counters[missionID]
 	local ct=counterThreatIndex[missionID]
 	local maxedSkipped=new()
 	local ignoredSkipped=new()
 	openParty(missionID,mission.numFollowers)
-	for i=1,#slots do
-		local threat=cleanicon(slots[i].icon)
-		local candidates=ct[threat]
-		local choosen
-		for i=1,#candidates do
-			local followerID=missionCounters[candidates[i]].followerID
-			if(not addon:GetFollowerStatusForMission(followerID,skipBusy)) then
-				if (dbg) then print("Skipped",n[followerID],"due to skipbusy" ) end
-			elseif (self:IsIgnored(followerID,missionID)) then
-				tinsert(ignoredSkipped,followerID)
-				if (dbg) then print("Skipped",n[followerID],"due to ignored" ) end
-			elseif (skipMaxed and self:GetFollowerData(followerID,'maxed')) then
-				tinsert(maxedSkipped,followerID)
-				if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end
+	-- Preloading skipped ones in party table.
+	if (missionCounters) then
+		for i=1,#missionCounters do
+			local followerID=missionCounters[i].followerID
+			if (not followerID) then
+				xprint("Trying to use [",followerID,"]")
 			else
-				choosen=best(choosen,candidates[i],missionCounters)
-				if (dbg) then print("Taken",n[missionCounters[choosen].followerID]) end
-			end
-		end
-		if (choosen) then
-			if (type(missionCounters[choosen]) ~="table") then
-				trace(format("%s %s %d %d",mission.name,threat,missionID,tonumber(choosen) or 0))
-			end
-			pushFollower(missionCounters[choosen].followerID)
-		end
-		if (roomInParty()==0) then
-			break
-		end
-	end
-	self:CompleteParty(missionID,mission,skipBusy,skipMaxed)
-	if (roomInParty()>0) then
-		--We try to use maxed, then ignored followers
-		for i=1,#maxedSkipped do
-			pushFollower(maxedSkipped[i])
-			if (roomInParty()==0) then
-				break
+				if (self:IsIgnored(followerID,missionID)) then
+					if (dbg) then print("Skipped",n[followerID],"due to ignored" ) end
+					partyIgnore(followerID,true)
+				elseif not addon:GetFollowerStatusForMission(followerID,skipBusy) then
+					if (dbg) then print("Skipped",n[followerID],"due to busy" ) end
+					partyIgnore(followerID)
+				elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then
+					if (dbg) then print("Skipped",n[followerID],"due to busy" ) end
+					partyIgnore(followerID,true)
+				end
 			end
 		end
-		for i=1,#ignoredSkipped do
-			pushFollower(ignoredSkipped[i])
-			if (roomInParty()==0) then
-				break
+		if (type(slots)=='table') then
+			for i=1,#slots do
+				local threat=cleanicon(slots[i].icon)
+				local candidates=ct[threat]
+				local choosen
+				for i=1,#candidates do
+					local followerID=missionCounters[candidates[i]].followerID
+					if followerID then
+						if(not isPartyIgnored(followerID)) then
+							choosen=best(choosen,candidates[i],missionCounters)
+							if (dbg) then print("Taken",n[missionCounters[choosen].followerID]) end
+						end
+					end
+				end
+				if (choosen) then
+					if (type(missionCounters[choosen]) ~="table") then
+						trace(format("%s %s %d %d",mission.name,threat,missionID,tonumber(choosen) or 0))
+					end
+					pushFollower(missionCounters[choosen].followerID)
+				end
+				if (roomInParty()==0) then
+					break
+				end
 			end
+		else
+			xprint("Mission",missionID,"has no slots????")
 		end
+		if roomInParty() > 0 then self:AddTraitsToParty(missionID,mission) end
 	end
+	--if roomInParty() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end
 	storeFollowers(party.members)
 	party.full= roomInParty()==0
 	party.perc=closeParty()
@@ -1030,6 +1103,16 @@ function addon:IsIgnored(followerID,missionID)
 	if (dbcache.ignored[missionID][followerID]) then return true end
 	if (dbcache.totallyignored[followerID]) then return true end
 end
+function addon:GetAllCounters(missionID,threat,table)
+	wipe(table)
+	local iter=genIteratorByThreat(missionID,cleanicon(tostring(threat)),new())
+	for i=1,iter() do
+		if (iter[i]) then
+			tinsert(table,iter[i].followerID)
+		end
+	end
+	del(iter)
+end
 function addon:GetCounterBias(missionID,threat)
 	local bias=-1
 	local who=""
@@ -1059,7 +1142,6 @@ function addon:AddLine(name,status)
 	GameTooltip:AddDoubleLine(name, status,nil,nil,nil,r2,g2,b2)
 end
 function addon:SetThreatColor(obj,missionID)
-	dbg=missionID==(tonumber(_G.MW) or 0)
 	if (dbg) then print("Evaluating ",missionID,obj.Icon:GetTexture()) end
 	local bias=self:GetCounterBias(missionID,obj.Icon:GetTexture())
 	local color=self:GetBiasColor(bias,nil,"Green")
@@ -1068,11 +1150,11 @@ function addon:SetThreatColor(obj,missionID)
 end

 function addon:HookedGarrisonMissionButton_AddThreatsToTooltip(missionID)
+	if (GMC:IsShown()) then return end
+	self:RenderTooltip(missionID)
+end
+function addon:RenderTooltip(missionID)
 	local mission=self:GetMissionData(missionID)
-	local button=GetMouseFocus()
---@debug@
-	GameTooltip:AddLine("ID:" .. tostring(missionID))
---@end-debug@
 	if (not mission) then
 --@debug@
 		GameTooltip:AddLine("E dove minchia è finita??")
@@ -1118,17 +1200,6 @@ function addon:HookedGarrisonMissionButton_AddThreatsToTooltip(missionID)
 		biascolors[fullname]={self:GetBiasColor(followerID,missionID,"White"),self:GetFollowerStatus(followerID,true)}
 	end
 	table.sort(fullnames)
-	if (not bigscreen) then
-		GameTooltip:AddLine(PARTY)
-		for i=1,#party do
-			local fullname=party[i]
-			local info=biascolors[fullname]
-			self:AddLine(fullname,info[2],info[1])
-		end
-		if (#party < mission.numFollowers) then
-			GameTooltip:AddLine(GARRISON_PARTY_NOT_FULL_TOOLTIP,C.Red())
-		end
-	end
 	GameTooltip:AddLine(L["Other useful followers"])
 	for i=1,#fullnames do
 		local fullname=fullnames[i]
@@ -1173,7 +1244,8 @@ function addon:RefreshMission(missionID)
 	end
 end

-function addon:BuildMissionsCache(fc,mm)
+function addon:BuildMissionsCache(fc,mm,OnEvent)
+--cache.missions
 --@debug@
 	local start=GetTime()
 	xprint("Start Full Cache Rebuild")
@@ -1182,11 +1254,24 @@ function addon:BuildMissionsCache(fc,mm)
 	G.GetAvailableMissions(t)
 	for index=1,#t do
 		local missionID=t[index].missionID
+		if (not	dbcache.seen[missionID]) then
+			dbcache.seen[missionID]=OnEvent and time() or dbcache.lastseen
+		end
 		self:BuildMissionCache(missionID,t[index])
 		if fc then self:FillCounters(missionID) end
 		if mm then self:MatchMaker(missionID) end
 	end
+	for k,v in pairs(dbcache.seen) do
+		if (not cache.missions[k]) then
+			local span=time()-tonumber(v) or time()
+			if (span > db.lifespan[k]) then
+				db.lifespan[k]=span
+			end
+			dbcache.seen[k]=nil
+		end
+	end
 	del(t)
+	collectgarbage("step",10)
 --@debug@
 	xprint("Done in",GetTime()-start)
 --@end-debug@
@@ -1260,39 +1345,87 @@ end
 	rank=0,
 	locPrefix=false
 }
+GetBasicInfo Table Format={
+	description="With infernals and felguard invading Talador, the rest of the Burning Legion can't be far behind. Defeat them, and try to find their source.",
+	cost=15,
+	duration="8 hr",
+	durationSeconds=28800,
+	level=100,
+	type="Combat",
+	locPrefix="GarrMissionLocation-Talador",
+	rewards={
+		[248]={
+			itemID=114057,
+			quantity=1
+		}
+	},
+	numRewards=1,
+	numFollowers=3,
+	state=-2,
+	iLevel=0,
+	name="Burning Legion Vanguard",
+	followers={
+	},
+	location="Talador",
+	isRare=false,
+	typeAtlas="GarrMission_MissionIcon-Combat",
+	missionID=113
+}
+
 --]]
 function addon:BuildMissionCache(id,data)
-	if (not	dbcache.seen[id]) then
-		dbcache.seen[id]=time()
-	end
 	local mission=cache.missions[id]
-	if (mission.name=="<newmission>") then
-		if (not data) then
-			mission.name=G.GetMissionName(id)
-			mission.numFollowers=G.GetMissionMaxFollowers(id)
-			mission.durationSeconds=select(5,G.GetMissionTimers(id))
-		else
-			mission.name=data.name
-			mission.numFollowers=data.numFollowers
-			mission.durationSeconds=data.durationSeconds
-		end
+	if (not mission) then
+--@dedbug@
+		xprint("Generating new data for ",id)
+--@end-debug@
+		mission = data or G.GetBasicMissionInfo(id)
+		if (not mission) then return end
+		cache.missions[id]=mission
+		if dbg then print("Retrieved",id,mission.name) end
+		local _,xp,type,typeDesc,typeIcon,locPrefix,_,enemies=G.GetMissionInfo(id)
 		mission.rank=mission.level < 100 and mission.level or mission.iLevel
-		mission.xp=true
-		mission.resources=false
-		for k,v in pairs(G.GetMissionRewardInfo(id)) do
-			if (not v.followerXP) then mission.xp=false end
-			if (v.currencyID and v.currencyID==GARRISON_CURRENCY) then mission.resource=false end
+		mission.xp=xp
+		mission.xpBonus=0
+		mission.resources=0
+		mission.gold=0
+		mission.followerUpgrade=0
+		mission.itemLevel=0
+		for k,v in pairs(mission.rewards) do
+			if (v.followerXP) then mission.xpBonus=mission.xpBonus+v.followerXP end
+			if (v.currencyID and v.currencyID==GARRISON_CURRENCY) then mission.resources=v.quantity end
+			if (v.currencyID and v.currencyID==0) then mission.gold =mission.gold+v.quantity/10000 end
+			if (v.itemID) then
+				if (v.itemID~=120205) then
+					local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount,itemEquipLoc, itemTexture, itemSellPrice = GetItemInfo(v.itemID)
+					if (itemName) then
+						if (itemLevel > 1 ) then
+							mission.itemLevel=itemLevel
+						else
+							mission.followerUpgrade=1
+						end
+					end
+				end
+			end
+		end
+		mission.totalXp=(tonumber(mission.xp) or 0) + (tonumber(mission.xpBonus) or 0)
+		mission.globalXp=mission.totalXp*mission.numFollowers
+		if (mission.resources==0 and mission.gold==0 and mission.itemLevel==0 and mission.followerUpgrade==0) then
+			mission.xpOnly=true
+		else
+			mission.xpOnly=false
 		end
-		local _,xp,type,typeDesc,typeIcon,locPrefix,_,enemies=G.GetMissionInfo(id)
 		mission.locPrefix=locPrefix
 		if (not type) then
 --@debug@
-			print("No type",id,data.name)
+			xprint("No type",id,data.name)
 --@end-debug@
 		else
-			self.db.global.types[type]={name=type,description=typeDesc,icon=typeIcon}
+			if (not self.db.global.types[type]) then
+				self.db.global.types[type]={name=type,description=typeDesc,icon=typeIcon}
+			end
 		end
-		wipe(mission.slots)
+		mission.slots={}
 		local slots=mission.slots

 		for i=1,#enemies do
@@ -1305,13 +1438,16 @@ function addon:BuildMissionCache(id,data)
 		if (type) then
 			tinsert(slots,{name=TYPE,key=type,icon=typeIcon})
 		end
+		--collectgarbace("step",100)
 	end
 	mission.basePerc=select(4,G.GetPartyMissionInfo(id))
+
 end
 function addon:SetDbDefaults(default)
 	default.global=default.global or {}
 	default.global["*"]={
 	}
+	default.global.lifespan={["*"]=0}
 end
 function addon:CreatePrivateDb()
 	self.privatedb=self:RegisterDatabase(
@@ -1338,6 +1474,17 @@ function addon:CreatePrivateDb()
 				},
 				runningIndex={
 					["*"]=0
+				},
+				missionControl={
+					allowedRewards = {["*"]=true},
+					rewardChance={["*"]=100},
+					useOneChance=true,
+					itemPrio = {},
+					minimumChance = 100,
+					minDuration = 0,
+					maxDuration = 24,
+					epicExp = false,
+					skipRare=true
 				}
 			}
 		},
@@ -1346,21 +1493,7 @@ function addon:CreatePrivateDb()
 		"GACPrivateVolatile",
 		{
 			profile={
-				missions={
-					["*"]={
-						counters={},
-						slots={},
-						missionID=0,
-						numFollowers=0,
-						name="<newmission>",
-						basePerc=0,
-						durationSeconds=0,
-						level=0,
-						iLevel=0,
-						rank=0,
-						locPrefix=false
-					}
-				}
+				missions={}
 			}
 		}
 	,
@@ -1371,18 +1504,13 @@ end
 function addon:SetClean()
 	dirty=false
 end
-function addon:wipe(i)
---@debug@
-	DevTools_Dump(i)
-	self.privatedb:ResetDB()
---@end-debug@
-end
+
 function addon:WipeMission(missionID)
 	cache.missions[missionID]=nil
 	counters[missionID]=nil
 	dbcache.seen[missionID]=nil
 	parties[missionID]=nil
-	collectgarbage("step")
+	--collectgarbage("step")


 end
@@ -1395,13 +1523,33 @@ function addon:EventGARRISON_MISSION_NPC_OPENED(event,...)
 --@debug@
 	xprint(event,...)
 --@end-debug@
-	GCF:Show()
+	if (GCF) then GCF:Show() end
 end
 function addon:EventGARRISON_MISSION_NPC_CLOSED(event,...)
 --@debug@
 	xprint(event,...)
 --@end-debug@
-	GCF:Hide()
+	if (GCF) then
+		self:RemoveMenu()
+		GCF:Hide()
+	end
+end
+function addon:EventGARRISON_MISSION_LIST_UPDATE(event)
+	local n=0
+	for _,k in pairs(event) do n=n+1 end
+	xprint("GARRISON_MISSION_LIST_UPDATE",n,date("%d/%m/%y %H:%M:%S"))
+	local t=new()
+	G.GetAvailableMissions(t)
+	local justseen={}
+	local now=time()
+	for i=1,#t do
+		justseen[t[i].missionID]=true
+	end
+	for missionID,_ in pairs(justseen) do
+		if (not tonumber(db.seen[missionID])) then db.seen[missionID]=now end
+	end
+	self:BuildMissionsCache(false,false,true)
+	del(t)
 end
 ---
 --@param #string event GARRISON_MISSION_STARTED
@@ -1429,6 +1577,12 @@ function addon:EventGARRISON_MISSION_STARTED(event,missionID,...)
 			dbcache.runningIndex[m]=missionID
 		end
 	end
+	local v=dbcache.seen[missionID]
+	local span=time()-tonumber(v) or time()
+	if (span > db.lifespan[missionID]) then
+		db.lifespan[missionID]=span
+		-- IF we started it.. it was alive, so it's expire time is at least the time we waited before starting it
+	end
 	dbcache.seen[missionID]=nil
 	counters[missionID]=nil
 	parties[missionID]=nil
@@ -1446,9 +1600,20 @@ end
 function addon:EventGARRISON_MISSION_FINISHED(event,missionID,...)
 --@debug@
 	xprint(event,missionID,...)
-	DevTools_Dump(G.GetPartyMissionInfo(missionID))
+	xdump(G.GetPartyMissionInfo(missionID))
 --@end-debug@
 end
+function addon:EventGARRISON_FOLLOWER_LIST_UPDATE(event)
+--We need to update all followers, maybe this could be done in an onupdate handler
+end
+function addon:EventGARRISON_FOLLOWER_ADDED(event)
+	wipe(followersCache)
+	wipe(followersCacheIndex)
+end
+function addon:EventGARRISON_FOLLOWER_REMOVED(event)
+	wipe(followersCache)
+	wipe(followersCacheIndex)
+end

 function addon:EventGARRISON_MISSION_BONUS_ROLL_COMPLETE(event,missionID,completed,success)
 --@debug@
@@ -1499,9 +1664,45 @@ local coroutines={

 local lastmin=0
 local MPShown=nil
+local dbgFrame
+local lastCPU=0
+local startTime=GetTime()
 -- Keeping it as a nice example of coroutine management.. but not using it anymore
 function addon:Clock()
-	collectgarbage("step")
+	if (GMFMissions.showInProgress)	 then
+		collectgarbage("collect") --while I fix it....
+	else
+		collectgarbage("step",100)
+	end
+--@debug@
+	if (not dbgFrame) then
+		dbgFrame=AceGUI:Create("Window")
+		dbgFrame:SetTitle("GC Performance")
+		dbgFrame:SetPoint("LEFT")
+		dbgFrame:SetHeight(60)
+		dbgFrame:SetWidth(350)
+		dbgFrame:SetLayout("fill")
+		dbgFrame.Text=AceGUI:Create("Label")
+		dbgFrame.Text:SetColor(1,0,0)
+		dbgFrame:AddChild(dbgFrame.Text)
+	end
+	local h,m=GetGameTime()
+	if (m~=lastmin) then
+		lastmin=m
+	end
+	if (trc) then
+		UpdateAddOnCPUUsage()
+		UpdateAddOnMemoryUsage()
+	end
+	local cpu=GetAddOnCPUUsage("GarrisonCommander")
+	dbgFrame.Text:SetText(format("GC Cpu %3.2f/%2.2f/%2.2f Mem %4.3fMB ",
+		cpu,
+		cpu-lastCPU,cpu/(GetTime()-startTime),
+		GetAddOnMemoryUsage("GarrisonCommander")/1024)
+	)
+	lastCPU=cpu
+--@end-debug@
+	dbcache.lastseen=time()
 	if (not MP or MPGoodGuy) then return  end
 	MPShown=not self:GetBoolean("CKMP")
 	local children={GMFMissions:GetChildren()}
@@ -1538,32 +1739,19 @@ function addon:Clock()
 		end
 	end
 --@end-debug@
---@debug@
-	local h,m=GetGameTime()
-	if (m~=lastmin) then
-		lastmin=m
-		UpdateAddOnCPUUsage()
-		UpdateAddOnMemoryUsage()
-		xprint("GC Usage",GetAddOnCPUUsage("GarrisonCommander"),GetAddOnMemoryUsage("GarrisonCommander"))
-	end
---@end-debug@
 end
 function addon:ActivateButton(button,OnClick,Tooltiptext,persistent)
 	button:SetScript("OnClick",function(...) self[OnClick](self,...) end )
 	if (Tooltiptext) then
 		button.tooltip=Tooltiptext
-		button:SetScript("OnEnter",function(...) self:ShowTT(...) end )
+		button:SetScript("OnEnter",ShowTT)
 		button:SetScript("OnLeave",function() GameTooltip:FadeOut() end)
 	else
 		button:SetScript("OnEnter",nil)
 		button:SetScript("OnLeave",nil)
 	end
 end
-function addon:ShowTT(this)
-	GameTooltip:SetOwner(this, "ANCHOR_CURSOR_RIGHT")
-	GameTooltip:SetText(this.tooltip)
-	GameTooltip:Show()
-end
+
 function addon:Shrink(button)
 	local f=button.Toggle
 	local name=f:GetName() or "Unnamed"
@@ -1574,11 +1762,29 @@ function addon:Shrink(button)
 		f:SetHeight(f.savedHeight)
 	end
 end
+
+function addon:ShowMissionControl()
+	if (not GMC:IsShown()) then
+		GarrisonMissionFrame_SelectTab(999)
+		GMF.FollowerTab:Hide()
+		GMF.FollowerList:Hide()
+		GMF.MissionTab:Hide()
+		GMF.TitleText:SetText("Garrison Commander Mission Control")
+		GMC:Show()
+		GMC.startButton:Click()
+		GMC.tabMC:SetChecked(true)
+	else
+		GMC:Hide()
+		GMC.tabMC:SetChecked(false)
+		GarrisonMissionFrame_SelectTab(1)
+	end
+end
 local helpwindow -- pseudo static
 function addon:ShowHelpWindow(button)
 	if (not helpwindow) then
 		local backdrop = {
-				bgFile="Interface\\TutorialFrame\\TutorialFrameBackground",
+				--bgFile="Interface\\TutorialFrame\\TutorialFrameBackground",
+				bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
 				edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
 				tile=true,
 				tileSize=16,
@@ -1594,6 +1800,7 @@ function addon:ShowHelpWindow(button)
 			insets={bottom=5,left=5,right=5,top=5}
 		}
 		helpwindow=CreateFrame("Frame",nil,GCF)
+		helpwindow:EnableMouse(true)
 		helpwindow:SetBackdrop(backdrop)
 		helpwindow:SetBackdropColor(1,1,1,1)
 		helpwindow:SetFrameStrata("TOOLTIP")
@@ -1611,50 +1818,61 @@ function addon:ShowHelpWindow(button)
 		local text=[[<html><body>
 <h1 align="center">Garrison Commander Help</h1>
 <br/>
-<p>  GC enhances standard Garrison UI by adding a Menu header and  a secondary list of mission button to the right of the standard list.<br/>
+<p align="center">GC enhances standard Garrison UI by adding a Menu header and useful information in mission button and tooltip.
 Since 2.0.2, the "big screen" mode became optional. If you choosed to disable it, some feature described here will not be available
 </p>
 <br/>
-<h2>  Secondary button list:</h2>
+<h2>  Button list:</h2>
 <p>
-	* Time since the first time we saw this mission in log<br/>
-	* Success percent with the current followers selection guidelines<br/>
-	* A "Good" party composition, on each member countered mechanics are shown.<br/>
-	*** Green border means full counter, Orange border low level counter<br/>
+* Success percent with the current followers selection guidelines<br/>
+* Time since the first time we saw this mission in log<br/>
+* A "Good" party composition. on each member countered mechanics are shown.<br/>
+*** Green border means full counter, Orange border low level counter<br/>
 </p>
 <h2>Tooltip:</h2>
 <p>
- * Overall mission status<br/>
- * All members which can possibly play a role in the mission<br/>
+* Overall mission status<br/>
+* All members which can possibly play a role in the mission<br/>
 </p>
-<h2>Standard button enhancement:</h2>
+<h2>Button enhancement:</h2>
 <p>
- * In rewards, actual quantity is shown (xp, money and resources) ot iLevel (item rewards)<br/>
- * Countered status<br/>
+* In rewards, actual quantity is shown (xp, money and resources) ot iLevel (item rewards)<br/>
+* Countered status<br/>
 </p>
 <h2>Menu Header:</h2>
 <p>
- * Quick selection of which follower ignore for match making<br/>
- * Quick mission list order selection<br/>
+* Quick selection of which follower ignore for match making<br/>
+* Quick mission list order selection<br/>
+</p>
+<h2>Mission Control:</h2>
+<p>Thanks to Motig which donated the code, we have an auto lancher for mission<br/>
+You specify some criteria mission should satisfy (success chance, rewards type etc) and matching missions will be autosubmitted<br/>
+BE WARNED, FEATURE IS |cffff0000EXPERIMENTAL|r
 </p>
 ]]
 if (MP) then
 text=text..[[
-<h3>Clashing Master Plan Detected</h3>
-<p>You cold experience issues. Please update MP to the last revision or downgrade it to 0.18 for a smoother experience
+<p><br/></p>
+<h3>Master Plan 0.20 or above detected</h3>
+<p>Master Plan hides Garrison Commander interface for available missions<br/>
+You can still use Garrison Commander Mission Control<br/>
+You can switch between MP and GC interface for missions checking and unchecking "Use GC Interface" checkbox. It usually works :)
 </p>
 ]]
 end
 if (MPGoodGuy) then
 text=text..[[
-<h3>Master Plan 0.18 or 0.23 or above Detected</h3>
-<p>This version of Master Plan plays not so bad with GC<br/>
-You can use the "Use GC interface" switch to regain GC interface with MP 0.23 or above.<br/>
+<p><br/></p>
+<h3>Master Plan 0.18 Detected</h3>
+<p>This the last known version of Master Plan which leaves Blizzard UI available to other addons<br/>
+You loose Garrison Commander Active Mission page, but the one provided by MP is good enough.<br/>
+In order to see enhanced tooltips you need to hover on extra button.
 </p>
 ]]
 end
 if (GMM) then
 text=text..[[
+<p><br/></p>
 <h3>Garrison Mission Manager Detected</h3>
 <p>Garrison Mission Manager and Garrison Commander plays reasonably well together.<br/>
 The red button to the right of rewards is from GMM. It spills out of button, Yes, it's designed this way. Dunno why. Ask GMM author :)<br/>
@@ -1666,12 +1884,13 @@ text=text.."</body></html>"
 		--html:SetTextColor('h1',C.Red())
 		--html:SetTextColor('h2',C.Orange())
 		helpwindow:SetWidth(800)
-		helpwindow:SetHeight(600+ (MP and 80 or 0) + (GMM and 70 or 0))
-		helpwindow:SetPoint("TOPLEFT",button,"TOPRIGHT",0,0)
+		helpwindow:SetHeight(590 + ((MP or MPGoodGuy) and 160 or 0) + (GMM and 120 or 0))
+		helpwindow:SetPoint("TOPRIGHT",button,"TOPLEFT",0,0)
 		html:ClearAllPoints()
 		html:SetWidth(helpwindow:GetWidth()-20)
 		html:SetHeight(helpwindow:GetHeight()-20)
 		html:SetPoint("TOPLEFT",helpwindow,"TOPLEFT",10,-10)
+		html:SetPoint("BOTTOMRIGHT",helpwindow,"BOTTOMRIGHT",-10,10)
 		html:SetText(text)
 		helpwindow:Show()
 		return
@@ -1687,42 +1906,242 @@ function addon:Toggle(button)
 	end
 end
 -- Unused, experimenting with acegui
-local function GFC_Constructor()
-	local widget=setmetatable({},{__index=AceGUI:Create("SimpleGroup")})
-	function widget:DrawOn(frame,l,r)
-		self.frame:ClearAllPoints()
-		self.frame:SetPoint("TOPLEFT",frame,"TOPLEFT",l,0)
-		self.frame:SetPoint("BOTTOMRIGHT",frame,"TOPRIGHT",r,0)
-	end
-	function widget:OnRelease()
-		self.frame:ClearAllPoints()
-	end
-	if (false) then
-		AceGUI:RegisterWidgetType("GarrisonCommanderHeader",GFC_Constructor,1)
-		local layer=AceGUI:Create("GarrisonCommanderHeader")
-		layer:DrawOn(GCF)
-		layer:SetLayout("flow")
-		LibStub("AceConfigDialog-3.0"):Open(me,layer)
+function addon:GenerateMissionsWidgets()
+	self:GenerateMissionContainer()
+	self:GenerateMissionButton()
+end
+function addon:GenerateMissionContainer()
+	do
+		local Type="GMCLayer"
+		local Version=1
+		local function OnRelease(self)
+			wipe(self.childs)
+		end
+		local function OnAcquire(self)
+			self.frame:SetParent(UIParent)
+			self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+			self.frame:SetHeight(50)
+			self.frame:SetWidth(100)
+			self.frame:Show()
+			self.frame:SetPoint("LEFT")
+		end
+		local function Show(self)
+			self.frame:Show()
+		end
+		local function Hide(self)
+			self.frame:Hide()
+			self:Release()
+		end
+		local function SetScript(self,...)
+			self.frame:SetScript(...)
+		end
+		local function SetParent(self,...)
+			self.frame:SetParent(...)
+		end
+		local function PushChild(self,child,index)
+			self.childs[index]=child
+			self.scroll:AddChild(child)
+		end
+		local function RemoveChild(self,index)
+			local child=self.childs[index]
+			if (child) then
+				self.childs[index]=nil
+				child:Hide()
+				self:DoLayout()
+			end
+		end
+		local function ClearChildren(self)
+			wipe(self.childs)
+			self:AddScroll()
+		end
+		local function AddScroll(self)
+			if (self.scroll) then
+				self:ReleaseChildren()
+				self.scroll=nil
+			end
+			self.scroll=AceGUI:Create("ScrollFrame")
+			local scroll=self.scroll
+			self:AddChild(scroll)
+			scroll:SetLayout("List") -- probably?
+			scroll:SetFullWidth(true)
+			scroll:SetFullHeight(true)
+			scroll:SetPoint("TOPLEFT",self.title,"BOTTOMLEFT",0,0)
+			scroll:SetPoint("TOPRIGHT",self.title,"BOTTOMRIGHT",0,0)
+			scroll:SetPoint("BOTTOM",self.content,"BOTTOM",0,0)
+		end
+		local function Constructor()
+			local frame=CreateFrame("Frame")
+			local title=frame:CreateFontString(nil, "BACKGROUND", "GameFontNormalHugeBlack")
+			title:SetJustifyH("CENTER")
+			title:SetJustifyV("CENTER")
+			title:SetPoint("TOPLEFT")
+			title:SetPoint("TOPRIGHT")
+			title:SetHeight(0)
+			title:SetWidth(0)
+			addBackdrop(frame)
+			local widget={childs={}}
+			widget.title=title
+			widget.type=Type
+			widget.SetTitle=function(self,...) self.title:SetText(...) end
+			widget.SetTitleColor=function(self,...) self.title:SetTextColor(...) end
+			widget.SetFormattedTitle=function(self,...) self.title:SetFormattedText(...) end
+			widget.SetTitleWidth=function(self,...) self.title:SetWidth(...) end
+			widget.SetTitleHeight=function(self,...) self.title:SetHeight(...) end
+			widget.frame=frame
+			frame.obj=widget
+			widget.OnAcquire=OnAcquire
+			widget.OnRelease=OnRelease
+			widget.Show=Show
+			widget.Hide=Hide
+			widget.SetScript=SetScript
+			widget.SetParent=SetParent
+			frame:SetScript("OnHide",function(self) self.obj:Fire('OnClose') end)
+			--Container Support
+			local content = CreateFrame("Frame",nil,frame)
+			widget.content = content
+			content.obj = self
+			content:SetPoint("TOPLEFT",title,"BOTTOMLEFT")
+			content:SetPoint("BOTTOMRIGHT")
+			AceGUI:RegisterAsContainer(widget)
+			widget.PushChild=PushChild
+			widget.RemoveChild=RemoveChild
+			widget.ClearChildren=ClearChildren
+			widget.AddScroll=AddScroll
+			return widget
+		end
+		AceGUI:RegisterWidgetType(Type,Constructor,Version)
 	end
-	return widget
 end

-function addon:CreateOptionsLayer(...)
-	local o=AceGUI:Create("SimpleGroup") -- a transparent frame
-	xprint("Created options ", o)
-	o:SetLayout("Flow")
-	o:SetCallback("OnRelease",function(widget) widget.frame:SetScale(1.0) end)
-	o:SetCallback("OnClose",function(widget) widget.frame:SetScale(1.0) widget:Release() end)
-	for i=1,select('#',...) do
-		self:AddOptionToOptionsLayer(o,select(i,...))
+function addon:GenerateMissionButton()
+	do
+		local Type="GMCMissionButton"
+		local Version=1
+		local unique=0
+		local function OnAcquire(self)
+			local frame=self.frame
+			frame.info=nil
+			frame:SetHeight(80)
+			self.frame:SetAlpha(1)
+			self.frame:Enable()
+		end
+		local function Show(self)
+			self.frame:Show()
+		end
+		local function Hide(self)
+			self.frame:SetHeight(1)
+			self.frame:SetAlpha(0)
+			self.frame:Disable()
+		end
+		local function SetScript(self,...)
+			self.frame:SetScript(...)
+		end
+		local function SetMission(self,mission,missionID)
+			self.frame.info=mission
+			addon:BuildMissionButton(self.frame,true)
+			self.frame:EnableMouse(true)
+			--self.frame:SetScript("OnEnter",GarrisonMissionPageFollowerFrame_OnEnter)
+			--self.frame:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave)
+			self.frame:SetScript("OnEnter",GarrisonMissionButton_OnEnter)
+			self.frame:SetScript("OnLeave",function() GameTooltip:FadeOut() end)
+			local party
+			for i=1,#GMC.ml.Parties do
+				party=GMC.ml.Parties[i]
+				if party.missionID==missionID then
+					break
+				end
+			end
+			self.frame.Percent:SetFormattedText("%d%%",party.perc)
+			self.frame.Percent:SetTextColor(addon:GetDifficultyColors(party.perc))
+			local x=1
+			for i=1,#party.members do
+				x=i+1
+				addon:RenderFollowerButton(self.frame.members[i],party.members[i],missionID)
+				self.frame.members[i]:SetScript("OnEnter",GarrisonMissionPageFollowerFrame_OnEnter)
+				self.frame.members[i]:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave)
+				self.frame.members[i]:Show()
+			end
+			for i=x,3 do
+				self.frame.members[i]:SetScript("OnEnter",nil)
+				self.frame.members[i]:Hide()
+			end
+		end
+
+		local function Constructor()
+			unique=unique+1
+			local frame=CreateFrame("Button","Pippo"..unique,nil,"GarrisonMissionListButtonTemplate") --"GarrisonCommanderMissionListButtonTemplate")
+			local indicators=CreateFrame("Frame",nil,frame,"GarrisonCommanderIndicators")
+			frame.Title:SetFontObject("QuestFont_Shadow_Small")
+			frame.Summary:SetFontObject("QuestFont_Shadow_Small")
+			indicators:SetPoint("LEFT",65,0)
+			indicators.Age:Hide()
+			frame.Percent=indicators.Percent
+			frame:SetScript("OnEnter",nil)
+			frame:SetScript("OnLeave",nil)
+			frame:SetScript("OnClick",function(self,button) self.obj:Fire("OnClick",self,button) end)
+			frame.LocBG:SetPoint("LEFT")
+			frame.MissionType:SetPoint("TOPLEFT",5,-2)
+			frame.members={}
+			for i=1,3 do
+				local f=CreateFrame("Button",nil,frame,"GarrisonCommanderMissionPageFollowerTemplateSmall" )
+				frame.members[i]=f
+				f:SetPoint("BOTTOMRIGHT",-65 -65 *i,5)
+				f:SetScale(0.8)
+			end
+			local widget={}
+			setmetatable(widget,{__index=frame})
+			widget.type=Type
+			widget.frame=frame
+			frame.obj=widget
+			widget.OnAcquire=OnAcquire
+			widget.Show=Show
+			widget.Hide=Hide
+			widget.SetScript=SetScript
+			widget.SetMission=SetMission
+			return AceGUI:RegisterAsWidget(widget)
+
+		end
+		AceGUI:RegisterWidgetType(Type,Constructor,Version)
 	end
-	_G.TEST=o
-	local frame=setmetatable({},{__index=o})
-	function frame:Show() self.frame:Show() end
-	return frame
 end
-function addon:AddOptionToOptionsLayer(o,flag)
-	if (not flag) then return end
+function addon:GMCBuildMiniMissionButton(frame,i,mission,scale,perc,offset)
+	offset=offset or 20
+	scale=scale or 0.6
+	local panel=frame.Missions[i]
+	if (not panel) then
+		panel=CreateFrame("Button",nil,frame,"GarrisonCommanderMissionListButtonTemplate")
+		panel:SetPoint("TOPLEFT",frame,1,-((i-1)*panel:GetHeight() +offset))
+		panel:SetPoint("TOPRIGHT",frame,-1,-((i-1)*panel:GetHeight()-offset))
+		panel.orderId=i
+		tinsert(frame.Missions,panel)
+		--Creo una riga nuova
+		panel:SetScale(scale)
+		panel.LocBG:SetPoint("LEFT")
+	end
+	panel.info=mission
+	--panel.id=index[missionID]
+	self:BuildMissionButton(panel)
+	local q=self:GetDifficultyColor(perc)
+	panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc)
+	panel.Percent:SetTextColor(q.r,q.g,q.b)
+	panel.NumMembers:SetFormattedText(GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS,mission.numFollowers)
+	panel:Show()
+	return panel
+end
+
+function addon:CreateOptionsLayer(...)
+	local o=AceGUI:Create("SimpleGroup") -- a transparent frame
+	o:SetLayout("Flow")
+	o:SetCallback("OnClose",function(widget) widget:Release() end)
+	local totsize=0
+	for i=1,select('#',...) do
+		totsize=totsize+self:AddOptionToOptionsLayer(o,select(i,...))
+	end
+	return o,totsize
+end
+function addon:AddOptionToOptionsLayer(o,flag,maxsize)
+	maxsize=tonumber(maxsize) or 140
+	if (not flag) then return 0 end
 	local info=self:GetVarInfo(flag)
 	if (info) then
 		local data={option=info}
@@ -1733,13 +2152,25 @@ function addon:AddOptionToOptionsLayer(o,flag)
 			widget:SetValue(value)
 			local color=value and "Green" or "Silver"
 			widget:SetLabel(C(info.name,color))
-			widget:SetWidth(max(widget.text:GetStringWidth(),120))
+			widget:SetWidth(max(widget.text:GetStringWidth(),maxsize))
 		elseif(info.type=="select") then
 			widget=AceGUI:Create("Dropdown")
 			widget:SetValue(self:GetVar(flag))
 			widget:SetLabel(info.name)
 			widget:SetText(info.values[self:GetVar(flag)])
 			widget:SetList(info.values)
+			widget:SetWidth(maxsize)
+		elseif (info.type=="execute") then
+			widget=AceGUI:Create("Button")
+			widget:SetText(info.name)
+			widget:SetWidth(maxsize)
+			widget:SetCallback("OnClick",function(widget,event,value)
+				self[info.func](self,data,value)
+			end)
+		else
+			widget=AceGUI:Create("Label")
+			widget:SetText(info.name)
+			widget:SetWidth(maxsize)
 		end
 		widget:SetCallback("OnValueChanged",function(widget,event,value)
 			if (type(value=='boolean')) then
@@ -1758,22 +2189,92 @@ function addon:AddOptionToOptionsLayer(o,flag)
 		end)
 		o:AddChildren(widget)
 	end
+	return maxsize
 end
+
 function addon:Options()
 	-- Main Garrison Commander Header
-	local base=CreateFrame("Frame","GCF",UIParent,"GarrisonCommanderTitle")
-	GCF=base
+	GCF=CreateFrame("Frame","GCF",UIParent,"GarrisonCommanderTitle")
+--@alpha@
+	local fs=GCF:CreateFontString(nil, "BACKGROUND", "WorldMapTextFont")
+	fs:SetAllPoints()
+	fs:SetJustifyH("CENTER")
+	fs:SetJustifyV("CENTER")
+	fs:SetText("A l p h a   V e r s i o n")
+	fs:SetTextColor(C.Silver())
+	fs:SetAlpha(0.6)
+--@end-alpha@
+	-- Removing wood corner. I do it here to not derive an xml frame. This shoud play better with ui extensions
+	GCF.CloseButton:Hide()
+	for _,f in pairs({GCF:GetRegions()}) do
+		if (f:GetObjectType()=="Texture" and f:GetAtlas()=="Garr_WoodFrameCorner") then f:Hide() end
+	end
+	GCF:SetFrameStrata(GMF:GetFrameStrata())
+	GCF:SetFrameLevel(GMF:GetFrameLevel()-2)
+	if (not bigscreen) then GCF:SetHeight(GCF:GetHeight()+35) end
+	baseHeight=GCF:GetHeight()
+	minHeight=47
+	GCF.CloseButton:SetScript("OnClick",nil)
+	GCF.Pin:SetAllPoints(GCF.CloseButton)
 	GCF:SetWidth(BIGSIZEW)
 	GCF:SetPoint("TOP",UIParent,0,-60)
-	base:SetHeight(40)
-	base:EnableMouse(true)
+	if (self:GetBoolean("PIN")) then
+		GCF.Pin:SetChecked(true)
+	else
+		GCF.Pin:SetChecked(false)
+	end
+
+	do
+		local baseHeight=baseHeight
+		local minHeight=minHeight
+		local baseStrata=GCF:GetFrameStrata()
+		local baseLevel=GCF:GetFrameStrata()
+		local speed=3
+		local function shrink(this)
+			addon:RemoveMenu()
+			this:SetScript("OnUpdate",function(me,ts)
+				local h=me:GetHeight()
+				if (h<=45) then
+					me:SetHeight(45)
+					me:SetScript("OnUpdate",nil)
+					GCF.tooltip=L["You can open the menu clicking on the icon in top right corner"]
+				else
+					me:SetHeight(h-2)
+				end
+			end)
+		end
+		local function grow(this)
+			this:SetScript("OnUpdate",function(me,ts)
+				local h=me:GetHeight()
+				if (h>=baseHeight) then
+					me:SetScript("OnUpdate",nil)
+					me:SetHeight(baseHeight)
+					if (not me.Menu) then addon:AddMenu() end
+					GCF.tooltip=nil
+					me.Menu:DoLayout()
+				else
+					me:SetHeight(h+2)
+				end
+			end)
+		end
+		GCF.Pin.tooltip=L["Toggles Garrison Commander Menu AutoHide on/off"]
+		GCF.Pin:SetScript("OnEnter",ShowTT)
+		GCF.Pin:SetScript("OnClick",function(this)
+			local value=this:GetChecked()
+			this:SetChecked(value)
+			addon:SetBoolean("PIN",value)
+			if (value) then grow(GCF) else shrink(GCF) end
+		end)
+	end
+	GCF:EnableMouse(true)
 	GCF:SetMovable(true)
 	GCF:RegisterForDrag("LeftButton")
 	GCF:SetScript("OnDragStart",function(frame)if (self:GetBoolean("MOVEPANEL")) then frame:StartMoving() end end)
 	GCF:SetScript("OnDragStop",function(frame) frame:StopMovingOrSizing() end)
-	self:ActivateButton(GCF.help,"ShowHelpWindow",L["Click to toggle Help page"])
 	if (bigscreen) then
 		--MinimizeButton
+		-- It's not working well, now I dont have time to fix it
+		if (false) then
 		local h=CreateFrame("Button",nil,base,"UIPanelCloseButton")
 		h:SetFrameLevel(999)
 		h:SetNormalTexture("Interface\\BUTTONS\\UI-Panel-CollapseButton-Up")
@@ -1784,6 +2285,7 @@ function addon:Options()
 		h:SetPoint("TOPRIGHT")
 		self:ActivateButton(h,"Shrink",L["Click to toggle Garrison Mission Frame"])
 		GCF.gcHIDE=h
+		end
 		-- Mission list on follower panels
 		local ml=CreateFrame("Frame","GCFMissions",GMFFollowers,"GarrisonCommanderFollowerMissionList")
 		ml:SetPoint("TOPLEFT",GMFFollowers,"TOPRIGHT")
@@ -1808,10 +2310,10 @@ function addon:ScriptTrace(hook,frame,...)
 --@end-debug@
 end
 function addon:IsProgressMissionPage()
-	return GMF:IsShown() and GMFMissions:IsShown() and GMFMissions.showInProgress and not GMFFollowers:IsShown() and not GMF.MissionComplete:IsShown()
+	return GMF:IsShown() and GMF.MissionTab and GMF.MissionTab.MissionList.showInProgress
 end
 function addon:IsAvailableMissionPage()
-	return GMF:IsShown() and GMFMissions:IsShown() and not GMFMissions.showInProgress  and not GMFFollowers:IsShown() and not GMF.MissionComplete:IsShown()
+	return GMF:IsShown() and GMF.MissionTab:IsShown() and not GMF.MissionTab.MissionList.showInProgress
 end
 function addon:IsFollowerList()
 	return GMF:IsShown() and GMFFollowers:IsShown()
@@ -1824,6 +2326,25 @@ end
 function addon:IsMissionPage()
 	return GMF:IsShown() and GMFMissionPage:IsShown() and GMFFollowers:IsShown()
 end
+---
+-- Switches between missions (1) and followers (others) panels
+function addon:HookedGarrisonMissionFrame_SelectTab(id)
+	GMC:Hide()
+	GMC.tabMC:SetChecked(false)
+	wipe(GMCUsedFollowers)
+end
+---
+-- Switchs between active and availabla missions depending on tab object
+do
+	local original=GarrisonMissionList_SetTab
+		function GarrisonMissionList_SetTab(...)
+		-- I dont actually care wich page we are shoing, I know I must redraw missions
+		original(...)
+		for i=1,#GMFMissionListButtons do
+			GMFMissionListButtons.lastMissionID=nil
+		end
+	end
+end
 function addon:HookedGarrisonMissionFrame_HideCompleteMissions()
 	self:BuildMissionsCache(true,true)
 end
@@ -1861,19 +2382,63 @@ function addon:HookedGarrisonFollowerTooltipTemplate_SetGarrisonFollower(...)
 		ft:Show()
 	end
 end
+function addon:HookedGarrisonFollowerButton_UpdateCounters(frame,follower,showCounters)
+	if MP then self:Unhook("GarrisonFollowerButton_UpdateCounters") return end
+	if not frame.GCTime then
+		frame.GCTime=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
+		frame.GCTime:SetPoint("TOPLEFT",frame.Status,"TOPRIGHT",5,0)
+		frame.GCXp=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
+		frame.GCXp:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,2)
+		frame.GCIt=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
+		frame.GCIt:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,-2)
+	end
+	if not frame.isCollected then
+		frame.GCTime:Hide()
+		frame.GCXp:Hide()
+		frame.GCIt:Hide()
+		return
+	end
+	if (frame.Status:GetText() == GARRISON_FOLLOWER_ON_MISSION) then
+		frame.GCTime:SetText(self:GetFollowerStatus(follower.followerID,true,true))
+		frame.GCTime:Show()
+	else
+		frame.GCTime:Hide()
+	end
+	local follower=self:GetFollowerData(follower.followerID)
+	if (follower.level >= GARRISON_FOLLOWER_MAX_LEVEL ) then
+		local c1=ITEM_QUALITY_COLORS[follower.weaponQuality or 1]
+		local c2=ITEM_QUALITY_COLORS[follower.armorQuality or 1]
+		frame.GCIt:SetFormattedText("W:%s%3d|r A:%s%3d|r",c1.hex,follower.weaponItemLevel,c2.hex,follower.armorItemLevel)
+		frame.GCIt:Show()
+	else
+		frame.GCIt:Hide()
+	end
+	if (follower.level >= GARRISON_FOLLOWER_MAX_LEVEL and follower.quality >= GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY) then
+		frame.GCXp:Hide()
+	else
+		frame.GCXp:SetFormattedText("Xp to next upgrade: %d",follower.levelXP-follower.xp)
+		frame.GCXp:Show()
+	end
+
+end
 function addon:HookedGarrisonFollowerListButton_OnClick(frame,button)
 --@debug@
-	trace("Click",button,GarrisonMissionFrame.FollowerTab.Model:IsShown())
+	trace("Click",frame:GetName(),button,GMF.FollowerTab.Model:IsShown())
 --@end-debug@
-	if (button=="LeftButton" and GarrisonMissionFrame.FollowerTab.FollowerID ~= frame.info.followerID) then
+	if (button=="LeftButton" and GMF.FollowerTab.FollowerID ~= frame.info.followerID) then
 		if (frame.info.isCollected) then
 			self:HookedGarrisonFollowerPage_ShowFollower(frame.info,frame.info.followerID)
 		end
 	end
 end
 -- Shamelessly stolen from Blizzard Code
-function addon:FillMissionButton(button)
+function addon:BuildMissionButton(button,gmc,...)
 	local mission=button.info
+	if (not mission or not mission.name) then
+		if (button.missionID) then
+			mission=self:GetMissionData(button.missionID)
+		end
+	end
 	if (not mission) then return end
 	button.Title:SetWidth(0);
 	button.Title:SetText(mission.name);
@@ -1895,6 +2460,7 @@ function addon:FillMissionButton(button)
 		button.Summary:ClearAllPoints();
 		button.Summary:SetPoint("TOPLEFT", button.Title, "BOTTOMLEFT", 0, -4);
 	end
+	if gmc then button.Title:SetPoint("LEFT",70,25) end
 	if ( mission.locPrefix ) then
 		button.LocBG:Show();
 		button.LocBG:SetAtlas(mission.locPrefix.."-List");
@@ -1932,7 +2498,7 @@ function addon:FillMissionButton(button)
 		button.Overlay:Hide();
 	end
 	button.MissionType:SetAtlas(mission.typeAtlas);
-	self.ClonedGarrisonMissionButton_SetRewards(button, mission.rewards, mission.numRewards);
+	GarrisonMissionButton_SetRewards(button,mission.rewards, mission.numRewards);
 	button:Show();

 end
@@ -1981,7 +2547,22 @@ function addon:ClonedGarrisonMissionButton_SetRewards(rewards, numRewards)
 		self.Rewards[i]:Hide();
 	end
 end
-
+function addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,this,...)
+	local tip=GameTooltip
+	tip:SetOwner(this, "ANCHOR_CURSOR_RIGHT");
+	tip:AddLine(this.info.name,C.White())
+	--tip:AddTexture(this.Icon:GetTexture())
+	tip:AddLine(this.info.description,C.Orange())
+	local t=new()
+	self:GetAllCounters(missionID,this.Icon:GetTexture(),t)
+	if( #t > 0) then
+		tip:AddLine(GARRISON_MISSION_COUNTER_FROM)
+		for i=1,#t do
+			tip:AddLine(self:GetFollowerData(t[i],'fullname'),C[self:GetBiasColor(t[i],missionID,C.White())]())
+		end
+	end
+	tip:Show()
+end
 local Busystatusmessage
 function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 	local i=0
@@ -1989,7 +2570,7 @@ function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 	if (not GCFMissions.Missions) then GCFMissions.Missions={} end
 	if (not Busystatusmessage) then Busystatusmessage=C(BUSY_MESSAGE,"Red)") end
 	-- frame has every info you can need on a follower, but here I dont really need them, maybe just counters
-	--DevTools_Dump(table.Counters)
+	--xdump(table.Counters)
 	local followerName=self:GetFollowerData(followerID,'name')
 	repeat -- a poor man goto
 		if (type(frame.followerID)=="number") then
@@ -2035,7 +2616,7 @@ function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 			end
 			table.sort(partyIndex,function(a,b) return parties[a].perc > parties[b].perc end)
 		end
-		self:FillFollowerButton(GCFMissions.Header,followerID)
+		self:RenderFollowerButton(GCFMissions.Header,followerID)
 		-- Scanning mission list
 		for z = 1,#partyIndex do
 			local missionID=partyIndex[z]
@@ -2066,6 +2647,8 @@ function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 				local panel=GCFMissions.Missions[i]
 				if (not panel) then
 					panel=CreateFrame("Button",nil,GCFMissions,"GarrisonCommanderMissionListButtonTemplate")
+					self:SafeHookScript(panel,"OnClick","OnClick_GarrisonMissionButton",true)
+
 					if (i==1) then
 						panel:SetPoint("TOPLEFT",GCFMissions.Header,"BOTTOMLEFT")
 					else
@@ -2079,8 +2662,8 @@ function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 					panel.LocBG:SetPoint("LEFT")
 				end
 				panel.info=mission
-				panel.id=index[missionID]
-				self:FillMissionButton(panel)
+				--panel.id=index[missionID]
+				self:BuildMissionButton(panel)
 				local q=self:GetDifficultyColor(perc)
 				panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc)
 				panel.Percent:SetTextColor(q.r,q.g,q.b)
@@ -2110,7 +2693,64 @@ function addon:SetUp(...)
 	self:CheckMP()
 	self:CheckGMM()
 	self:Options()
+	self:GenerateMissionsWidgets()
+	self:GMCBuildPanel()
+	local tabMC=CreateFrame("CheckButton",nil,GMF,"SpellBookSkillLineTabTemplate")
+	tabMC.tooltip="Open Garrison Commander Mission Control"
+	--tab:SetNormalTexture("World\\Dungeon\\Challenge\\clockRunes.blp")
+	--tab:SetNormalTexture("Interface\\Timer\\Challenges-Logo.blp")
+	tabMC:SetNormalTexture("Interface\\ICONS\\ACHIEVEMENT_GUILDPERK_WORKINGOVERTIME.blp")
+	self:MarkAsNew(tabMC,'MissionControl','New in 2.2.0! Try automatic mission management!')
+	tabMC:Show()
+	GMC.tabMC=tabMC
+	local tabCF=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate")
+	tabCF.tooltip="Open Garrison Commander Configuration Screen"
+	tabCF:SetNormalTexture("Interface\\ICONS\\Trade_Engineering.blp")
+	tabCF:SetPushedTexture("Interface\\ICONS\\Trade_Engineering.blp")
+	tabCF:Show()
+	local tabHP=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate")
+	tabHP.tooltip="Open Garrison Commander Help"
+	tabHP:SetNormalTexture("Interface\\ICONS\\INV_Misc_QuestionMark.blp")
+	tabHP:SetPushedTexture("Interface\\ICONS\\INV_Misc_QuestionMark.blp")
+	tabHP:Show()
+	tabMC:SetScript("OnClick",function(this,...) addon:ShowMissionControl() end)
+	tabCF:SetScript("OnClick",function(this,...) addon:Gui() end)
+	tabHP:SetScript("OnClick",function(this,button) addon:ShowHelpWindow(this,button) end)
+	tabHP:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-10)
+	tabCF:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-60)
+	tabMC:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-110)
 	self:StartUp()
+	--collectgarbage("step",10)
+--/Interface/FriendsFrame/UI-Toast-FriendOnlineIcon
+end
+function addon:AddMenu()
+	local menu,size=self:CreateOptionsLayer(MP and 'CKMP' or nil,'BIGSCREEN','MOVEPANEL','IGM','IGP','NOFILL','MSORT')
+	--self:AddOptionToOptionsLayer(GCF.Menu,'MSORT')
+	--self:AddOptionToOptionsLayer(GCF.Menu,'ShowMissionControl')
+--@debug@
+	self:AddOptionToOptionsLayer(menu,'DBG')
+	self:AddOptionToOptionsLayer(menu,'TRC')
+--@end-debug@
+	local frame=menu.frame
+	frame:Show()
+	menu:ClearAllPoints()
+	menu:SetPoint("TOPLEFT",GCF,"TOPLEFT",25,-18)
+	menu:SetWidth(GCF:GetWidth()-50)
+	menu:SetHeight(GCF:GetHeight()-50)
+	menu:DoLayout()
+	GCF.Menu=menu
+end
+function addon:RemoveMenu()
+	if (GCF.Menu) then
+		pcall(GCF.Menu.Release,GCF.Menu)
+		GCF.Menu=nil
+	end
+end
+function addon:AddMissionId(b)
+	if (b.info and b.info.missionID) then
+		GameTooltip:AddDoubleLine("MissionID",b.info.missionID)
+		GameTooltip:Show()
+	end
 end
 ---
 -- Additional setup
@@ -2120,23 +2760,15 @@ function addon:StartUp(...)
 --@debug@
 	xprint("Startup")
 --@end-debug@
+	self:GrowPanel()
 	self:Unhook(GMF,"OnShow")
-	self:Trigger("CKMP")
-	self:PermanentEvents()
-	GCF.Menu=self:CreateOptionsLayer(MPSwitch and 'CKMP' or nil,'BIGSCREEN','MOVEPANEL','IGM','IGP','NOFILL','MSORT')
-	GCF.Menu:SetParent(GCF)
-	GCF.Menu.frame:SetScale(0.6)
-	if (bigscreen) then
-		GCF.Menu:SetPoint("TOPLEFT",GCF.Signature,"TOPRIGHT",10,10)
+	if (self:GetBoolean("PIN")) then
+		GCF:SetHeight(baseHeight)
+		self:AddMenu()
 	else
-		GCF:SetHeight(60)
-		GCF.Menu:SetPoint("TOPLEFT",GCF,"TOPLEFT",0,-24)
+		GCF:SetHeight(minHeight)
 	end
-	GCF.Menu:SetPoint("BOTTOMRIGHT",GCF,"BOTTOMRIGHT",-16,0)
-	GCF.Menu:Show()
-	self:GrowPanel()
-	self:SafeSecureHook("GarrisonMissionButton_OnClick","OnClick_GarrisonMissionButton")
-	self:SafeSecureHook("GarrisonMissionFrame_CheckCompleteMissions")
+	self:PermanentEvents()
 	self:SafeSecureHook("GarrisonMissionButton_AddThreatsToTooltip")
 	self:SafeSecureHook("GarrisonMissionButton_SetRewards")
 	if (bigscreen) then
@@ -2146,22 +2778,39 @@ function addon:StartUp(...)
 	end
 	self:SafeSecureHook("GarrisonMissionFrame_HideCompleteMissions")	-- Mission reward completed
 	self:SafeSecureHook("GarrisonMissionPage_ShowMission")
-	self:SafeSecureHook("GarrisonMissionList_UpdateMissions")
+	self:SafeSecureHook("GarrisonMissionFrame_SelectTab")
+	-- GarrisonMissionList_SetTab is overrided
+
 	self:SafeHookScript(GMFMissions,"OnShow")--,"GrowPanel")
 	self:SafeHookScript(GMFFollowers,"OnShow")--,"GrowPanel")
 	self:SafeHookScript(GCF,"OnHide","CleanUp",true)
+	-- Follower button enhancement in follower list
+	self:SafeSecureHook("GarrisonFollowerButton_UpdateCounters")
+	-- Mission management
 	self:SafeHookScript(GMF.MissionComplete.NextMissionButton,"OnClick","OnClick_GarrisonMissionFrame_MissionComplete_NextMissionButton",true)
 	-- Hooking mission buttons on click
 	for i=1,#GMFMissionListButtons do
 		local b=GMFMissionListButtons[i]
 		self:SafeHookScript(b,"OnClick","OnClick_GarrisonMissionButton",true)
+--@debug@
+		self:SafeHookScript(b,"OnEnter","AddMissionId",true)
+--@end-debug@
 	end
 	self:ScheduleRepeatingTimer("Clock",1)
 	self:BuildMissionsCache(true,true)
 	self:BuildRunningMissionsCache()
 	self:Trigger("MSORT")
+	self:Trigger("CKMP")
+end
+function addon:MarkAsNew(obj,key,message)
+	if (not db.news[key]) then
+		local f=CreateFrame("Frame",nil,obj,"GarrisonCommanderWhatsNew")
+		f.tooltip=message
+		f:SetPoint("BOTTOMLEFT",obj,"TOPRIGHT")
+		f:Show()
+	end
 end
--- probably not really needed, haven seen yet them firing out of garrison
+-- probably not really needed, havenr seen yet them firing out of garrison
 function addon:PermanentEvents()
 	self:SafeRegisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE")
 	self:SafeRegisterEvent("GARRISON_MISSION_STARTED")
@@ -2170,18 +2819,24 @@ function addon:PermanentEvents()
 	self:SafeRegisterEvent("GARRISON_FOLLOWER_XP_CHANGED")
 	self:SafeRegisterEvent("GARRISON_FOLLOWER_ADDED")
 	self:SafeRegisterEvent("GARRISON_FOLLOWER_REMOVED")
+	self:RegisterBucketEvent("GARRISON_MISSION_LIST_UPDATE",2,"EventGARRISON_MISSION_LIST_UPDATE")
+	self:SafeRegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
 --@debug@
 	self:DebugEvents()
 --@end-debug@
 end
 function addon:DebugEvents()
-	self:SafeRegisterEvent("GARRISON_MISSION_LIST_UPDATE")
-	self:SafeRegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") -- Should be used only when has true as parameter
 	self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT")
 	self:SafeRegisterEvent("GARRISON_MISSION_FINISHED")
 	self:SafeRegisterEvent("GARRISON_UPDATE")
 	self:SafeRegisterEvent("GARRISON_USE_PARTY_GARRISON_CHANGED")
 	self:SafeRegisterEvent("GARRISON_MISSION_NPC_OPENED")
+	self:SafeSecureHook("GarrisonMissionList_UpdateMissions")
+	self:SafeSecureHook("GarrisonMissionFrame_ShowCompleteMissions")
+	self:SafeSecureHook("GarrisonMissionFrame_CheckCompleteMissions")
+	self:SafeSecureHook("MissionCompletePreload_LoadMission")
+
+
 end
 function addon:checkMethod(method,hook)
 	if (type(self[method])=="function") then
@@ -2213,7 +2868,7 @@ function addon:SafeSecureHook(tobehooked,method)
 	else
 		do
 			local hooked=tobehooked
-			return self:SecureHook(tobehooked,function(...) xprint(hooked,...) end)
+			return self:SecureHook(tobehooked,function(...) print(hooked,...) end)
 		end
 --@end-debug@
 	end
@@ -2248,13 +2903,13 @@ end
 function addon:CleanUp()
 	self:UnhookAll()
 	self:CancelAllTimers()
-	GCF.Menu:Release()
+	self:RemoveMenu()
 	self:HookScript(GMF,"OnSHow","StartUp",true)
 	self:PermanentEvents() -- Reattaching permanent events
 	if (GarrisonFollowerTooltip.fs) then
 		GarrisonFollowerTooltip.fs:Hide()
 	end
-	collectgarbage("collect")
+	--collectgarbage("collect")
 --@debug@
 	xprint("Cleaning up")
 --@end-debug@
@@ -2287,10 +2942,17 @@ function addon:GetFollowerData(key,subkey)
 			if (not follower.isCollected) then
 				followersCache[i]=nil
 			else
-			follower.rank=follower.level==100 and follower.iLevel or follower.level
-			follower.coloredname=C(follower.name,tostring(follower.quality))
-			follower.fullname=format("%3d %s",follower.rank,follower.coloredname)
-			follower.maxed=follower.quality >= GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY and follower.level >=GARRISON_FOLLOWER_MAX_LEVEL
+				follower.rank=follower.level==100 and follower.iLevel or follower.level
+				follower.coloredname=C(follower.name,tostring(follower.quality))
+				follower.fullname=format("%3d %s",follower.rank,follower.coloredname)
+				follower.maxed=follower.quality >= GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY and follower.level >=GARRISON_FOLLOWER_MAX_LEVEL
+				local weaponItemID, weaponItemLevel, armorItemID, armorItemLevel = G.GetFollowerItems(follower.followerID);
+				follower.weaponItemID=weaponItemID
+				follower.weaponItemLevel=weaponItemLevel
+				follower.armorItemID=armorItemID
+				follower.armorItemLevel=armorItemLevel
+				follower.weaponQuality=select(3,GetItemInfo(weaponItemID))
+				follower.armorQuality=select(3,GetItemInfo(armorItemID))
 			end
 		end
 	end
@@ -2317,20 +2979,24 @@ function addon:GetFollowerData(key,subkey)
 end
 function addon:GetMissionData(missionID,subkey)
 	local missionCache=cache.missions[missionID]
-	if (missionCache.name=="<newmission>") then
+	if (not missionCache) then
 --@debug@
-		xprint("Found a new mission",missionID,"Refreshing mission list")
+		xprint("Found a new mission",missionID,G.GetMissionName(missionID),"Refreshing it")
 --@end-debug@
-		self:BuildMissionsCache()
+		self:BuildMissionCache(missionID)
 		self:FillCounters(missionID,cache.missions[missionID])
 		self:MatchMaker(missionID,cache.missions[missionID])
 	end
+	if not missionCache then return end
 	if (subkey) then
 		return missionCache[subkey]
 	end
 	return missionCache
 end
 function addon:GetFollowerStatusForMission(followerID,skipbusy)
+	if (GMCUsedFollowers[followerID]) then
+		return false
+	end
 	if (not skipbusy) then
 		return true
 	else
@@ -2338,6 +3004,7 @@ function addon:GetFollowerStatusForMission(followerID,skipbusy)
 	end
 end
 function addon:GetFollowerStatus(followerID,withTime,colored)
+	if (not followerID) then return UNAVAILABLE end
 	local status=G.GetFollowerStatus(followerID)
 	if (status and status== GARRISON_FOLLOWER_ON_MISSION and withTime) then
 		local running=dbcache.running[dbcache.runningIndex[followerID]]
@@ -2357,7 +3024,7 @@ function addon:FillMissionPage(missionInfo)
 --@debug@
 	xprint("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers)
 --@end-debug@
-	--DevTools_Dump(missionInfo)
+	--xdump(missionInfo)
 	--self:BuildMissionData(missionInfo.missionID.missionInfo)
 	GarrisonMissionPage_ClearParty()
 	local party=parties[missionID]
@@ -2388,9 +3055,9 @@ local firstcall=true
 function addon:GrowPanel()
 	GCF:Show()
 	if (bigscreen) then
-		GMF:ClearAllPoints()
-		GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT")
-		GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT")
+--		GMF:ClearAllPoints()
+--		GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT")
+--		GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT")
 		GMFRewardSplash:ClearAllPoints()
 		GMFRewardSplash:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT")
 		GMFRewardSplash:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT")
@@ -2407,11 +3074,13 @@ function addon:GrowPanel()
 		GMF.MissionCompleteBackground:SetWidth(BIGSIZEW)
 	else
 		GCF:SetWidth(GMF:GetWidth())
-		GMF:ClearAllPoints()
-		GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT")
-		GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT")
+--		GMF:ClearAllPoints()
+--		GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT",0,-25)
+--		GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT",0,-25)
 	end
-
+	GMF:ClearAllPoints()
+	GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT",0,23)
+	GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT",0,23)
 end
 ---@function
 -- Return bias color for follower and mission
@@ -2437,34 +3106,49 @@ function addon:GetBiasColor(followerID,missionID,goodcolor)
 	end
 	return goodcolor
 end
-function addon:FillFollowerButton(frame,followerID,missionID)
+function addon:RenderFollowerButton(frame,followerID,missionID)
 	if (not frame) then return end
-	for i=1,#frame.Threats do
-		if (frame.Threats[i]) then frame.Threats[i]:Hide() end
+	if (frame.Threats) then
+		for i=1,#frame.Threats do
+			if (frame.Threats[i]) then frame.Threats[i]:Hide() end
+		end
+		frame.NotFull:Hide()
 	end
-	frame.NotFull:Hide()
 	if (not followerID) then
-		frame.PortraitFrame.Empty:Show()
-		frame.Name:Hide()
-		frame.Class:Hide()
-		frame.Status:Hide()
+		if (frame.Name) then
+			frame.PortraitFrame.Empty:Show()
+			frame.Name:Hide()
+			frame.Class:Hide()
+			frame.Status:Hide()
+		else
+			frame.PortraitFrame.Empty:Hide()
+			frame.PortraitFrame.Portrait:Show()
+			frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_iLvlBorder");
+			frame.PortraitFrame.LevelBorder:SetWidth(70);
+			frame.PortraitFrame.Level:SetText(MISSING)
+			frame.PortraitFrame.Level:SetTextColor(1,0,0,0.7)
+		end
 		frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_LevelBorder");
 		frame.PortraitFrame.LevelBorder:SetWidth(58);
-		frame.PortraitFrame.Level:SetText("")
-		--frame:SetScript("OnEnter",nil)
 		GarrisonFollowerPortrait_Set(frame.PortraitFrame.Portrait)
+		frame.PortraitFrame.PortraitRingQuality:SetVertexColor(C.Silver());
+		frame.PortraitFrame.LevelBorder:SetVertexColor(C.Silver());
 		return
 	end
-	local info=G.GetFollowerInfo(followerID)
-	--local info=followers[ID]
+	frame.PortraitFrame.Level:SetTextColor(1,1,1,1)
+	frame.PortraitFrame.Portrait:Show()
+	local info=self:GetFollowerData(followerID)
+	if (not info) then return end
 	frame.info=info
 	frame.missionID=missionID
-	frame.Name:Show();
-	frame.Name:SetText(info.name);
-	local color=missionID and self:GetBiasColor(followerID,missionID,"White") or "Yellow"
-	frame.Name:SetTextColor(C[color]())
-	frame.Status:SetText(self:GetFollowerStatus(followerID,true,true))
-	frame.Status:Show()
+	if (frame.Name) then
+		frame.Name:Show()
+		frame.Name:SetText(info.name);
+		local color=missionID and self:GetBiasColor(followerID,missionID,"White") or "Yellow"
+		frame.Name:SetTextColor(C[color]())
+		frame.Status:SetText(self:GetFollowerStatus(followerID,true,true))
+		frame.Status:Show()
+	end
 	if (frame.Class) then
 		frame.Class:Show();
 		frame.Class:SetAtlas(info.classAtlas);
@@ -2472,7 +3156,7 @@ function addon:FillFollowerButton(frame,followerID,missionID)
 	frame.PortraitFrame.Empty:Hide();

 	local showItemLevel;
-	if (info.level == GarrisonMissionFrame.followerMaxLevel ) then
+	if (info.level == GMF.followerMaxLevel ) then
 		frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_iLvlBorder");
 		frame.PortraitFrame.LevelBorder:SetWidth(70);
 		showItemLevel = true;
@@ -2483,22 +3167,24 @@ function addon:FillFollowerButton(frame,followerID,missionID)
 	end
 	GarrisonMissionFrame_SetFollowerPortrait(frame.PortraitFrame, info, showItemLevel);
 	-- Counters icon
-	if (missionID and not GMF.MissionTab.MissionList.showInProgress) then
-		local tohide=1
-		local missionCounters=counters[missionID]
-		local index=counterFollowerIndex[missionID][followerID]
-		for i=1,#index do
-			local k=index[i]
-			local t=frame.Threats[i]
-			local tx=missionCounters[k].icon
-			t.Icon:SetTexture(tx)
-			local color=self:GetBiasColor(missionCounters[k].bias,nil,"Green")
-			t.Border:SetVertexColor(C[color]())
-			t:Show()
-			tohide=i+1
+	if (frame.Name) then
+		if (missionID and not GMF.MissionTab.MissionList.showInProgress) then
+			local tohide=1
+			local missionCounters=counters[missionID]
+			local index=counterFollowerIndex[missionID][followerID]
+			for i=1,#index do
+				local k=index[i]
+				local t=frame.Threats[i]
+				local tx=missionCounters[k].icon
+				t.Icon:SetTexture(tx)
+				local color=self:GetBiasColor(missionCounters[k].bias,nil,"Green")
+				t.Border:SetVertexColor(C[color]())
+				t:Show()
+				tohide=i+1
+			end
+		else
+			frame.Status:Hide()
 		end
-	else
-		frame.Status:Hide()
 	end
 end
 -- pseudo static
@@ -2507,11 +3193,15 @@ function addon:BuildFollowersButtons(button,bg,limit)
 	if (bg.Party) then return end
 	bg.Party={}
 	for numMembers=1,3 do
-		local f=CreateFrame("Button",nil,bg,"GarrisonCommanderMissionPageFollowerTemplate")
+		local f=CreateFrame("Button",nil,bg,bigscreen and "GarrisonCommanderMissionPageFollowerTemplate" or "GarrisonCommanderMissionPageFollowerTemplateSmall" )
 		if (numMembers==1) then
-			f:SetPoint("BOTTOMLEFT",bg.Percent,"BOTTOMRIGHT",10,0)
+			f:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMRIGHT",10,0)
 		else
-			f:SetPoint("LEFT",bg.Party[numMembers-1],"RIGHT",10,0)
+			if (bigscreen) then
+				f:SetPoint("LEFT",bg.Party[numMembers-1],"RIGHT",10,0)
+			else
+				f:SetPoint("LEFT",bg.Party[numMembers-1],"LEFT",65,0)
+			end
 		end
 		tinsert(bg.Party,f)
 		f:EnableMouse(true)
@@ -2519,14 +3209,16 @@ function addon:BuildFollowersButtons(button,bg,limit)
 		f:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave)
 		f:RegisterForClicks("AnyUp")
 		f:SetScript("OnClick",function(...) self:OnClick_PartyMember(...) end)
-		for numThreats=1,4 do
-			local threatFrame =f.Threats[numThreats];
-			if ( not threatFrame ) then
-				threatFrame = CreateFrame("Frame", nil, f, "GarrisonAbilityCounterTemplate");
-				threatFrame:SetPoint("LEFT", f.Threats[numThreats - 1], "RIGHT", 10, 0);
-				tinsert(f.Threats, threatFrame);
+		if (bigscreen) then
+			for numThreats=1,4 do
+				local threatFrame =f.Threats[numThreats];
+				if ( not threatFrame ) then
+					threatFrame = CreateFrame("Frame", nil, f, "GarrisonAbilityCounterTemplate");
+					threatFrame:SetPoint("LEFT", f.Threats[numThreats - 1], "RIGHT", 10, 0);
+					tinsert(f.Threats, threatFrame);
+				end
+				threatFrame:Hide()
 			end
-			threatFrame:Hide()
 		end
 	end
 	for i=1,3 do bg.Party[i]:SetScale(0.9) end
@@ -2539,123 +3231,109 @@ function addon:BuildFollowersButtons(button,bg,limit)
 		button.Threats[1]:ClearAllPoints()
 		button.Threats[1]:SetPoint("TOPLEFT",165,0)
 	end
-
-
-
 end
 function addon:RenderExtraButton(button,numRewards)
-	local panel=button.gcPANEL
+	local panel=button.gcINDICATOR
 	local missionInfo=button.info
 	local missionID=missionInfo.missionID
 	panel.missionID=missionID
+	local mission=missionInfo
+	if not mission then print "not yet updated missions" return end -- something went wrong while refreshing
+	if (not bigscreen) then
+		local index=mission.numFollowers+numRewards-3
+		local position=(index * -65) - 130
+		button.gcPANEL.Party[1]:ClearAllPoints()
+		button.gcPANEL.Party[1]:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMLEFT", position,0)
+	end
 	if (GMF.MissionTab.MissionList.showInProgress) then
 		local perc=select(4,G.GetPartyMissionInfo(missionID))
 		panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc)
 		panel.Age:Hide()
-		local q=self:GetDifficultyColor(perc)
-		panel.Percent:SetTextColor(q.r,q.g,q.b)
-		if (bigscreen) then
-			for i=1,3 do
-				local frame=panel.Party[i]
-				if (missionInfo.followers[i]) then
-					self:FillFollowerButton(frame,missionInfo.followers[i],missionID)
-					frame:Show()
-				else
-					frame:Hide()
-				end
-			end
-			if ( missionInfo.locPrefix ) then
-				panel.LocBG:Show();
-				panel.LocBG:SetAtlas(missionInfo.locPrefix.."-List");
+		panel.Percent:SetTextColor(self:GetDifficultyColors(perc))
+		for i=1,3 do
+			local frame=button.gcPANEL.Party[i]
+			if (missionInfo.followers[i]) then
+				self:RenderFollowerButton(frame,missionInfo.followers[i],missionID)
+				frame:Show()
 			else
-				panel.LocBG:Hide();
+				frame:Hide()
 			end
 		end
 		return
 	end
-	local mission=self:GetMissionData(missionID)
 	local party=parties[missionID]
 	if (#party.members==0) then
+		local mission=self:GetMissionData(missionID) -- matchmaker and fillcounters need our enriched mission
 		self:FillCounters(missionID,mission)
 		self:MatchMaker(missionID,mission,party)
 	end
 	local perc=party.perc
 	local age=tonumber(dbcache.seen[missionID])
 	local notFull=false
-	if (bigscreen) then
-		for i=1,3 do
-			local frame=button.gcPANEL.Party[i]
-			if (i>mission.numFollowers) then
-				frame:Hide()
+	for i=1,3 do
+		local frame=button.gcPANEL.Party[i]
+		if (i>mission.numFollowers) then
+			frame:Hide()
+		else
+			if (party.members[i]) then
+				self:RenderFollowerButton(frame,party.members[i],missionID)
+				if (bigscreen) then frame.NotFull:Hide() end
 			else
-				if (party.members[i]) then
-					self:FillFollowerButton(frame,party.members[i],missionID)
-					frame.NotFull:Hide()
-				else
-					self:FillFollowerButton(frame,false)
-					frame.NotFull:Show()
-				end
-				frame:Show()
+				self:RenderFollowerButton(frame,false)
+				if (bigscreen) then frame.NotFull:Show() end
 			end
-		end
-		if ( mission.locPrefix ) then
-			panel.LocBG:Show();
-			panel.LocBG:SetAtlas(mission.locPrefix.."-List");
-		else
-			panel.LocBG:Hide();
+			frame:Show()
 		end
 	end
+	panel=button.gcINDICATOR
 	panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc)
-	local q=self:GetDifficultyColor(perc)
-	panel.Percent:SetTextColor(q.r,q.g,q.b)
+	panel.Percent:SetTextColor(self:GetDifficultyColors(perc))
 	panel.Percent:SetWidth(80)
 	panel.Percent:SetJustifyH("RIGHT")
 	if (age) then
-		local day=60*24
-		age=floor((time()-age)/60)
-		local days=floor(age/day)
-		if (days==0) then
-			local hours=floor(age/60)
-			panel.Age:SetFormattedText(AGE_HOURS,hours, age  -hours*60 )
-			panel.Age:SetTextColor(C.Green())
+		local expire=ns.wowhead[missionID]
+		if (expire==9999999) then
+			panel.Age:SetText("Expires: Far far away")
+			panel.Age:SetTextColor(C.White())
+		elseif (expire==0) then
+			panel.Age:SetText("Expires: " .. UNKNOWN)
+			panel.Age:SetTextColor(C.White())
 		else
-			local q=self:GetDifficultyColor(100-(days*10),true)
+			local age=(age+expire-time())/60
+			if age < 0 then age=0 end
+			local hours=(floor((age/60)/6)+1)*6
+			local q=self:GetDifficultyColor(hours+20,true)
+			panel.Age:SetFormattedText("Expires in less than %d hr",hours)
 			panel.Age:SetTextColor(q.r,q.g,q.b)
-			panel.Age:SetFormattedText(AGE_DAYS,days,(age-days*day)/60)
 		end
 	else
 		panel.Age:SetText(UNKNOWN)
 	end
 	panel.Age:Show()
 	panel.Percent:Show()
-	if (not bigscreen) then
-		panel:SetPoint("TOPRIGHT",numRewards *-75 - (GMM and 65 or 0),0)
-		panel.Followers:SetFormattedText(GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS,mission.numFollowers)
-	end
+end
+function addon:CheckExpire(missionID)
+	local age=tonumber(dbcache.seen[missionID])
+	local expire=ns.wowhead[missionID]
+	print("Age",date("%m/%d/%y %H:%M:%S",age))
+	print("Now",date("%m/%d/%y %H:%M:%S"))
+	print("Expire",expire,ns.expire[missionID])
+	print("Age+expire",date("%m/%d/%y %H:%M:%S",age+expire))
+	print("Delta",age+expire-time())
 end
 function addon:BuildExtraButton(button)
-	if (bigscreen) then
-		local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton")
-		bg:SetPoint("TOPLEFT",button,"TOPRIGHT")
-		bg:SetPoint("RIGHT",GarrisonMissionFrameMissionsListScrollFrame,"RIGHT",-25,0)
-		bg.button=button
-		bg:SetScript("OnEnter",function(this) GarrisonMissionButton_OnEnter(this.button) end)
-		bg:SetScript("OnLeave",function() GameTooltip:FadeOut() end)
-		bg:RegisterForClicks("AnyUp")
-		bg:SetScript("OnClick",function(...) self:OnClick_GCMissionButton(...) end)
-		button.gcPANEL=bg
-		if (not bg.Party) then self:BuildFollowersButtons(button,bg,3) end
-	else
-		local bg=button.GC
-		if (not bg) then
-			bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionInfo")
-			bg:SetHeight(button:GetHeight())
-			button.gcPANEL=bg
-			bg.button=button
-			bg:SetScript("OnEnter",function(this) GarrisonMissionButton_OnEnter(this.button,"LeftUp") end)
-			bg:SetScript("OnLeave",function(this) GameTooltip:FadeOut() end)
-		end
-	end
+	local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton")
+	local indicators=CreateFrame("Frame",nil,button,"GarrisonCommanderIndicators")
+	indicators:SetPoint("LEFT",70,0)
+	bg:SetPoint("RIGHT")
+	bg.button=button
+	bg:SetScript("OnEnter",function(this) GarrisonMissionButton_OnEnter(this.button) end)
+	bg:SetScript("OnLeave",function() GameTooltip:FadeOut() end)
+	bg:RegisterForClicks("AnyUp")
+	bg:SetScript("OnClick",function(...) self:OnClick_GCMissionButton(...) end)
+	button.gcPANEL=bg
+	button.gcINDICATOR=indicators
+	if (not bg.Party) then self:BuildFollowersButtons(button,bg,3) end
 end
 --function addon:GarrisonMissionButton_SetRewards(button,rewards,numrewards)
 --end
@@ -2741,24 +3419,25 @@ function addon:OnClick_GarrisonMissionFrame_MissionComplete_NextMissionButton(th
 	end
 end
 function addon:OnClick_GarrisonMissionButton(tab,button)
+	if (GMF.MissionTab.MissionList.showInProgress) then
+		return
+	end
 --@debug@
-	trace("Clicked")
+	xprint("Clicked GarrisonMissionButto")
 --@end-debug@
 	if (tab.fromFollowerPage) then
 		GarrisonMissionFrame_SelectTab(1)
 		self:FillMissionPage(tab.info)
 	else
 --@debug@
-		DevTools_Dump(tab.info)
+		xdump(tab.info)
 --@end-debug@
 		self:FillMissionPage(tab.info)
 	end
 end
 function addon:OnClick_GCMissionButton(frame,button)
 	if (button=="RightButton") then
-
 		self:HookedGarrisonMissionButton_SetRewards(frame:GetParent(),{},0)
-		_G.DBG=frame.button.info.missionID
 	else
 		frame.button:Click()
 	end
@@ -2774,99 +3453,124 @@ function addon:RenderButton(button,rewards,numRewards)
 		return
 --@end-debug@
 	end
-	--if (self:IsRewardPage()) then return end
+	local missionID=button.info.missionID
+	if GMF.MissionTab.MissionList.showInProgress and missionID==button.lastMissionID then return end
+	button.lastMissionID=missionID
 	if (bigscreen) then
 		local width=GMF.MissionTab.MissionList.showInProgress and BIGBUTTON or SMALLBUTTON
-		button:SetWidth(width)
-		button.LocBG:SetPoint("LEFT")
+		button:SetWidth(width+600)
+		button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0)
+	end
+	if (not button.xp) then
+		button.xp=button:CreateFontString(nil, "ARTWORK", "QuestMaprewardsFont")
+		button.xp:SetPoint("TOPRIGHT",button.Rewards[1],"TOPRIGHT")
+		button.xp:SetJustifyH("RIGHT")
+		button.xp:Show()
+
 	end
-	local tw=button:GetWidth()-165 - (GMM and 65 or 0)
-	if ( button.Title:GetWidth() + button.Summary:GetWidth() + 8 < tw - numRewards * 65 ) then
+	button.MissionType:SetPoint("TOPLEFT",5,-2)
+	button.xp:SetWidth(0)
+	if (not GMF.MissionTab.MissionList.showInProgress) then
+		button.xp:SetFormattedText("Xp: %d (approx)",self:GetMissionData(missionID,'globalXp'))
+		button.xp:SetTextColor(self:GetDifficultyColors(self:GetMissionData(missionID,'totalXp')/3000*100))
+	else
+		button.xp:Hide()
+	end
+	--button.Title:SetText("123456789012345678901234567890123456789012345678901234567890") -- Used for design
+	local offset= bigscreen and (numRewards *65) or (button.info.numFollowers+numRewards) *65
+	local tw=button:GetWidth() - 165
+	if (button.Title:GetWidth() + button.Summary:GetWidth() + button.xp:GetWidth() < (tw -offset) ) then
 		button.Title:SetPoint("LEFT", 165, 5);
 		button.Summary:ClearAllPoints();
 		button.Summary:SetPoint("BOTTOMLEFT", button.Title, "BOTTOMRIGHT", 8, 0);
 	else
 		button.Title:SetPoint("LEFT", 165, 25);
-		button.Title:SetWidth(tw - numRewards * 65);
+		button.Title:SetWidth(tw - offset);
 		button.Summary:ClearAllPoints();
 		button.Summary:SetPoint("TOPLEFT", button.Title, "BOTTOMLEFT", 0, -4);
 	end
-	local missionID=button.info.missionID
-	if (not button.Threats) then -- I am a good guy. If MP present, I dont make my own threat indicator (Only MP <= 1.8)
-		if (not button.Env) then
-			button.Env=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate")
-			button.Env:SetWidth(20)
-			button.Env:SetHeight(20)
-			button.Env:SetPoint("BOTTOMLEFT",button,165,8)
-			button.GcThreats={}
-		end
-		local slots=self:GetMissionData(missionID,'slots')
-		local threatIndex=1
-		if (not GMF.MissionTab.MissionList.showInProgress) then
-			button.Env:Show()
-			dbg=missionID==(tonumber(_G.MW) or 0)
-			if (dbg) then self:DumpParty(missionID) end
-			for i=1,#slots do
-				local slot=slots[i]
-				if (slot.name==TYPE) then
-					button.Env.Icon:SetTexture(slot.icon)
-					self:SetThreatColor(button.Env,missionID)
-					button.Env.info=self.db.global.types[slot.key]
-					button.Env:SetScript("OnEnter",GarrisonMissionMechanic_OnEnter)
-					button.Env:SetScript("OnLeave",function() GarrisonMissionMechanicTooltip:Hide() end)
-				else
-					local th=button.GcThreats[threatIndex]
-					if (not th) then
-						th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate")
-						th:SetWidth(20)
-						th:SetHeight(20)
-						button.GcThreats[threatIndex]=th
-						th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8)
+	local threatIndex=1
+	if (not GMF.MissionTab.MissionList.showInProgress) then
+		if (not button.Threats) then -- I am a good guy. If MP present, I dont make my own threat indicator (Only MP <= 1.8)
+			if (not button.Env) then
+				button.Env=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate")
+				button.Env:SetWidth(20)
+				button.Env:SetHeight(20)
+				button.Env:SetPoint("BOTTOMLEFT",button,165,8)
+				button.GcThreats={}
+			end
+			local slots=self:GetMissionData(missionID,'slots')
+			if (not GMF.MissionTab.MissionList.showInProgress) then
+				button.Env:Show()
+				if (dbg) then self:DumpParty(missionID) end
+				for i=1,#slots do
+					local slot=slots[i]
+					if (slot.name==TYPE) then
+						button.Env.Icon:SetTexture(slot.icon)
+						self:SetThreatColor(button.Env,missionID)
+						button.Env.info=self.db.global.types[slot.key]
+						button.Env:SetScript("OnEnter",function(...) addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,...) end)
+						button.Env:SetScript("OnLeave",function() GameTooltip:Hide() end)
+					else
+						local th=button.GcThreats[threatIndex]
+						if (not th) then
+							th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate")
+							th:SetWidth(20)
+							th:SetHeight(20)
+							th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8)
+							button.GcThreats[threatIndex]=th
+						end
 						th.info=slot
-						th:SetScript("OnEnter",GarrisonMissionMechanic_OnEnter)
-						th:SetScript("OnLeave",function() GarrisonMissionMechanicTooltip:Hide() end)
+						threatIndex=threatIndex+1
+						th.Icon:SetTexture(slot.icon)
+						self:SetThreatColor(th,missionID)
+						th:Show()
+						th:SetScript("OnEnter",function(...) addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,...) end)
+						th:SetScript("OnLeave",function() GameTooltip:Hide() end)
 					end
-					threatIndex=threatIndex+1
-					th.Icon:SetTexture(slot.icon)
-					self:SetThreatColor(th,missionID)
-					th:Show()
 				end
+			else
+				button.Env:Hide()
 			end
-		else
-			button.Env:Hide()
 		end
-		for i=threatIndex,#button.GcThreats do
-			button.GcThreats[i]:Hide()
+		if (numRewards > 0) then
+			local index=1
+			for id,reward in pairs(rewards) do
+				local Reward = button.Rewards[index];
+				Reward.Quantity:SetTextColor(C.Yellow())
+				if (reward.followerXP) then
+					Reward.Quantity:SetText(reward.followerXP)
+					Reward.Quantity:Show()
+				elseif (reward.currencyID==0) then
+					Reward.Quantity:SetFormattedText("%d",reward.quantity/10000)
+					Reward.Quantity:Show()
+				elseif (reward.itemID and reward.itemID==120205) then
+					Reward.Quantity:SetFormattedText("%d",self:GetMissionData(missionID,'xp') or 1)
+					Reward.Quantity:Show()
+				elseif (reward.itemID and reward.quantity==1) then
+					local _,_,q,i=GetItemInfo(reward.itemID)
+					Reward.Quantity:SetText(i)
+					local c=ITEM_QUALITY_COLORS[q]
+					if (not c) then
+						Reward.Quantity:SetTextColor(1,1,1)
+					else
+						Reward.Quantity:SetTextColor(c.r,c.g,c.b)
+					end
+					Reward.Quantity:Show()
+				end
+				index=index+1
+			end
 		end
+	else
+		if (button.Env) then button.Env:Hide() end
 	end
-	if (numRewards > 0) then
-		local index=1
-		for id,reward in pairs(rewards) do
-			local Reward = button.Rewards[index];
-			Reward.Quantity:SetTextColor(C.Yellow())
-			if (reward.followerXP) then
-				Reward.Quantity:SetText(reward.followerXP)
-				Reward.Quantity:Show()
-			elseif (reward.currencyID==0) then
-				Reward.Quantity:SetFormattedText("%d",reward.quantity/10000)
-				Reward.Quantity:Show()
-			elseif (reward.itemID and reward.quantity==1) then
-				local _,_,q,i=GetItemInfo(reward.itemID)
-				local c=ITEM_QUALITY_COLORS[q]
-				if (not c) then c={r=1,g=1,b=1} end
-				Reward.Quantity:SetText(i)
-				Reward.Quantity:SetTextColor(c.r,c.g,c.b)
-				Reward.Quantity:Show()
-			end
-			index=index+1
+	if (button.GcThreats) then
+		for i=threatIndex,#button.GcThreats do
+			button.GcThreats[i]:Hide()
 		end
 	end
 	if (button.fromFollowerPage) then
-		--button.Title:ClearAllPoints()
-		--button.Title:SetPoint("TOPLEFT",165,-5)
-		--button.Summary:ClearAllPoints()
-		--button.Summary:SetPoint("BOTTOMLEFT",165,5)
-		--button:SetHeight(70)
+		print("From follower page")
 		return
 	end
 	if (not button.gcPANEL) then
@@ -2874,213 +3578,703 @@ function addon:RenderButton(button,rewards,numRewards)
 	end
 	self:RenderExtraButton(button,numRewards)
 end
---@do-not-package@
-_G.GAC=addon
---[[

-GMFMissions.CompleteDialog.BorderFrame.CompleteAll
-Garrison page structure
-Tab selection:
-Managed by
-GarrisonMissionFrameTab(1|2) onclick:
-->GarrisonMissionFrameTab_OnClick(self)
---->GarrisonMissionFrame_SelectTab(self:GetID()) - 1 for Missions, 2 for followers
+-- Courtesy of Motig
+-- Concept and interface reused with permission
+-- Mission building rewritten from scratch
+local GMC_G = {}
+--GMC_G.frame = CreateFrame('FRAME')
+local aMissions={}

-Main Container is GarrisonMissionFrame
-Followers tab selected:
-->GarrisonMissionFrameFollowers -> anchored GarrisonMissionFrame TOPLEFT 33,-64
--->GarrisonMissionFrameFollowersListScrollFrame
---->GarrisonMissionFrameFollowersListScrooFrameScrollChild
----->GarrisonMissionFrameFollowersListScrooFrameButton(1..9)
-->GarrisonMissionFrame.FollowerTab -> abcuored GarrisonMissionFrame TOPRIGHT -35 -64
-Missions tab selected
-->GarrisonMissionFrameMissions -> anchored (parent)e TOPLEFT 35,-65
+function addon:GMCCreateMissionList(workList)
+	--First get rid of unwanted rewards and missions that are too long
+	local settings=self.privatedb.profile.missionControl
+	local ar=settings.allowedRewards
+	wipe(workList)
+	for missionID,mission in pairs(cache.missions) do
+		local discarded=false
+		repeat
+			if (mission.durationSeconds > settings.maxDuration * 3600 or mission.durationSeconds <  settings.minDuration * 3600) then
+				xprint(missionID,"discarded due to len",mission.durationSeconds /3600)
+				break
+			end -- Mission too long, out of here
+			if (mission.isRare and settings.skipRare) then
+				xprint(missionID,"discarded due to rarity")
+				break
+			end
+			for k,v in pairs(ar) do
+				if (not v) then
+					if (mission[k] and mission[k]~=0) then -- we have a forbidden reward
+						discarded=true
+						break
+					end
+				end
+			end
+			if (not discarded) then
+				tinsert(workList,missionID)
+			end
+		until true
+	end
+	local function msort(i1,i2)
+		local m1=addon:GetMissionData(i1)
+		local m2=addon:GetMissionData(i2)
+		for i=1,#GMC.settings.itemPrio do
+			local criterium=GMC.settings.itemPrio[i]
+			xprint("Checking",criterium)
+			if (criterium) then
+				xprint(i1,i2,"Sorting on ",criterium,m1[criterium] , m2[criterium])
+				if (m1[criterium] ~= m2[criterium]) then
+					xprint(i1,i2,"Sorted on ",criterium,m1[criterium] , m2[criterium])
+					return m1[criterium] > m2[criterium]
+				end
+			end
+		end
+		xprint(i1,i2,"Sorted on level",m1.level , m2.level)
+		return m1.level > m2.level
+	end
+	table.sort(workList,msort)
+end
+local factory={} --#factory
+do
+	local nonce=0
+	local GetTime=GetTime
+	function factory:Slider(father,min,max,current,message)
+		local name=tostring(self)..GetTime()*1000 ..nonce
+		nonce=nonce+1
+		local sl = CreateFrame('Slider',name, father, 'OptionsSliderTemplate')
+		sl:SetWidth(128)
+		sl:SetHeight(20)
+		sl:SetOrientation('HORIZONTAL')
+		sl:SetMinMaxValues(min, max)
+		sl:SetValue(current)
+		sl:SetValueStep(1)
+		sl.Low=_G[name ..'Low']
+		sl.Low:SetText(min)
+		sl.High=_G[name .. 'High']
+		sl.High:SetText(max)
+		sl.Text=_G[name.. 'Text']
+		sl.Text:SetText(message)
+		sl.OnValueChanged=function(this,value)
+			if (not this.unrounded) then
+				value = math.floor(value)
+			end
+			if (this.isPercent) then
+				this.Text:SetFormattedText('%d%%',value)
+			else
+				this.Text:SetText(value)
+			end
+			return value
+		end
+		sl:SetScript("OnValueChanged",sl.OnValueChanged)
+		return sl
+	end
+	function factory:Checkbox(father,current,message)
+		local name=tostring(self)..GetTime()*1000 ..nonce
+		nonce=nonce+1
+		local ck=CreateFrame("CheckButton",name,father,"ChatConfigCheckButtonTemplate")
+		ck.Text=_G[name..'Text']
+		ck.Text:SetText(message)
+		ck:SetChecked(current)
+		return ck
+	end
+end
+--- This routine can be called both as coroutin and as a standard one
+-- In standard version, delay between group building and submitting is done via a self schedule
+--@param #integer missionID Optional, to run a single mission
+--@param #bool start Optional, tells that follower already are on mission and that we need just to start it
+function addon:GMCRunMission(missionID,start)
+	xprint("Asked to start mission",missionID)
+	if (start) then
+		G.StartMission(missionID)
+		PlaySound("UI_Garrison_CommandTable_MissionStart")
+		return
+	end
+	for i=1,#GMC.ml.Parties do
+		local party=GMC.ml.Parties[i]
+		xprint("Checking",party.missionID)
+		if (missionID and party.missionID==missionID or not missionID) then
+			GMC.ml.widget:RemoveChild(party.missionID)
+			GMC.ml.widget:DoLayout()
+			if (party.full) then
+				for j=1,#party.members do
+					G.AddFollowerToMission(party.missionID, party.members[j])
+				end
+				if (not missionID) then
+					coroutine.yield(true)
+					G.StartMission(party.missionID)
+					PlaySound("UI_Garrison_CommandTable_MissionStart")
+					coroutine.yield(true)
+				else
+					self:ScheduleTimer("GMCRunMission",0.25,party.missionID,true)
+				end
+			end
+		end
+	end
+end
+do
+	local timeElapsed=0
+	local currentMission=0
+	local x=0
+	function addon:GMCCalculateMissions(this,elapsed)
+		db.news.MissionControl=true
+		timeElapsed = timeElapsed + elapsed
+		if (#aMissions == 0 ) then
+			if timeElapsed >= 1 then
+				currentMission=0
+				x=0
+				self:Unhook(this,"OnUpdate")
+				GMC.ml.widget:SetTitle(READY)
+				GMC.ml.widget:SetTitleColor(C.Green())
+				this:Enable()
+				if (#GMC.ml.Parties>0) then
+					GMC.runButton:Enable()
+				end
+			end
+			return
+		end
+		if (timeElapsed >=0.) then
+			currentMission=currentMission+1
+			if (currentMission > #aMissions) then
+				wipe(aMissions)
+				currentMission=0
+				x=0
+				timeElapsed=0.2
+			else
+				GMC.ml.widget:SetFormattedTitle("Processing mission %d of %d",currentMission,#aMissions)
+				local missionID=aMissions[currentMission]
+				if (dbg) then print(C("Processing ","Red"),missionID) end
+				local party={members={},perc=0}
+				local mission=self:GetMissionData(missionID)
+				if (not mission ) then
+					if dbg then print ("NO data for",missionID) end
+					return
+				end
+				self:MatchMaker(missionID,mission,party) -- I need my mission data
+				local minimumChance=0
+				if (GMC.settings.useOneChance) then
+					minimumChance=GMC.settings.minimumChance
+				end
+				for prio,enabled in pairs(GMC.settings.allowedRewards) do
+					if (dbg) then print("Chance from ",prio,"=",GMC.settings.rewardChance[prio],enabled) end
+					if (enabled and (tonumber(self:GetMissionData(missionID,prio)) or 0) >0) then
+						minimumChance=math.max(GMC.settings.rewardChance[prio],minimumChance)
+					end
+				end
+				if (dbg) then print ("Missionid",missionID,"Chance",minimumChance,"chance",party.perc) end
+				if ( party.full and party.perc >= minimumChance) then
+					if (dbg) then print("Preparing button for",missionID) end
+					local mb=AceGUI:Create("GMCMissionButton")
+					for i=1,#party.members do
+						GMCUsedFollowers[party.members[i]]=true
+					end
+					party.missionID=missionID
+					tinsert(GMC.ml.Parties,party)
+					GMC.ml.widget:PushChild(mb,missionID)
+					mb:SetFullWidth(true)
+					mb:SetMission(mission)
+					mb:SetCallback("OnClick",function(...)
+						addon:GMCRunMission(missionID)
+						GMC.ml.widget:RemoveChild(missionID)
+					end
+					)
+				end
+				timeElapsed=0
+			end
+		end
+	end
+end

+function addon:GMC_OnClick_Run(this,button)
+	this:Disable()
+	do
+	local elapsed=0
+	local co=coroutine.wrap(self.GMCRunMission)
+	self:RawHookScript(GMC.runButton,'OnUpdate',function(this,ts)
+		elapsed=elapsed+ts
+		if (elapsed>0.25) then
+			elapsed=0
+			local rc=co(self)
+			if (not rc) then
+				self:Unhook(GMC.runButton,'OnUpdate')
+			end
+		end
+	end
+	)
+	end
+end
+function addon:GMC_OnClick_Start(this,button)
+	xprint(C("-------------------------------------------------","Yellow"))
+	this:Disable()
+	GMC.ml.widget:ClearChildren()
+	addon:GMCCreateMissionList(aMissions)
+	wipe(GMCUsedFollowers)
+	wipe(GMC.ml.Parties)
+	if (#aMissions>0) then
+		GMC.ml.widget:SetFormattedTitle(L["Processing mission %d of %d"],1,#aMissions)
+	else
+		GMC.ml.widget:SetTitle("No mission matches your criteria")
+		GMC.ml.widget:SetTitleColor(C.Red())
+	end
+	self:RawHookScript(GMC.startButton,'OnUpdate',"GMCCalculateMissions")

+end
+local chestTexture
+function addon:GMCBuildPanel()
+	--PanelTemplates_SetNumTabs(GarrisonMissionFrame, 4)
+	--PanelTemplates_UpdateTabs(GarrisonMissionFrame)
+	chestTexture='GarrMission-'..UnitFactionGroup('player').. 'Chest'
+	GMC = CreateFrame('FRAME', 'GMCOptions', GarrisonMissionFrame)
+	GMC.settings=dbcache.missionControl
+	GMC:SetPoint('CENTER')
+	GMC:SetSize(GarrisonMissionFrame:GetWidth(), GarrisonMissionFrame:GetHeight())
+	GMC:Hide()
+	local chance=self:GMCBuildChance()
+	local duration=self:GMCBuildDuration()
+	local rewards=self:GMCBuildRewards()
+	local priorities=self:GMCBuildPriorities()
+	local list=self:GMCBuildMissionList()
+	duration:SetPoint("TOPLEFT",0,-50)
+	chance:SetPoint("TOPLEFT",duration,"TOPRIGHT",bigscreen and 50 or 10,0)
+	priorities:SetPoint("TOPLEFT",duration,"BOTTOMLEFT",25,-40)
+	rewards:SetPoint("TOPLEFT",priorities,"TOPRIGHT",bigscreen and 50 or 15,0)
+	list:SetPoint("TOPLEFT",chance,"TOPRIGHT",10,0)
+	list:SetPoint("BOTTOMRIGHT",GMF,"BOTTOMRIGHT",-25,25)
+	GMC.skipRare=factory:Checkbox(GMC,GMC.settings.skipRare,L["Ignore rare missions"])
+	GMC.skipRare:SetPoint("TOPLEFT",priorities,"BOTTOMLEFT",0,-10)
+	GMC.startButton = CreateFrame('BUTTON',nil,  list.frame, 'GameMenuButtonTemplate')
+	GMC.startButton:SetText('Calculate')
+	GMC.startButton:SetWidth(148)
+	GMC.startButton:SetPoint('TOPLEFT',15,25)
+	GMC.startButton:SetScript('OnClick', function(this,button) self:GMC_OnClick_Start(this,button) end)
+	GMC.startButton:SetScript('OnEnter', function() GameTooltip:SetOwner(GMC.startButton, 'ANCHOR_TOPRIGHT') GameTooltip:AddLine('Assign your followers to missions.') GameTooltip:Show() end)
+	GMC.startButton:SetScript('OnLeave', function() GameTooltip:Hide() end)
+	GMC.runButton = CreateFrame('BUTTON', nil,list.frame, 'GameMenuButtonTemplate')
+	GMC.runButton:SetText('Send all mission at once')
+	GMC.runButton:SetScript('OnEnter', function()
+		GameTooltip:SetOwner(GMC.runButton, 'ANCHOR_TOPRIGHT')
+		GameTooltip:AddLine('Submit all yopur mission at once. No question asked.')
+		GameTooltip:AddLine('You can also send mission one by one clicking on each button.')
+		GameTooltip:Show()
+	end)
+	GMC.runButton:SetScript('OnLeave', function() GameTooltip:Hide() end)
+	GMC.runButton:SetWidth(148)
+	GMC.runButton:SetPoint('TOPRIGHT',-15,25)
+	GMC.runButton:SetScript('OnClick',function(this,button) self:GMC_OnClick_Run(this,button) end)
+	GMC.runButton:Disable()
+	GMC.Credits=GMC:CreateFontString(nil,"ARTWORK","ReputationDetailFont")
+	GMC.Credits:SetWidth(0)
+	GMC.Credits:SetFormattedText("Original concept and interface by %s",C("Motig","Red") )
+	GMC.Credits:SetPoint("BOTTOMLEFT",25,25)
+end
+function addon:GMCRewardRefresh()
+	local single=GMC.settings.useOneChance
+	local ref
+	for i=1,#GMC.ignoreFrames do
+		local frame=GMC.ignoreFrames[i]
+		local allowed=GMC.settings.allowedRewards[frame.key]
+		frame.icon:SetDesaturated(not allowed)
+		local a1,o,a2,x,y=frame:GetPoint(1)
+		if (not single) then
+			frame.chest:Show()
+			frame.slider:Show()
+			frame:SetPoint(a1,o,a2,0,y)
+		else
+			frame.chest:Hide()
+			frame.slider:Hide()
+			frame:SetPoint(a1,o,a2,100,y)
+		end
+		ref=frame
+	end
+	if (single) then
+		GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', -110, -15)
+		GMC.cp:SetDesaturated(false)
+		GMC.ct:SetTextColor(C.Green())
+	else
+		GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', 10, -15)
+		GMC.cp:SetDesaturated(true)
+		GMC.ct:SetTextColor(C.Silver())
+	end
+end
+function addon:GMCBuildChance()
+	_G['GMC']=GMC
+	--Chance
+	GMC.cf = CreateFrame('FRAME', nil, GMC)
+	GMC.cf:SetSize(256, 150)

+	GMC.cp = GMC.cf:CreateTexture(nil, 'BACKGROUND')
+	GMC.cp:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp')
+	GMC.cp:SetAtlas(chestTexture)
+	GMC.cp:SetSize((209-(209*0.25))*0.60, (155-(155*0.25))*0.60)
+	GMC.cp:SetPoint('CENTER', 0, 20)

-GarrisonMissionFrameMissionsListScrollFrameButtonx.info:
-Dump: value=GarrisonMissionFrameMissionsListScrollFrameButton1.info
-[1]={
-	description="In a remote corner of Talador, a small faction of draenei has embraced the worship of Sargeras. Stop their cult before it spreads.",
-	cost=10,
-	duration="4 hr",
-	durationSeconds=14400,
-	level=100,
-	type="Combat",
-	locPrefix="GarrMissionLocation-Talador",
-	rewards={
-		[290]={
-			title="Money Reward",
-			quantity=600000,
-			icon="Interface\\Icons\\inv_misc_coin_01",
-			currencyID=0
-		}
-	},
-	numRewards=1,
-	numFollowers=2,
-	state=-2,
-	iLevel=0,
-	name="Cult of Sargeras",
-	followers={
-	},
-	location="Talador",
-	isRare=false,
-	typeAtlas="GarrMission_MissionIcon-Combat",
-	missionID=126
-}
-Dump: value=G.GetFollowerInfo("0x000000000002F5E1")
-[1]={
-	displayHeight=0.5,
-	iLevel=600,
-	scale=0.60000002384186,
-	classAtlas="GarrMission_ClassIcon-Druid",
-	garrFollowerID="0x0000000000000022",
-	displayScale=1,
-	status="On Mission",
-	level=100,
-	quality=4,
-	portraitIconID=1066112,
-	isFavorite=false,
-	xp=0,
-	className="Guardian Druid",
-	classSpec=8,
-	name="Qiana Moonshadow",
-	followerID="0x000000000002F5E1",
-	height=1.3999999761581,
-	displayID=55047,
-	levelXP=0,
-	isCollected=true
-}
-value=GarrisonMissionFrame.MissionTab.MissionList.availableMissions[13]
-[1]={
-	description="Scouts report a many-headed beast named Festerbloom waylaying travelers crossing the Murkbog.  Clear the path for everyone's sake.",
-	cost=20,
-	duration="10 hr",
-	durationSeconds=36000,
-	level=96,
-	type="Combat",
-	locPrefix="GarrMissionLocation-SpiresofArak",
-	rewards={
-		[778]={
-			title="Bonus Follower XP",
-			followerXP=1400,
-			tooltip="+1,400 XP",
-			icon="Interface\\Icons\\XPBonus_Icon",
-			name="+1,400 XP"
-		}
-	},
-	numRewards=1,
-	numFollowers=3,
-	state=-2,
-	iLevel=0,
-	name="Murkbog Terror",
-	followers={
-	},
-	location="Spires of Arak",
-	isRare=false,
-	typeAtlas="GarrMission_MissionIcon-Combat",
-	missionID=374
-}
-Dump: value=GarrisonMissionFrame.MissionTab.MissionList.inProgressMissions
-[1]={
-	description="The voidlords and voidcallers plaguing Shadowmoon Valley are being summoned by someone. Find and kill whoever is responsible.",
-	cost=15,
-	duration="6 hr",
-	durationSeconds=21600,
-	level=100,
-	timeLeft="1 hr 12 min",
-	type="Combat",
-	inProgress=true,
-	locPrefix="GarrMissionLocation-ShadowmoonValley",
-	rewards={
-		[251]={
-			title="Bonus Follower XP",
-			followerXP=8000,
-			tooltip="+8,000 XP",
-			icon="Interface\\Icons\\XPBonus_Icon",
-			name="+8,000 XP"
-		}
-	},
-	numRewards=1,
-	numFollowers=3,
-	state=-1,
-	iLevel=0,
-	name="Twisting the Nether",
-	followers={
-		[1]="0x000000000002F5E1",
-		[2]="0x0000000000079D62",
-		[3]="0x00000000001307EF"
-	},
-	location="Shadowmoon Valley",
-	isRare=false,
-	typeAtlas="GarrMission_MissionIcon-Combat",
-	missionID=114
-}
-Dump: value=G.GetMissionInfo(119)
-local location, xp, environment, environmentDesc, environmentTexture, locPrefix, isExhausting, enemies = C_Garrison.GetMissionInfo(missionID);
-[1]="Nagrand",
-[2]=1500,
-[3]="Orc",
-[4]="Lok'tar ogar!",
-[5]="Interface\\ICONS\\Achievement_Boss_General_Nazgrim.blp",
-[6]="GarrMissionLocation-Nagrand",
-[7]=false,
-[8]={
-	[1]={
-		portraitFileDataID=1067358,
-		displayID=56189,
-		name="Warsong Earthcaller",
-		mechanics={
-			[4]={
-				description="A dangerous harmful effect that should be dispelled.",
-				name="Magic Debuff",
-				icon="Interface\\ICONS\\Spell_Shadow_ShadowWordPain.blp"
-			},
-			[8]={
-				description="A dangerous spell that should be interrupted.",
-				name="Powerful Spell",
-				icon="Interface\\ICONS\\Spell_Shadow_ShadowBolt.blp"
-			}
-		}
+	GMC.cc = GMC.cf:CreateFontString()
+	GMC.cc:SetFontObject('GameFontNormalHuge')
+	GMC.cc:SetText('Success Chance')
+	GMC.cc:SetPoint('TOP', 0, 0)
+	GMC.cc:SetTextColor(1, 1, 1)
+
+	GMC.ct = GMC.cf:CreateFontString()
+	GMC.ct:SetFontObject('ZoneTextFont')
+	GMC.ct:SetFormattedText('%d%%',GMC.settings.minimumChance)
+	GMC.ct:SetPoint('TOP', 0, -40)
+	GMC.ct:SetTextColor(0, 1, 0)
+
+	GMC.cs = factory:Slider(GMC.cf,0,100,GMC.settings.minimumChance,'Minumum chance to start a mission')
+	GMC.cs:SetPoint('BOTTOM', 10, 0)
+	GMC.cs:SetScript('OnValueChanged', function(self, value)
+			local value = math.floor(value)
+			GMC.ct:SetText(value..'%')
+			GMC.settings.minimumChance = value
+	end)
+	GMC.cs:SetValue(GMC.settings.minimumChance)
+	GMC.ck=factory:Checkbox(GMC.cs,GMC.settings.useOneChance,"Use this percentage for all missions")
+	GMC.ck.tooltip="Unchecking this will allow you to set specific success chance for each reward type"
+	GMC.ck:SetPoint("TOPLEFT",GMC.cs,"BOTTOMLEFT",-60,-10)
+	GMC.ck:SetScript("OnClick",function(this)
+		GMC.settings.useOneChance=this:GetChecked()
+		addon:GMCRewardRefresh()
+	end)
+	return GMC.cf
+end
+local function timeslidechange(this,value)
+	local value = math.floor(value)
+	if (this.max) then
+		GMC.settings.maxDuration = max(value,GMC.settings.minDuration)
+		if (value~=GMC.settings.maxDuration) then this:SetValue(GMC.settings.maxDuration) end
+	else
+		GMC.settings.minDuration = min(value,GMC.settings.maxDuration)
+		if (value~=GMC.settings.minDuration) then this:SetValue(GMC.settings.minDuration) end
+	end
+	local c = 1-(value*(1/24))
+	if c < 0.3 then c = 0.3 end
+	GMC.mt:SetTextColor(1, c, c)
+	GMC.mt:SetFormattedText("%d-%dh",GMC.settings.minDuration,GMC.settings.maxDuration)
+end
+function addon:GMCBuildDuration()
+	-- Duration
+	GMC.tf = CreateFrame('FRAME', nil, GMC)
+	GMC.tf:SetSize(256, 180)
+	GMC.tf:SetPoint('LEFT', 80, 120)
+
+	GMC.bg = GMC.tf:CreateTexture(nil, 'BACKGROUND')
+	GMC.bg:SetTexture('Interface\\Timer\\Challenges-Logo.blp')
+	GMC.bg:SetSize(100, 100)
+	GMC.bg:SetPoint('CENTER', 0, 0)
+	GMC.bg:SetBlendMode('ADD')
+
+	GMC.tcf = GMC.tf:CreateTexture(nil, 'BACKGROUND')
+	--bb:SetTexture('Interface\\Timer\\Challenges-Logo.blp')
+	--bb:SetTexture('dungeons\\textures\\devices\\mm_clockface_01.blp')
+	GMC.tcf:SetTexture('World\\Dungeon\\Challenge\\clockRunes.blp')
+	GMC.tcf:SetSize(110, 110)
+	GMC.tcf:SetPoint('CENTER', 0, 0)
+	GMC.tcf:SetBlendMode('ADD')
+
+	GMC.mdt = GMC.tf:CreateFontString()
+	GMC.mdt:SetFontObject('GameFontNormalHuge')
+	GMC.mdt:SetText('Mission Duration')
+	GMC.mdt:SetPoint('TOP', 0, 0)
+	GMC.mdt:SetTextColor(1, 1, 1)
+
+	GMC.mt = GMC.tf:CreateFontString()
+	GMC.mt:SetFontObject('ZoneTextFont')
+	GMC.mt:SetFormattedText('%d-%dh',GMC.settings.minDuration,GMC.settings.maxDuration)
+	GMC.mt:SetPoint('CENTER', 0, 0)
+	GMC.mt:SetTextColor(1, 1, 1)
+
+	GMC.ms1 = factory:Slider(GMC.tf,0,24,GMC.settings.minDuration,'Minimum mission duration.')
+	GMC.ms2 = factory:Slider(GMC.tf,0,24,GMC.settings.maxDuration,'Maximum mission duration.')
+	GMC.ms1:SetPoint('BOTTOM', 0, 0)
+	GMC.ms2:SetPoint('TOP', GMC.ms1,"BOTTOM",0, -25)
+	GMC.ms2.max=true
+	GMC.ms1:SetScript('OnValueChanged', timeslidechange)
+	GMC.ms2:SetScript('OnValueChanged', timeslidechange)
+	timeslidechange(GMC.ms1,GMC.settings.minDuration)
+	timeslidechange(GMC.ms2,GMC.settings.maxDuration)
+	return GMC.tf
+end
+function addon:GMCBuildRewards()
+	--Allowed rewards
+	GMC.aif = CreateFrame('FRAME', nil, GMC)
+	GMC.aif:SetPoint('CENTER', 0, 120)
+
+	GMC.itf = GMC.aif:CreateFontString()
+	GMC.itf:SetFontObject('GameFontNormalHuge')
+	GMC.itf:SetText('Allowed Rewards')
+	GMC.itf:SetPoint('TOP', 0, -10)
+	GMC.itf:SetTextColor(1, 1, 1)
+
+	GMC.itf2 = GMC.aif:CreateFontString()
+	GMC.itf2:SetFontObject('GameFontHighlight')
+	GMC.itf2:SetText('Click to enable/disable a reward.')
+	GMC.itf2:SetTextColor(1, 1, 1)
+
+
+	local t = {
+		{t = 'Enable/Disable money rewards.', i = 'Interface\\Icons\\inv_misc_coin_01', key = 'gold'},
+		{t = 'Enable/Disable other currency awards. (Resources/Seals)', i= 'Interface\\Icons\\inv_garrison_resource', key = 'resources'},
+		{t = 'Enable/Disable Follower XP Bonus rewards.', i = 'Interface\\Icons\\XPBonus_Icon', key = 'xpBonus'},
+		{t = 'Enable/Disable follower equip enhancement.', i = 'Interface\\ICONS\\Garrison_ArmorUpgrade', key = 'followerUpgrade'},
+		{t = 'Enable/Disable item tokens.', i = "Interface\\ICONS\\INV_Bracer_Cloth_Reputation_C_01", key = 'itemLevel'}
 	}
-}
-local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = C_Garrison.GetPartyMissionInfo(MISSION_PAGE_FRAME.missionInfo.missionID);
-Dump: value=C_Garrison.GetPartyMissionInfo(118)
-[1]="8 hr",
-[2]=28800,
-[3]=false,
-[4]=0,
-[5]={
-},
-[6]=false,
-[7]=0,
-[8]=1
-Dump: value=table returned by GetFollowerInfo for a collected follower
-[1]={
-	displayHeight=0.5,
-	iLevel=600,
-	isCollected=true,
-	classAtlas="GarrMission_ClassIcon-Druid",
-	garrFollowerID="0x0000000000000022",
-	displayScale=1,
-	level=100,
-	quality=4,
-	portraitIconID=1066112,
-	isFavorite=false,
-	xp=0,
-	className="Guardian Druid",
-	classSpec=8,
-	name="Qiana Moonshadow",
-	followerID="0x000000000002F5E1",
-	height=1.3999999761581,
-	displayID=55047,
-	scale=0.60000002384186,
-	levelXP=0
-}
-	local location, xp, environment, environmentDesc, environmentTexture, locPrefix, isExhausting, enemies = G.GetMissionInfo(missionID)
---]]
-function addon:GetScroller(title)
+	local scale=1.1
+	GMC.ignoreFrames = {}
+	local ref
+	local h=37 -- itemButtonTemplate standard size
+	local gap=5
+	for i = 1, #t do
+			local frame = CreateFrame('BUTTON', nil, GMC.aif, 'ItemButtonTemplate')
+			frame:SetScale(scale)
+			frame:SetPoint('TOPLEFT', 0,(i) * (-h -gap) * scale)
+			frame.icon:SetTexture(t[i].i)
+			frame.key=t[i].key
+			frame.tooltip=t[i].t
+			local allowed=GMC.settings.allowedRewards[frame.key]
+			local chance=GMC.settings.rewardChance[frame.key]
+			-- Need to resave them asap in order to populate the array for future scans
+			GMC.settings.allowedRewards[frame.key]=allowed
+			GMC.settings.rewardChance[frame.key]=chance
+			frame.slider=factory:Slider(frame,0,100,chance or 100,chance or 100)
+			frame.slider:SetWidth(128)
+			frame.slider:SetPoint('BOTTOMLEFT',60,0)
+			frame.slider.Text:SetFontObject('NumberFont_Outline_Med')
+			frame.slider.Text:SetTextColor(C.Green())
+			frame.slider.isPercent=true
+			frame.slider:SetScript("OnValueChanged",function(this,value)
+				GMC.settings.rewardChance[this:GetParent().key]=this:OnValueChanged(value)
+				end
+			)
+			frame.chest = frame:CreateTexture(nil, 'BACKGROUND')
+			frame.chest:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp')
+			frame.chest:SetAtlas(chestTexture)
+			frame.chest:SetSize((209-(209*0.25))*0.30, (155-(155*0.25)) * 0.30)
+			frame.chest:SetPoint('CENTER',frame.slider, 0, 25)
+			frame:SetScript('OnClick', function(this)
+				local allowed=  this.icon:IsDesaturated() -- ID it was desaturated, I want it allowed, now
+				GMC.settings.allowedRewards[this.key] = allowed
+				addon:GMCRewardRefresh()
+			end)
+			frame:SetScript('OnEnter', function(this)
+				GameTooltip:SetOwner(this, 'ANCHOR_BOTTOMRIGHT')
+				GameTooltip:AddLine(this.tooltip);
+				GameTooltip:Show()
+			end)
+
+			frame:SetScript('OnLeave', function() GameTooltip:Hide() end)
+			GMC.ignoreFrames[i] = frame
+			ref=frame
+	end
+	self:GMCRewardRefresh()
+	GMC.aif:SetSize(256, (scale*h+gap) * #t)
+	GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', 5, -15)
+	return GMC.aif
+end
+
+local addPriorityRule,prioRefresh,removePriorityRule,prioMenu,prioTitles,prioCheck,prioVoices
+do
+-- 1 = item, 2 = folitem, 3 = exp, 4 = money, 5 = resource
+	prioTitles={
+		itemLevel="Gear Items",
+		followerUpgrade="Upgrade Items",
+		xpBonus="Follower XP Bonus",
+		gold="Gold Reward",
+		resources="Resource Rewards"
+	}
+	prioVoices=0
+	for _ in pairs(prioTitles) do prioVoices=prioVoices+1 end
+	prioMenu={}
+
+	---@function [parent=#GMC] prioRefresh
+	function prioRefresh()
+		for i=1,prioVoices do
+			local group=GMC.prioFrames[i]
+			local code=GMC.settings.itemPrio[i]
+			if (not code) then
+				group.text:Hide()
+				group.xbutton:Hide()
+				group.nr:Hide()
+			else
+				group.text:Show()
+				group.text:SetText(prioTitles[code])
+				group.xbutton:Show()
+				group.nr:Show()
+			end
+		end
+		GMC.abutton:Hide()
+		for i=1,prioVoices do
+			local group=GMC.prioFrames[i]
+			if (not group.text:IsShown()) then
+				group.nr:Show()
+				GMC.abutton:SetPoint("TOPLEFT",group.text)
+				GMC.abutton:Show()
+				break
+			end
+		end
+	end
+	---@function [parent=#GMC] addPriorityRule
+	function addPriorityRule(this,key)
+		tinsert(GMC.settings.itemPrio,key)
+		prioRefresh()
+	end
+	---@function [parent=#GMC] removePriorityRule
+	function removePriorityRule(index)
+		tremove(GMC.settings.itemPrio,index)
+		prioRefresh()
+	end
+
+end
+_G.XPRIO=prioRefresh
+function addon:GMCBuildPriorities()
+	--Prio
+	GMC.pf = CreateFrame('FRAME', nil, GMC)
+	GMC.pf:SetSize(256, 240)
+
+	GMC.pft = GMC.pf:CreateFontString()
+	GMC.pft:SetFontObject('GameFontNormalHuge')
+	GMC.pft:SetText('Item Priority')
+	GMC.pft:SetPoint('TOP', 0, -10)
+	GMC.pft:SetTextColor(1, 1, 1)
+
+	GMC.pft2 = GMC.pf:CreateFontString()
+	GMC.pft2:SetFontObject('GameFontNormal')
+	GMC.pft2:SetText('Prioritize missions with certain a reward.')
+	GMC.pft2:SetPoint('BOTTOM', 0, 16)
+	GMC.pft2:SetTextColor(1, 1, 1)
+	GMC.pmf = CreateFrame("FRAME", "GMC_PRIO_MENU", GMC.pf, "UIDropDownMenuTemplate")
+
+
+	GMC.prioFrames = {}
+	GMC.prioFrames.selected = 0
+	for i = 1, prioVoices do
+		GMC.prioFrames[i] = {}
+		local this = GMC.prioFrames[i]
+		this.f = CreateFrame('FRAME', nil, GMC.pf)
+		this.f:SetSize(255, 32)
+		this.f:SetPoint('TOP', 0, -38-((i-1)*32))
+
+		this.nr = this.f:CreateFontString()
+		this.nr:SetFontObject('GameFontNormalHuge')
+		this.nr:SetText(i..'.')
+		this.nr:SetPoint('LEFT', 8, 0)
+		this.nr:SetTextColor(1, 1, 1)
+
+		this.text = this.f:CreateFontString()
+		this.text:SetFontObject('GameFontNormalLarge')
+		this.text:SetText('Def')
+		this.text:SetPoint('LEFT', 32, 0)
+		--this.text:SetTextColor(1, 1, 0)
+		this.text:SetJustifyH('LEFT')
+		this.text:Hide()
+
+		this.xbutton = CreateFrame('BUTTON', nil, this.f, 'GameMenuButtonTemplate')
+		this.xbutton:SetPoint('RIGHT', 0, 0)
+		this.xbutton:SetText('X')
+		this.xbutton:SetWidth(28)
+		this.xbutton:SetScript('OnClick', function() removePriorityRule(i)  end)
+		this.xbutton:Hide()
+	end
+
+	GMC.abutton = CreateFrame('BUTTON', nil, GMC.pmf, 'GameMenuButtonTemplate')
+	GMC.abutton:SetText(L['Add priority rule'])
+	GMC.abutton:SetWidth(128)
+	GMC.abutton:Hide()
+	GMC.abutton:SetScript('OnClick', function()
+		wipe(prioMenu)
+		tinsert(prioMenu,{text = L["Select an item to add as priority."], isTitle = true, isNotRadio=true,disabled=true, notCheckable=true,notClickable=true})
+		for k,v in pairs(prioTitles) do
+			tinsert(prioMenu,{text = v, func = addPriorityRule, notCheckable=true, isNotRadio=true, arg1 = k , disabled=inTable(GMC.settings.itemPrio,k)})
+		end
+		EasyMenu(prioMenu, GMC.pmf, "cursor", 0 , 0, "MENU")
+		end
+	)
+	prioRefresh()
+	return GMC.pf
+end
+function addon:GMCBuildMissionList()
+		-- Mission list on follower panels
+--		local ml=CreateFrame("Frame",nil,GMC)
+--		addBackdrop(ml)
+--		ml:Show()
+--		ml.Missions={}
+--		ml.Parties={}
+--		GMC.ml=ml
+--		local fs=ml:CreateFontString(nil, "BACKGROUND", "GameFontNormalHugeBlack")
+--		fs:SetPoint("TOPLEFT",0,-5)
+--		fs:SetPoint("TOPRIGHT",0,-5)
+--		fs:SetText(READY)
+--		fs:SetTextColor(C.Green())
+--		fs:SetHeight(30)
+--		fs:SetJustifyV("CENTER")
+--		fs:Show()
+--		GMC.progressText=fs
+--		GMC.ml.Header=fs
+--		return GMC.ml
+	local ml={widget=AceGUI:Create("GMCLayer"),Parties={}}
+	ml.widget:SetTitle(READY)
+	ml.widget:SetTitleColor(C.Green())
+	ml.widget:SetTitleHeight(40)
+	ml.widget:SetParent(GMC)
+	ml.widget:Show()
+	GMC.ml=ml
+	return ml.widget
+
+end
+--@do-not-package@
+_G.GAC=addon
+--- Enable a trace for every function call. It's a VERY heavy debug
+--
+local memorysinks={}
+local lib=LibStub("LibInit")
+for k,v in pairs(addon) do
+	if (type(v))=="function" and not lib[k] then
+		local wrapped
+		do
+			local original=addon[k]
+			wrapped=function(...)
+				if trc then
+					UpdateAddOnMemoryUsage()
+				end
+				local membefore=floor(GetAddOnMemoryUsage("GarrisonCommander"))
+				local s=GetTime()
+				local a1,a2,a3,a4,a5,a6,a7,a8,a9=original(...)
+				local e=GetTime()
+				local memafter=floor(GetAddOnMemoryUsage("GarrisonCommander"))
+				memorysinks[k].mem=memorysinks[k].mem+memafter-membefore
+				memorysinks[k].calls=memorysinks[k].calls+1
+				memorysinks[k].elapsed=memorysinks[k].elapsed+e-s
+				if (memafter-membefore > 100) then
+					pp(C(k,'Red'),'used ',memafter-membefore)
+				end
+				return a1,a2,a3,a4,a5,a6,a7,a8,a9
+			end
+		end
+		addon[k]=wrapped
+		memorysinks[k]={mem=0,elapsed=0,calls=0}
+	end
+end
+function addon:ResetSinks()
+	for k,v in pairs(memorysinks) do
+		memorysinks[k].mem=0
+		memorysinks[k].calls=0
+		memorysinks[k].elapsed=0
+	end
+end
+local sorted={}
+function addon:DumpSinks()
+	local scroll=self:GetScroller("Sinks",400,1000)
+	wipe(sorted)
+	for k,v in pairs(memorysinks) do
+		if v.mem > 0 then
+			tinsert(sorted,format("Mem %06d %-80s (calls: %3d) Mem per call:%3.2f  Elapsed %3.3f (per call %3.3f)",v.mem,k,v.calls,v.mem/v.calls,v.elapsed,v.elapsed/v.calls))
+		end
+	end
+	table.sort(sorted,function(a,b) return a>b end)
+	self:cutePrint(scroll,sorted)
+end
+function addon:GetScroller(title,type,h,w)
+	h=h or 800
+	w=w or 400
+	type=type or "Frame"
 	local scrollerWindow=AceGUI:Create("Frame")
 	scrollerWindow:SetTitle(title)
 	scrollerWindow:SetLayout("Fill")
@@ -3095,126 +4289,88 @@ function addon:GetScroller(title)
 	scroll:SetFullHeight(true)
 	scrollerWindow:AddChild(scroll)
 	scrollerWindow:SetCallback("OnClose","Release")
-	scrollerWindow:SetHeight(800)
-	scrollerWindow:SetWidth(400)
+	scrollerWindow:SetHeight(h)
+	scrollerWindow:SetWidth(w)
 	scrollerWindow:SetPoint("CENTER")
 	scrollerWindow:Show()
 	return scroll
 end
-function addon:AddLabel(obj,text,...)
+function addon:AddRow(obj,text,...)
 		local l=AceGUI:Create("Label")
 		l:SetText(text)
 		l:SetColor(...)
 		l:SetFullWidth(true)
 		obj:AddChild(l)
 end
-function addon:cuttyPrint(scroll,level,k,v)
+function addon:cutePrint(scroll,level,k,v)
 	if (type(level)=="table") then
 		for k,v in pairs(level) do
-			self:cuttyPrint(scroll,"",k,v)
+			self:cutePrint(scroll,"",k,v)
 		end
 		return
 	end
 	if (type(v)=="table") then
-		self:AddLabel(scroll,level..C(k,"Azure")..":" ..C("Table","Orange"))
+		self:AddRow(scroll,level..C(k,"Azure")..":" ..C("Table","Orange"))
 		for kk,vv in pairs(v) do
-			self:cuttyPrint(scroll,level .. "  ",kk,vv)
+			self:cutePrint(scroll,level .. "  ",kk,vv)
 		end
 	else
 		if (type(v)=="string" and v:sub(1,2)=='0x') then
 			v=v.. " " ..tostring(self:GetFollowerData(v,'name'))
 		end
-		self:AddLabel(scroll,level..C(k,"White")..":" ..C(v,"Yellow"))
+		self:AddRow(scroll,level..C(k,"White")..":" ..C(v,"Yellow"))
 	end
 end
+function addon:DumpFollower(name)
+	local follower=self:GetFollowerData(name)
+	if (follower) then
+		local scroll=self:GetScroller(follower.name)
+		self:cutePrint(scroll,follower)
+	end
+
+end
 function addon:DumpFollowerMissions(missionID)
 	local scroll=self:GetScroller("FollowerMissions " .. self:GetMissionData(missionID,'name'))
-	self:cuttyPrint(scroll,followerMissions.missions[missionID])
+	self:cutePrint(scroll,followerMissions.missions[missionID])
 end
-function addon:DumpIfnored()
+function addon:DumpIgnored()
 	local scroll=self:GetScroller("Ignored")
-	self:cuttyPrint(scroll,self.privatedb.profile.ignored)
+	self:cutePrint(scroll,self.privatedb.profile.ignored)
 end
 function addon:DumpMission(missionID)
 	local scroll=self:GetScroller("MissionCache " .. self:GetMissionData(missionID,'name'))
-	self:cuttyPrint(scroll,cache.missions[missionID])
+	self:cutePrint(scroll,cache.missions[missionID])
+end
+function addon:DumpMissions()
+	local scroll=self:GetScroller("MissionCache")
+	for id,data in pairs(cache.missions) do
+		self:cutePrint(scroll,id .. '.'..data.name)
+	end
 end
 ---
 -- Debug function
 --@param missionID Identificativo missione
 function addon:DumpCounters(missionID)
 	local scroll=self:GetScroller("Counters " .. self:GetMissionData(missionID,'name'))
-	self:cuttyPrint(scroll,counters[missionID])
-	self:cuttyPrint(scroll,"Lista per follower","","")
-	self:cuttyPrint(scroll,counterFollowerIndex[missionID])
-	self:cuttyPrint(scroll,"Lista per threat","","")
-	self:cuttyPrint(scroll,counterThreatIndex[missionID])
+	self:cutePrint(scroll,counters[missionID])
+	self:cutePrint(scroll,"Lista per follower","","")
+	self:cutePrint(scroll,counterFollowerIndex[missionID])
+	self:cutePrint(scroll,"Lista per threat","","")
+	self:cutePrint(scroll,counterThreatIndex[missionID])
 end
 function addon:Dump(title,data)
 	local scroll=self:GetScroller(title)
-	self:cuttyPrint(scroll,data)
+	self:cutePrint(scroll,data)

 end
 function addon:DumpCounterers(missionID)
 	local scroll=self:GetScroller("Counterers " .. self:GetMissionData(missionID,'name'))
-	self:cuttyPrint(scroll,cache.missions[missionID].counterers)
+	self:cutePrint(scroll,cache.missions[missionID].counterers)
 end
 function addon:DumpParty(missionID)
 	local scroll=self:GetScroller("Party " .. self:GetMissionData(missionID,'name'))
-	self:cuttyPrint(scroll,parties[missionID])
-end
-function addon:GenerateTimersPeriodic()
-	return coroutine.wrap(
-		function(self)
-			repeat
-				local t=new()
-				G.GetInProgressMissions(t)
-				for index=1,#t do
-					local mission=t[index]
-					for i=1,mission.numFollowers do
-					end
-				end
-				coroutine.yield()
-			until false
-		end
-	)
-end
-function addon:GMF_OnDragStart(frame)
-	if (not self:GetBoolean('MOVEPANEL')) then return end
-	frame.IsSizingOrMoving=true
-	if (IsShiftKeyDown()) then
-		frame.IsSizing=true
-		frame:StartSizing("BOTTOMRIGHT")
-		frame:SetScript("OnUpdate",function(frame,elapsed)
-			if (frame.timepassed and frame.timepassed >1) then
-				GarrisonMissionList_UpdateMissions()
-			else
-				frame.timepassed=frame.timepassed or 0
-				frame.timepassed=frame.timepassed +elapsed
-			end
-		end)
-	else
-		frame.IsSizing=nil
-		frame:StartMoving()
-	end
-end
-function addon:GMF_OnDragStop(frame)
-	frame:StopMovingOrSizing()
-	frame:SetScript("OnUpdate",nil)
-	if (frame.IsSizing) then
-		BIGSIZEW=frame:GetWidth()
-		SIZEV=frame:GetHeight()
-		BIGBUTTON=min(BIGSIZEW*0.55,BIGSIZEW-GCSIZE)
-		SMALLBUTTON=BIGBUTTON
-		if (not self:IsFollowerList()) then
-			HybridScrollFrame_CreateButtons(frame.MissionTab.MissionList.listScroll, "GarrisonMissionListButtonTemplate", 13, -8, nil, nil, nil, -4);
-			GarrisonMissionList_Update();
-		else
-			HybridScrollFrame_CreateButtons(frame.FollowerList.listScroll, "GarrisonMissionFollowerButtonTemplate", 7, -7, nil, nil, nil, -6);
-		end
-	end
-	frame.IsSizing=nil
-	frame.IsSizingOrMoving=nil
+	self:cutePrint(scroll,parties[missionID])
 end

+_G.GCF=GCF
 --@end-do-not-package@
diff --git a/GarrisonCommander.toc b/GarrisonCommander.toc
index 980e124..6c7ff5c 100644
--- a/GarrisonCommander.toc
+++ b/GarrisonCommander.toc
@@ -24,5 +24,6 @@
 ## X-Embeds:
 embeds.xml
 localization.lua
+wowhead.lua
 GarrisonCommander.xml
 RelNotes.lua
diff --git a/GarrisonCommander.xml b/GarrisonCommander.xml
index 032901c..b02e3bd 100644
--- a/GarrisonCommander.xml
+++ b/GarrisonCommander.xml
@@ -1,133 +1,82 @@
 <Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
 ..\FrameXML\UI.xsd">
 	<Script file="GarrisonCommander.lua"/>
-	<Frame name="GarrisonCommanderBackground" virtual ="true">
-		<Layers>
-			<Layer level="BACKGROUND">
-				<Texture atlas="GarrMission_MissionParchment" useAtlasSize="true" vertTile="true" horizTile="true">
-					<Anchors>
-						<Anchor point="TOPLEFT" x="3"/>
-						<Anchor point="BOTTOMRIGHT" x="-3"/>
-					</Anchors>
-				</Texture>
-			</Layer>
-			<Layer level="BORDER">
-				<Texture atlas="_GarrMission_TopBorder" useAtlasSize="true" horizTile="true">
-					<Anchors>
-						<Anchor point="TOPLEFT" x="20" y="4"/>
-						<Anchor point="TOPRIGHT" x="-20" y="4"/>
-					</Anchors>
-				</Texture>
-				<Texture atlas="_GarrMission_TopBorder" useAtlasSize="true" horizTile="true">
-					<Anchors>
-						<Anchor point="BOTTOMLEFT" x="20" y="-4"/>
-						<Anchor point="BOTTOMRIGHT" x="-20" y="-4"/>
-					</Anchors>
-					<TexCoords left="0.0" right="1.0" top="1.0" bottom="0.0"/>
-				</Texture>
-			</Layer>
-			<Layer level="BORDER" textureSubLevel="1">
-				<Texture atlas="GarrMission_TopBorderCorner" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="TOPLEFT" x="-5" y="4"/>
-					</Anchors>
-				</Texture>
-				<Texture atlas="GarrMission_TopBorderCorner" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="TOPRIGHT" x="4" y="4"/>
-					</Anchors>
-					<TexCoords left="1.0" right="0.0" top="0.0" bottom="1.0"/>
-				</Texture>
-				<Texture atlas="GarrMission_TopBorderCorner" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="BOTTOMLEFT" x="-5" y="-4"/>
-					</Anchors>
-					<TexCoords left="0.0" right="1.0" top="1.0" bottom="0.0"/>
-				</Texture>
-				<Texture atlas="GarrMission_TopBorderCorner" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="BOTTOMRIGHT" x="4" y="-4"/>
-					</Anchors>
-					<TexCoords left="1.0" right="0.0" top="1.0" bottom="0.0"/>
-				</Texture>
-			</Layer>
-			<Layer level="BACKGROUND" textureSubLevel="3">
-				<Texture parentKey="IconBG" atlas="Garr_MissionList-IconBG">
-					<Size x="90" y="80"/>
-					<Anchors>
-						<Anchor point="TOPLEFT" y="-1"/>
-					</Anchors>
-					<Color r="0" g="0" b="0" a="0.4"/>
-				</Texture>
-			</Layer>
-			<Layer level="ARTWORK" textureSubLevel="2">
-				<Texture parentKey="LocBG">
-					<Size x="792" y="78"/>
-					<Anchors>
-						<Anchor point="RIGHT"/>
-					</Anchors>
-				</Texture>
-			</Layer>
-				<Layer level="HIGHLIGHT" textureSubLevel="1">
-				<Texture parentKey="HighlightTL" atlas="GarrMission_TopBorderCorner-Highlight" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="TOPLEFT" x="-5" y="4"/>
-					</Anchors>
-				</Texture>
-				<Texture parentKey="HighlightTR" atlas="GarrMission_TopBorderCorner-Highlight" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="TOPRIGHT" x="4" y="4"/>
-					</Anchors>
-					<TexCoords left="1.0" right="0.0" top="0.0" bottom="1.0"/>
-				</Texture>
-				<Texture parentKey="HighlightBL" atlas="GarrMission_TopBorderCorner-Highlight" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="BOTTOMLEFT" x="-5" y="-4"/>
-					</Anchors>
-					<TexCoords left="0.0" right="1.0" top="1.0" bottom="0.0"/>
-				</Texture>
-				<Texture parentKey="HighlightBR" atlas="GarrMission_TopBorderCorner-Highlight" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="BOTTOMRIGHT" x="4" y="-4"/>
-					</Anchors>
-					<TexCoords left="1.0" right="0.0" top="1.0" bottom="0.0"/>
-				</Texture>
-				<Texture parentKey="Highlight" atlas="GarrMission_ListGlow-Highlight" useAtlasSize="true">
-					<Anchors>
-						<Anchor point="TOPLEFT" y="0"/>
-						<Anchor point="TOPRIGHT" y="0"/>
-					</Anchors>
-				</Texture>
-			</Layer>
-		</Layers>
-	</Frame>
-	<Frame name="GarrisonCommanderTitle" inherits="GarrisonCommanderBackground" virtual="true">
-		<Size x="150" y="32"/>
+	<Button name="GarrisonCommanderWhatsNew" inherits="UIPanelInfoButton" hidden="true" virtual="true">
+		<Scripts>
+			<OnLeave>GameTooltip:FadeOut()</OnLeave>
+			<OnEnter>
+				if self.tooltip then
+					GameTooltip:SetOwner(self,"ANCHOR_TOPLEFT")
+					GameTooltip:AddLine(self.tooltip)
+					GameTooltip:Show()
+				end
+			</OnEnter>
+		</Scripts>
+	</Button>
+	<Frame name="GarrisonCommanderTitle" inherits="GarrisonUITemplate" enableMouse="true" topevel="true" hidden="true" virtual="true">
+		<Size x="150" y="85"/>
 		<Frames>
-			<Button parentKey="help" inherits="UIPanelInfoButton">
+			<CheckButton parentKey="Pin">
+					<Size x="32" y="32" />
 				<Anchors>
-					<Anchor point="TOPLEFT" x="0" y="0"/>
+					<Anchor point="TOPRIGHT" x="4" y="5"/>
 				</Anchors>
-			</Button>
+				<NormalTexture file="Interface\CHATFRAME\UI-ChatIcon-ScrollUp-Up">
+					<Size x="32" y="32" />
+				</NormalTexture>
+				<!--
+				<HighlightTexture file="Interface\CHATFRAME/UI-ChatIcon-BlinkHilight" alphaMode="ADD">
+					<Size x="32" y="32" />
+				</HighlightTexture>
+				-->
+				<CheckedTexture file="Interface\CHATFRAME\UI-ChatIcon-ScrollDown-Up">
+					<Size x="32" y="32" />
+				</CheckedTexture>
+				<Scripts>
+					<OnLeave>
+						GameTooltip:FadeOut()
+					</OnLeave>
+				</Scripts>
+			</CheckButton>
 		</Frames>
 		<Layers>
-			<Layer level="ARTWORK">
+			<Layer level="OVERLAY">
 				<Texture parentKey="Shield" file="Interface\ACHIEVEMENTFRAME\UI-ACHIEVEMENT-SHIELDS-NOPOINTS">
 					<Size x="32" y="32"/>
 					<Anchors>
-						<Anchor point="TOPLEFT" x="24" y="-5"/>
+						<Anchor point="TOPLEFT" x="-2" y="0"/>
 					</Anchors>
 					<TexCoords left="0" right="0.5" top="0.5" bottom="1"/>
 				</Texture>
-				<FontString parentKey="Signature" inherits="QuestTitleFontBlackShadow" justifyH="LEFT" justifyV="TOP" text="Garrison Commander" >
-					<Size x="200" y="32"/>
+				<FontString parentKey="Signature" inherits="QuestTitleFontBlackShadow" justifyH="RIGHT" justifyV="TOP" text="Garrison Commander" >
+					<Size x="220" y="80"/>
 					<Anchors>
-						<Anchor point="TOPLEFT" relativeKey="$parent.Shield" relativePoint="TOPRIGHT" x="5" y="0"/>
+						<Anchor point="TOPRIGHT"  x="-30" y="-2"/>
 					</Anchors>
 				</FontString>
 			</Layer>
 		</Layers>
+		<Scripts>
+			<OnLeave>GameTooltip:FadeOut()</OnLeave>
+			<OnEnter>
+				if self.tooltip then
+					GameTooltip:SetOwner(self,"ANCHOR_TOPLEFT")
+					GameTooltip:AddLine(self.tooltip)
+					GameTooltip:Show()
+				end
+			</OnEnter>
+		</Scripts>
 	</Frame>
+	<Button name="GarrisonCommanderMissionPageFollowerTemplateSmall" virtual="true">
+		<Size x="70" y="58"/>
+		<Frames>
+			<Frame parentKey="PortraitFrame" inherits="GarrisonFollowerMissionPortraitTemplate">
+				<Anchors>
+					<Anchor point="LEFT"/>
+				</Anchors>
+			</Frame>
+		</Frames>
+	</Button>
 	<Button name="GarrisonCommanderMissionPageFollowerTemplate" inherits="GarrisonMissionPageFollowerTemplate" virtual="true">
 		<Size x="170" y="58"/>
 		<Layers>
@@ -195,25 +144,40 @@
 			</Layer>
 		</Layers>
 	</Frame>
-	<Button name="GarrisonCommanderMissionButton" inherits="GarrisonCommanderBackground" virtual="true">
-		<Size x="600" y="80"/>
+	<Frame name="GarrisonCommanderIndicators" toplevel="true" virtual="true">
+		<Size x="90" y="80"/>
 		<Layers>
 			<Layer level="ARTWORK">
 				<FontString parentKey="Age" inherits="GameFontHighlightSmall" justifyH="CENTER" justifyV="TOP" >
-					<Size x="60" y="70"/>
+					<Size x="90" y="70"/>
 					<Anchors>
-						<Anchor point="TOPLEFT" relativeKey="$parent" relativePoint="TOPLEFT" x="10" y="-5"/>
+						<Anchor point="TOPLEFT" relativeKey="$parent" relativePoint="TOPLEFT" x="0" y="-5"/>
 					</Anchors>
 					<Color r="0.698" g="0.941" b="1" a="1"/>
 				</FontString>
 				<FontString parentKey="Percent" inherits="NumberFontNormalHuge" justifyH="RIGHT" justifyV="BOTTOM" >
-					<Size x="60" y="70"/>
+					<Size x="90" y="70"/>
 					<Anchors>
 						<Anchor point="BOTTOMLEFT" relativeKey="$parent" relativePoint="BOTTOMLEFT" x="0" y="10"/>
 					</Anchors>
 				</FontString>
 			</Layer>
 		</Layers>
+	</Frame>
+	<Button name="GarrisonCommanderMissionButton"  virtual="true">
+		<Size x="1" y="80"/>
+		<Layers>
+			<Layer level="OVERLAY" >
+				<FontString parentKey="NotFull" inherits="GameFontHighlightSmall" justifyH="CENTER" justifyV="CENTER" text="GARRISON_PARTY_NOT_FULL_TOOLTIP" >
+					<Size x="100" y="58"/>
+					<Anchors>
+						<Anchor point="TOPLEFT" relativeKey="$parent.PortraitFrame" relativePoint="TOPRIGHT" x="0" y="0"/>
+						<Anchor point="TOPRIGHT" relativeKey="$parent" relativePoint="TOPRIGHT" x="-10" y="0"/>
+					</Anchors>
+					<Color r="1.0" g="0.0" b="0.0" a="0.5" />
+				</FontString>
+			</Layer>
+		</Layers>
 	</Button>
 	<Button name="GarrisonCommanderMissionListButtonTemplate" inherits="GarrisonMissionListButtonTemplate" virtual="true">
 		<Size x="450" y="80" />
@@ -380,5 +344,20 @@
 			</OnHide>
 		</Scripts>
 	</Frame>
-
+	<Frame name="GarrisonCommanderLoadingFrame" inherits="LoadingSpinnerTemplate" hidden="true" virtual="true">
+		<Layers>
+			<Layer level="ARTWORK">
+				<FontString parentKey="Label" inherits="GameFontHighlight" text="LFG_LIST_LOADING">
+					<Anchors>
+						<Anchor point="LEFT" relativePoint="RIGHT"/>
+					</Anchors>
+				</FontString>
+			</Layer>
+		</Layers>
+		<Scripts>
+			<OnLoad>
+				self.Anim:Play();
+			</OnLoad>
+		</Scripts>
+	</Frame>
 </Ui>
\ No newline at end of file
diff --git a/doc.txt b/doc.txt
new file mode 100644
index 0000000..fb27416
--- /dev/null
+++ b/doc.txt
@@ -0,0 +1,254 @@
+GarrisonMissionFrame_CheckCompleteMissions(OnShow) Controlla se sono presenti missione complete. Se è già mostrato GMF.MissionComplete ritorna
+	Viene chiamato
+	1) su onshow del pannello missioni con OnShow=true
+	2) sull'evento GARRISON_MISSION_FINISHED con OnSHow=false
+	- Inizializza GMF.MissionComplete.completeMissions
+	- Se ci sono missioni complete e GMF è mostrato
+		- le conta (#GMF.MissionComplete.completeMissions
+		- mostra GMF.MissionTab.MissionList.CompleteDialog
+		- MissionCompletePreload_LoadMission(id) id=missionID prima missione completata
+			- Usa una globale per la missione corrente, in modo da uscire se è sempre farlo sulla stessa
+			- Rimuove eventuali modelli già prensenti via MissionCompletePreload_Cancel
+			- Carica tutti i modelli necessari
+		- abilita il viewbutton GarrisonMissionFrameMissions.CompleteDialog.BorderFrame.ViewButton
+			- Onclick :
+				- GarrisonMissionFrame_ShowCompleteMissions
+					- continua a farsi rilanciare finché non ha finito di caricare i modelli, poi:
+					- Nasconde GMF.MissionTab.MissionList.CompleteDialog
+					- mostra GMF.MissionComplete GMF.MissionCompleteBackground
+					- GarrisonMissionComplete_Initialize(GMF.MissionComplete.completeMissions,GMF.MissionComplete.currentIndex)
+
+
+
+Altre utilities
+
+GarrisonMissionFrame_SelectTab(id): switcha fra missioni e followers
+	id è numerico, 1 mostra le missioni, altro mostra i followers
+
+GarrisonMissionList_SetTab(tab): switcha fra active e available
+	tab è l'oggetto tab "available" o "in progress" (GarrisonMissionFrameMissionsTab[12])
+
+Pannelli utili:
+
+GMF.MissionTab.MissionList.CompleteDialog.BorderFrame.LoadingFrame Loading col tondino
+
+
+Dump: value=C_Garrison.GetMissionRewardInfo(91)
+[1]={
+	[163]={
+		itemID=112848,
+		quantity=1
+	}
+}
+
+--[[
+
+GMFMissions.CompleteDialog.BorderFrame.CompleteAll
+Garrison page structure
+Tab selection:
+Managed by
+GarrisonMissionFrameTab(1|2) onclick:
+->GarrisonMissionFrameTab_OnClick(self)
+--->GarrisonMissionFrame_SelectTab(self:GetID()) - 1 for Missions, 2 for followers
+
+Main Container is GarrisonMissionFrame
+Followers tab selected:
+->GarrisonMissionFrameFollowers -> anchored GarrisonMissionFrame TOPLEFT 33,-64
+-->GarrisonMissionFrameFollowersListScrollFrame
+--->GarrisonMissionFrameFollowersListScrooFrameScrollChild
+---->GarrisonMissionFrameFollowersListScrooFrameButton(1..9)
+->GarrisonMissionFrame.FollowerTab -> abcuored GarrisonMissionFrame TOPRIGHT -35 -64
+Missions tab selected
+->GarrisonMissionFrameMissions -> anchored (parent)e TOPLEFT 35,-65
+
+
+
+
+GarrisonMissionFrameMissionsListScrollFrameButtonx.info:
+Dump: value=GarrisonMissionFrameMissionsListScrollFrameButton1.info
+[1]={
+	description="In a remote corner of Talador, a small faction of draenei has embraced the worship of Sargeras. Stop their cult before it spreads.",
+	cost=10,
+	duration="4 hr",
+	durationSeconds=14400,
+	level=100,
+	type="Combat",
+	locPrefix="GarrMissionLocation-Talador",
+	rewards={
+		[290]={
+			title="Money Reward",
+			quantity=600000,
+			icon="Interface\\Icons\\inv_misc_coin_01",
+			currencyID=0
+		}
+	},
+	numRewards=1,
+	numFollowers=2,
+	state=-2,
+	iLevel=0,
+	name="Cult of Sargeras",
+	followers={
+	},
+	location="Talador",
+	isRare=false,
+	typeAtlas="GarrMission_MissionIcon-Combat",
+	missionID=126
+}
+Dump: value=G.GetFollowerInfo("0x000000000002F5E1")
+[1]={
+	displayHeight=0.5,
+	iLevel=600,
+	scale=0.60000002384186,
+	classAtlas="GarrMission_ClassIcon-Druid",
+	garrFollowerID="0x0000000000000022",
+	displayScale=1,
+	status="On Mission",
+	level=100,
+	quality=4,
+	portraitIconID=1066112,
+	isFavorite=false,
+	xp=0,
+	className="Guardian Druid",
+	classSpec=8,
+	name="Qiana Moonshadow",
+	followerID="0x000000000002F5E1",
+	height=1.3999999761581,
+	displayID=55047,
+	levelXP=0,
+	isCollected=true
+}
+value=GarrisonMissionFrame.MissionTab.MissionList.availableMissions[13]
+[1]={
+	description="Scouts report a many-headed beast named Festerbloom waylaying travelers crossing the Murkbog.  Clear the path for everyone's sake.",
+	cost=20,
+	duration="10 hr",
+	durationSeconds=36000,
+	level=96,
+	type="Combat",
+	locPrefix="GarrMissionLocation-SpiresofArak",
+	rewards={
+		[778]={
+			title="Bonus Follower XP",
+			followerXP=1400,
+			tooltip="+1,400 XP",
+			icon="Interface\\Icons\\XPBonus_Icon",
+			name="+1,400 XP"
+		}
+	},
+	numRewards=1,
+	numFollowers=3,
+	state=-2,
+	iLevel=0,
+	name="Murkbog Terror",
+	followers={
+	},
+	location="Spires of Arak",
+	isRare=false,
+	typeAtlas="GarrMission_MissionIcon-Combat",
+	missionID=374
+}
+Dump: value=GarrisonMissionFrame.MissionTab.MissionList.inProgressMissions
+[1]={
+	description="The voidlords and voidcallers plaguing Shadowmoon Valley are being summoned by someone. Find and kill whoever is responsible.",
+	cost=15,
+	duration="6 hr",
+	durationSeconds=21600,
+	level=100,
+	timeLeft="1 hr 12 min",
+	type="Combat",
+	inProgress=true,
+	locPrefix="GarrMissionLocation-ShadowmoonValley",
+	rewards={
+		[251]={
+			title="Bonus Follower XP",
+			followerXP=8000,
+			tooltip="+8,000 XP",
+			icon="Interface\\Icons\\XPBonus_Icon",
+			name="+8,000 XP"
+		}
+	},
+	numRewards=1,
+	numFollowers=3,
+	state=-1,
+	iLevel=0,
+	name="Twisting the Nether",
+	followers={
+		[1]="0x000000000002F5E1",
+		[2]="0x0000000000079D62",
+		[3]="0x00000000001307EF"
+	},
+	location="Shadowmoon Valley",
+	isRare=false,
+	typeAtlas="GarrMission_MissionIcon-Combat",
+	missionID=114
+}
+Dump: value=G.GetMissionInfo(119)
+local location, xp, environment, environmentDesc, environmentTexture, locPrefix, isExhausting, enemies = C_Garrison.GetMissionInfo(missionID);
+[1]="Nagrand",
+[2]=1500,
+[3]="Orc",
+[4]="Lok'tar ogar!",
+[5]="Interface\\ICONS\\Achievement_Boss_General_Nazgrim.blp",
+[6]="GarrMissionLocation-Nagrand",
+[7]=false,
+[8]={
+	[1]={
+		portraitFileDataID=1067358,
+		displayID=56189,
+		name="Warsong Earthcaller",
+		mechanics={
+			[4]={
+				description="A dangerous harmful effect that should be dispelled.",
+				name="Magic Debuff",
+				icon="Interface\\ICONS\\Spell_Shadow_ShadowWordPain.blp"
+			},
+			[8]={
+				description="A dangerous spell that should be interrupted.",
+				name="Powerful Spell",
+				icon="Interface\\ICONS\\Spell_Shadow_ShadowBolt.blp"
+			}
+		}
+	}
+}
+local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = C_Garrison.GetPartyMissionInfo(MISSION_PAGE_FRAME.missionInfo.missionID);
+Dump: value=C_Garrison.GetPartyMissionInfo(118)
+[1]="8 hr",
+[2]=28800,
+[3]=false,
+[4]=0,
+[5]={
+},
+[6]=false,
+[7]=0,
+[8]=1
+Dump: value=table returned by GetFollowerInfo for a collected follower
+[1]={
+	displayHeight=0.5,
+	iLevel=600,
+	isCollected=true,
+	classAtlas="GarrMission_ClassIcon-Druid",
+	garrFollowerID="0x0000000000000022",
+	displayScale=1,
+	level=100,
+	quality=4,
+	portraitIconID=1066112,
+	isFavorite=false,
+	xp=0,
+	className="Guardian Druid",
+	classSpec=8,
+	name="Qiana Moonshadow",
+	followerID="0x000000000002F5E1",
+	height=1.3999999761581,
+	displayID=55047,
+	scale=0.60000002384186,
+	levelXP=0
+}
+	local location, xp, environment, environmentDesc, environmentTexture, locPrefix, isExhausting, enemies = G.GetMissionInfo(missionID)
+--]]
+-- In case we need to change rown number in GMF
+		if (not self:IsFollowerList()) then
+			HybridScrollFrame_CreateButtons(frame.MissionTab.MissionList.listScroll, "GarrisonMissionListButtonTemplate", 13, -8, nil, nil, nil, -4);
+			GarrisonMissionList_Update();
+		else
+			HybridScrollFrame_CreateButtons(frame.FollowerList.listScroll, "GarrisonMissionFollowerButtonTemplate", 7, -7, nil, nil, nil, -6);
+		end
diff --git a/example.js b/example.js
new file mode 100644
index 0000000..f2f1df2
--- /dev/null
+++ b/example.js
@@ -0,0 +1,3 @@
+/**
+ *
+ */
\ No newline at end of file
diff --git a/wowhead.lua b/wowhead.lua
new file mode 100644
index 0000000..a8aa0ad
--- /dev/null
+++ b/wowhead.lua
@@ -0,0 +1,408 @@
+-- DataMined from WowHead on 11/01/2015
+-- Contains 304 missions
+--[[
+Array
+(
+    [id] => 2
+    [level] => 90
+    [itemlevel] => 0
+    [traveltime] => 0
+    [missiontime] => 1800
+    [cooldown] => 9999999
+    [cost] => 0
+    [followers] => 1
+    [experience] => 100
+    [basebonuschance] => 65
+    [name] => Gronnlings Abound
+    [description] => Gronnlings are a menace to the region.  We should partner with the Frostwolf clan to thin the population.  One may even join our cause...
+    [location] => Frostwall Approach
+    [mechanictype] => 23
+    [missiontype] => 3
+    [flags] => 0
+    [rewards] => Array
+        (
+            [experience] => Array
+                (
+                )
+
+            [prestige] => Array
+                (
+                )
+
+            [item] => Array
+                (
+                    [0] => Array
+                        (
+                            [item] => 112737
+                            [amount] => 1
+                        )
+
+                )
+
+            [currency] => Array
+                (
+                )
+
+            [chest] => Array
+                (
+                )
+
+        )
+
+    [encounters] => Array
+        (
+            [1] => Array
+                (
+                    [setkey] => 2
+                    [id] => 1
+                    [npc] => 80693
+                    [name] => Frostfire Gronnling
+                    [portraitfile] => 1067373
+                    [portraitfilename] => enemyportrait_56633
+                    [mechanics] => Array
+                        (
+                            [10] => Array
+                                (
+                                    [setkey] => 2
+                                    [id] => 10
+                                    [amount] => 300
+                                    [type] => 1
+                                    [category] => 2
+                                    [name] => Wild Aggression
+                                    [description] => An unpredictable enemy whose aggression should be controlled.
+                                    [icon] => spell_nature_reincarnation
+                                )
+
+                        )
+
+                )
+
+        )
+
+    [mechanics] => Array
+        (
+            [0] => Array
+                (
+                    [setkey] => 2
+                    [id] => 0
+                    [amount] => 0
+                    [type] => 23
+                    [category] => 0
+                    [name] => Snow
+                    [description] => An arctic region.
+                    [icon] => achievement_zone_stormpeaks_02
+                )
+
+        )
+
+)
+--]]
+local me,ns=...
+ ns.wowhead={
+[2]=9999999,
+[3]=9999999,
+[6]=9999999,
+[7]=9999999,
+[43]=9999999,
+[44]=9999999,
+[55]=9999999,
+[65]=9999999,
+[66]=9999999,
+[67]=0,
+[73]=86400,
+[86]=9999999,
+[87]=9999999,
+[88]=9999999,
+[89]=0,
+[90]=9999999,
+[91]=9999999,
+[107]=129600,
+[108]=129600,
+[109]=129600,
+[110]=129600,
+[111]=129600,
+[112]=129600,
+[113]=129600,
+[114]=129600,
+[115]=129600,
+[116]=129600,
+[117]=129600,
+[118]=129600,
+[119]=129600,
+[120]=129600,
+[125]=129600,
+[126]=129600,
+[127]=129600,
+[128]=129600,
+[129]=129600,
+[130]=129600,
+[131]=129600,
+[132]=129600,
+[133]=129600,
+[135]=86400,
+[136]=86400,
+[137]=86400,
+[138]=86400,
+[139]=86400,
+[140]=86400,
+[141]=86400,
+[142]=86400,
+[143]=86400,
+[144]=86400,
+[145]=86400,
+[146]=86400,
+[147]=86400,
+[148]=86400,
+[149]=86400,
+[150]=86400,
+[151]=86400,
+[152]=86400,
+[153]=86400,
+[154]=86400,
+[155]=86400,
+[156]=86400,
+[157]=86400,
+[158]=86400,
+[159]=86400,
+[160]=86400,
+[161]=86400,
+[162]=86400,
+[163]=86400,
+[164]=86400,
+[165]=86400,
+[166]=86400,
+[167]=86400,
+[168]=86400,
+[169]=86400,
+[170]=86400,
+[171]=86400,
+[172]=86400,
+[173]=86400,
+[174]=86400,
+[175]=86400,
+[176]=86400,
+[177]=86400,
+[178]=86400,
+[179]=86400,
+[180]=86400,
+[181]=86400,
+[182]=86400,
+[183]=86400,
+[184]=86400,
+[185]=86400,
+[186]=86400,
+[187]=86400,
+[188]=86400,
+[189]=86400,
+[190]=86400,
+[191]=86400,
+[192]=86400,
+[193]=86400,
+[194]=86400,
+[195]=86400,
+[196]=86400,
+[197]=86400,
+[198]=86400,
+[199]=86400,
+[200]=86400,
+[201]=86400,
+[202]=86400,
+[203]=86400,
+[204]=86400,
+[205]=86400,
+[206]=86400,
+[207]=86400,
+[208]=86400,
+[209]=86400,
+[210]=86400,
+[211]=86400,
+[212]=86400,
+[213]=86400,
+[214]=86400,
+[215]=86400,
+[217]=86400,
+[218]=86400,
+[219]=86400,
+[220]=86400,
+[221]=9999999,
+[222]=9999999,
+[223]=86400,
+[224]=86400,
+[228]=9999999,
+[229]=9999999,
+[230]=86400,
+[231]=86400,
+[232]=86400,
+[242]=86400,
+[243]=86400,
+[244]=86400,
+[245]=86400,
+[247]=129600,
+[248]=129600,
+[249]=129600,
+[250]=129600,
+[251]=129600,
+[252]=129600,
+[253]=129600,
+[254]=129600,
+[255]=129600,
+[256]=129600,
+[257]=129600,
+[258]=129600,
+[259]=129600,
+[260]=129600,
+[261]=129600,
+[262]=129600,
+[263]=129600,
+[264]=129600,
+[265]=129600,
+[266]=129600,
+[267]=129600,
+[268]=129600,
+[269]=129600,
+[271]=86400,
+[272]=86400,
+[273]=86400,
+[274]=86400,
+[275]=86400,
+[276]=86400,
+[277]=86400,
+[278]=86400,
+[279]=86400,
+[280]=86400,
+[281]=86400,
+[282]=86400,
+[283]=86400,
+[284]=86400,
+[285]=86400,
+[286]=86400,
+[287]=86400,
+[288]=86400,
+[289]=86400,
+[290]=129600,
+[291]=129600,
+[292]=129600,
+[293]=129600,
+[294]=129600,
+[295]=129600,
+[296]=129600,
+[297]=129600,
+[298]=129600,
+[299]=129600,
+[300]=129600,
+[301]=129600,
+[302]=129600,
+[303]=129600,
+[304]=129600,
+[305]=129600,
+[306]=129600,
+[307]=129600,
+[308]=129600,
+[309]=129600,
+[310]=129600,
+[311]=129600,
+[312]=129600,
+[313]=1209000,
+[314]=1209000,
+[315]=1209000,
+[316]=1209000,
+[317]=1209000,
+[318]=1209000,
+[319]=1209000,
+[320]=1209000,
+[321]=1209000,
+[322]=1209000,
+[323]=1209000,
+[324]=1209000,
+[325]=1209000,
+[326]=1209000,
+[327]=1209000,
+[328]=1209000,
+[329]=86400,
+[330]=86400,
+[331]=86400,
+[332]=86400,
+[333]=86400,
+[334]=252000,
+[335]=252000,
+[336]=252000,
+[337]=252000,
+[338]=86400,
+[339]=86400,
+[340]=86400,
+[341]=86400,
+[342]=86400,
+[343]=86400,
+[344]=86400,
+[345]=86400,
+[346]=86400,
+[347]=86400,
+[348]=86400,
+[349]=86400,
+[350]=86400,
+[351]=86400,
+[352]=86400,
+[353]=86400,
+[354]=86400,
+[355]=86400,
+[356]=86400,
+[357]=86400,
+[358]=252000,
+[359]=252000,
+[360]=252000,
+[361]=252000,
+[362]=86400,
+[363]=86400,
+[364]=86400,
+[365]=86400,
+[366]=57600,
+[367]=57600,
+[368]=57600,
+[369]=57600,
+[370]=57600,
+[371]=57600,
+[372]=57600,
+[373]=57600,
+[374]=57600,
+[375]=57600,
+[376]=57600,
+[377]=57600,
+[378]=86400,
+[379]=86400,
+[380]=129600,
+[381]=86400,
+[382]=86400,
+[383]=86400,
+[384]=86400,
+[385]=129600,
+[386]=86400,
+[387]=86400,
+[388]=86400,
+[389]=86400,
+[390]=86400,
+[391]=86400,
+[392]=86400,
+[393]=86400,
+[394]=86400,
+[395]=86400,
+[396]=86400,
+[397]=86400,
+[398]=86400,
+[399]=86400,
+[400]=86400,
+[401]=86400,
+[402]=86400,
+[403]=1209000,
+[404]=1209000,
+[405]=1209000,
+[406]=1209000,
+[407]=1209000,
+[408]=1209000,
+[409]=1209000,
+[410]=1209000,
+[411]=1209000,
+[412]=1209000,
+[413]=1209000,
+_lastupdate_=1421009516
+}
+setmetatable(ns.wowhead,{__index=function(t,k) return 0 end})