From 6abc792eb0b260d171f651fb2e17a15cea1cd97f Mon Sep 17 00:00:00 2001 From: Alex Shubert Date: Mon, 2 Apr 2012 23:02:20 +0400 Subject: [PATCH] fixed defect in logic, when was saved En constants, while item information returns localized (see prev. commit for detail). Everything works fine except:1. need to introduce relics handle, 2. may be there are any real way to load items if they aren't in a cache. See TryToLoadRewards() for details --- AutoTurnIn.lua | 279 +++++++++++++++++++++++++++++------------------------ RewardOptions.lua | 41 ++++---- rewards.lua | 53 +++++----- 3 files changed, 203 insertions(+), 170 deletions(-) diff --git a/AutoTurnIn.lua b/AutoTurnIn.lua index 0a1ddb8..7d56f67 100644 --- a/AutoTurnIn.lua +++ b/AutoTurnIn.lua @@ -11,8 +11,12 @@ local ldbstruct = { label = addonName, text = addonName, OnClick = function(clickedframe, button) - if InterfaceOptionsFrame:IsVisible() then - InterfaceOptionsFrameCancel:Click() + if InterfaceOptionsFrame:IsVisible() then + if (InterfaceOptionsFrameAddOns.selection:GetName() == "AutoTurnInOptionsPanel") then + InterfaceOptionsFrame_OpenToCategory(_G["AutoTurnInRewardPanel"]) + elseif (InterfaceOptionsFrameAddOns.selection:GetName() == "AutoTurnInRewardPanel") then + InterfaceOptionsFrameCancel:Click() + end else InterfaceOptionsFrame_OpenToCategory(_G["AutoTurnInOptionsPanel"]) end @@ -22,7 +26,7 @@ local ldbstruct = { local caption = addonName ..' [%s]' function AutoTurnIn:SetEnabled(enabled) AutoTurnInCharacterDB.enabled = not not enabled - if AutoTurnIn.ldb then + if AutoTurnIn.ldb then AutoTurnIn.ldb.text = caption:format((AutoTurnInCharacterDB.enabled) and 'on' or 'off' ) AutoTurnIn.ldb.label = AutoTurnIn.ldb.text end @@ -31,24 +35,27 @@ end function AutoTurnIn:OnEnable() local vers = GetAddOnMetadata(addonName, "Version") - if (not AutoTurnInDB) or (not AutoTurnInDB.version or (AutoTurnInDB.version < vers)) then + if (not AutoTurnInDB) or (not AutoTurnInDB.version or (AutoTurnInDB.version < vers)) then AutoTurnInCharacterDB = nil _G.AutoTurnInDB = {version = vers} self:Print(L["reset"]) end - - if not AutoTurnInCharacterDB then - _G.AutoTurnInCharacterDB = CopyTable(AutoTurnIn.defaults) + + if not AutoTurnInCharacterDB then + _G.AutoTurnInCharacterDB = CopyTable(AutoTurnIn.defaults) + end + if (tonumber(AutoTurnInCharacterDB.dontloot) == nil) then + AutoTurnInCharacterDB.dontloot = 1 end - if (tonumber(AutoTurnInCharacterDB.togglekey) == nil) then + if (tonumber(AutoTurnInCharacterDB.togglekey) == nil) then AutoTurnInCharacterDB.togglekey = 1 end - if ( AutoTurnInCharacterDB.items == nil ) then + if ( AutoTurnInCharacterDB.items == nil ) then AutoTurnInCharacterDB.items = {} end - + local LDB = LibStub:GetLibrary("LibDataBroker-1.1", true) - if LDB then + if LDB then AutoTurnIn.ldb = LDB:NewDataObject("AutoTurnIn", ldbstruct) end @@ -74,7 +81,7 @@ end local p1 = {[true]=L["enabled"], [false]=L["disabled"]} local p2 = {[true]=L["all"], [false]=L["list"]} -function AutoTurnIn:ConsoleComand(arg) +function AutoTurnIn:ConsoleComand(arg) arg = strlower(arg) if (#arg == 0) then InterfaceOptionsFrame_OpenToCategory(_G["AutoTurnInOptionsPanel"]) @@ -84,14 +91,14 @@ function AutoTurnIn:ConsoleComand(arg) elseif arg == "off" then self:SetEnabled(false) self:Print(L["disabled"]) - elseif arg == "all" then + elseif arg == "all" then AutoTurnInCharacterDB.all = true self:Print(L["all"]) - elseif arg == "list" then + elseif arg == "list" then AutoTurnInCharacterDB.all = false self:Print(L["list"]) - elseif arg == "help" then - self:Print(p1[AutoTurnInCharacterDB.enabled == true]) + elseif arg == "help" then + self:Print(p1[AutoTurnInCharacterDB.enabled == true]) self:Print(p2[AutoTurnInCharacterDB.all]) end end @@ -99,14 +106,14 @@ end local function GetItemAmount(isCurrency, item) local amount = isCurrency and select(2, GetCurrencyInfo(item)) or GetItemCount(item, nil, true) return amount and amount or 0 -end +end local funcList = {[1] = function() return false end, [2]=IsAltKeyDown, [3]=IsControlKeyDown, [4]=IsShiftKeyDown} local function AllowedToHandle(forcecheck) - if ( AutoTurnIn.allowed == nil or forcecheck ) then + if ( AutoTurnIn.allowed == nil or forcecheck ) then -- Double 'not' converts possible 'nil' to boolean representation local IsModifiedClick = not not funcList[AutoTurnInCharacterDB.togglekey]() - -- it's a simple xor implementation (a ~= b) + -- it's a simple xor implementation (a ~= b) AutoTurnIn.allowed = (not not AutoTurnInCharacterDB.enabled) ~= (IsModifiedClick) end return AutoTurnIn.allowed @@ -114,26 +121,26 @@ end -- OldGossip interaction system. Burn in hell See http://wowprogramming.com/docs/events/QUEST_GREETING function AutoTurnIn:QUEST_GREETING() - if (not AllowedToHandle(true)) then - return - end - - for index=1, GetNumActiveQuests() do - local quest, completed = GetActiveTitle(index) - if (AutoTurnInCharacterDB.all or L.quests[quest]) and (completed) then + if (not AllowedToHandle(true)) then + return + end + + for index=1, GetNumActiveQuests() do + local quest, completed = GetActiveTitle(index) + if (AutoTurnInCharacterDB.all or L.quests[quest]) and (completed) then SelectActiveQuest(index) end end - for index=1, GetNumAvailableQuests() do - local quest = L.quests[GetAvailableTitle(index)] - if (AutoTurnInCharacterDB.all or quest)then - if quest and quest.amount then - if GetItemAmount(quest.currency, quest.item) >= quest.amount then + for index=1, GetNumAvailableQuests() do + local quest = L.quests[GetAvailableTitle(index)] + if (AutoTurnInCharacterDB.all or quest)then + if quest and quest.amount then + if GetItemAmount(quest.currency, quest.item) >= quest.amount then SelectAvailableQuest(index) - return + return end - else + else SelectAvailableQuest(index) end end @@ -142,55 +149,54 @@ end -- (gaq[i+3]) equals "1" if quest is complete, "nil" otherwise -- why not gaq={GetGossipAvailableQuests()}? Well, tables in lua are truncated for values with ending `nil`. So: '#' for {1,nil, "b", nil} returns 1 -function AutoTurnIn:GOSSIP_SHOW() - if (not AllowedToHandle(true)) then - return +function AutoTurnIn:GOSSIP_SHOW() + if (not AllowedToHandle(true)) then + return end - if (AutoTurnInCharacterDB.darkmoonteleport and (L["DarkmoonFaireTeleport"]==UnitName("target"))) then + if (AutoTurnInCharacterDB.darkmoonteleport and (L["DarkmoonFaireTeleport"]==UnitName("target"))) then SelectGossipOption(1) StaticPopup1Button1:Click() end - local function VarArgForActiveQuests(...) + local function VarArgForActiveQuests(...) for i=1, select("#", ...), 4 do - local completeStatus = select(i+3, ...) - if (completeStatus) then -- complete status + local completeStatus = select(i+3, ...) + if (completeStatus) then -- complete status local questname = select(i, ...) - local quest = L.quests[questname] - if AutoTurnInCharacterDB.all or quest then - if quest and quest.amount then - if GetItemAmount(quest.currency, quest.item) >= quest.amount then + local quest = L.quests[questname] + if AutoTurnInCharacterDB.all or quest then + if quest and quest.amount then + if GetItemAmount(quest.currency, quest.item) >= quest.amount then SelectGossipActiveQuest(math.floor(i/4)+1) - return + return end else SelectGossipActiveQuest(math.floor(i/4)+1) return end end - end + end end end local function VarArgForAvailableQuests(...) for i=1, select("#", ...), 5 do local questname = select(i, ...) - local quest = L.quests[questname] - if AutoTurnInCharacterDB.all or (quest and (not quest.donotaccept)) then - if quest and quest.amount then - if GetItemAmount(quest.currency, quest.item) >= quest.amount then + local quest = L.quests[questname] + if AutoTurnInCharacterDB.all or (quest and (not quest.donotaccept)) then + if quest and quest.amount then + if GetItemAmount(quest.currency, quest.item) >= quest.amount then SelectGossipAvailableQuest(math.floor(i/5)+1) - return + return end - else + else SelectGossipAvailableQuest(math.floor(i/5)+1) return end end end - end - + end VarArgForActiveQuests(GetGossipActiveQuests()) VarArgForAvailableQuests(GetGossipAvailableQuests()) end @@ -210,8 +216,8 @@ function AutoTurnIn:QUEST_PROGRESS() end local function IsRangedWeapon(subclass) - return (AutoTurnInCharacterDB.items['Ranged'] and (C.ITEMS['Crossbows'] == subclass or - C.ITEMS['Guns'] == subclass or + return (AutoTurnInCharacterDB.items['Ranged'] and (C.ITEMS['Crossbows'] == subclass or + C.ITEMS['Guns'] == subclass or C.ITEMS['Bows'] == subclass)) end @@ -219,92 +225,117 @@ local function IsJewelry(equipSlot) return AutoTurnInCharacterDB.items['Jewelry'] and (C.JEWELRY[equipSlot]) end +--doesn't work. Frame appear faster than items loaded. Need rework. It is called nowhere right now +local function TryToLoadRewards() + local title = GetTitleText() + numEntries = GetNumQuestLogEntries() + for questIndex=1, numEntries do + questLogTitleText, _, _, _, isHeader = GetQuestLogTitle(questIndex) + if (not isHeader) then + if title == questLogTitleText then + SelectQuestLogEntry(questIndex) + if not QuestLogFrame:IsVisible() then + QuestLogFrame:Show() + QuestLogFrame:Hide() + end + end + end + end +end + +function AutoTurnIn:Greed() + local index, money = 0, 0; + + if (AutoTurnInCharacterDB.dontloot == 2) then + for i=1, GetNumQuestChoices() do + + local link = GetQuestItemLink("choice", i) + if ( link == nil ) then + return + end + + local m = select(11, GetItemInfo(link)) + if m > money then + money = m + index = i + end + end + if money > 0 then -- some quests, like tournament ones, offer reputation rewards and they have no cost. + GetQuestReward(index) + end + end +end + +local found = {} +function AutoTurnIn:Need() + wipe(found) + + for i=1, GetNumQuestChoices() do + local link = GetQuestItemLink("choice", i) + + if ( link == nil ) then + return + end + + local class, subclass, _, equipSlot = select(6, GetItemInfo(link)) + --[[relics and trinkets are out of autoloot + if C.STOPTOKENS[equipSlot] then + self:Print(INVTYPE_RELIC..' or ' .. INVTYPE_TRINKET .. ' found. Choose reward manually pls.') + return + end]]-- + if AutoTurnInCharacterDB.items[subclass] or IsRangedWeapon(subclass) or IsJewelry(equipSlot) then + local stattable = GetItemStats(link) + for stat, value in pairs(stattable) do + if ( AutoTurnInCharacterDB.items[C.STATS[stat]] ) then + tinsert(found, i) + end + end + end + end + + -- HANDLE RESULT + if #found > 1 then + local vars = "" + for _, reward in pairs(found) do + vars = vars..' '..GetQuestItemLink("choice", reward) + end + self:Print("Found few items. Choose manually pls" ..vars) + elseif(#found == 1) then + GetQuestReward(found[1]) + end +end + function AutoTurnIn:QUEST_COMPLETE() - -- blasted Lands citadel wonderful NPC. They do not trigger any events except quest_complete. - if not AllowedToHandle() then - return + -- blasted Lands citadel wonderful NPC. They do not trigger any events except quest_complete. + if not AllowedToHandle() then + return end - + if (AutoTurnInCharacterDB.showrewardtext) then - local gossip = UnitName("target") - if (gossip) then - self:Print(gossip) - end - self:Print(GetRewardText()) + self:Print( UnitName("target") and UnitName("target") or '' .. GetRewardText()) end - local quest = L.quests[GetTitleText()] + local quest = L.quests[GetTitleText()] if AutoTurnInCharacterDB.all or quest then - local index, money = 0, 0; - if GetNumQuestChoices() > 0 then - if AutoTurnInCharacterDB.dontloot > 1 then -- Auto Loot enabled! - + if GetNumQuestChoices() > 0 then + if AutoTurnInCharacterDB.dontloot > 1 then -- Auto Loot enabled! -- Tournament quest found if (quest == "tournament") then GetQuestReward(AutoTurnInCharacterDB.tournament) return - end - - -- G R E E D - if (AutoTurnInCharacterDB.dontloot == 2) then - for i=1, GetNumQuestChoices() do - local m = select(11, GetItemInfo(GetQuestItemLink("choice", i))) - if m > money then - money = m - index = i - end - end - if money > 0 then -- some quests, like tournament ones, offer reputation rewards and they have no cost. - GetQuestReward(index) - return - end end - -- #G R E E D - - -- N E E D if (AutoTurnInCharacterDB.dontloot == 3) then - local found = {} - - for i=1, GetNumQuestChoices() do - local link = GetQuestItemLink("choice", i) - local class, subclass, _, equipSlot = select(6, GetItemInfo(link)) - --[[relics and trinkets are out of autoloot - if C.STOPTOKENS[equipSlot] then - self:Print(INVTYPE_RELIC..' or ' .. INVTYPE_TRINKET .. ' found. Choose reward manually pls.') - return - end]]-- - if AutoTurnInCharacterDB.items[subclass] or IsRangedWeapon(subclass) or IsJewelry(equipSlot) then - local stattable = GetItemStats(link) - for stat, value in pairs(stattable) do - if ( C.STATS[stat] ) then - tinsert(found, i) - end - end - end - end - - print("Handle "..#found ) - -- HANDLE RESULT - if #found > 1 then - for _, reward in pairs(found) do - print("found: " .. GetQuestItemLink("choice", found[reward])) - --_G["QuestInfoItem" .. index] - end - elseif(#found == 1) then - print("found: " .. GetQuestItemLink("choice", found[1])) - --GetQuestReward(found[1]) - end + self:Need() + elseif (AutoTurnInCharacterDB.dontloot == 2) then + self:Greed() end - -- #N E E D - - end else - --GetQuestReward(index) + GetQuestReward(index) end end end -- gossip and quest interaction goes through a sequence of windows: gossip [shows a list of available quests] - quest[describes specified quest] --- sometimes some parts of this chain is skipped. For example, priest in Honor Hold show quest window directly. This is a trick to handle 'toggle key' +-- sometimes some parts of this chain is skipped. For example, priest in Honor Hold show quest window directly. This is a trick to handle 'toggle key' hooksecurefunc(QuestFrame, "Hide", function() AutoTurnIn.allowed = nil end) \ No newline at end of file diff --git a/RewardOptions.lua b/RewardOptions.lua index 4cf2252..6e90524 100644 --- a/RewardOptions.lua +++ b/RewardOptions.lua @@ -7,7 +7,7 @@ RewardPanel.name= QUEST_REWARDS local function CreateCheckbox(name, parent, marginx, marginy, text) local cb = CreateFrame("CheckButton", "$parent"..name, parent, "OptionsCheckButtonTemplate") cb:SetPoint("TOPLEFT", parent, marginx, marginy) - _G[cb:GetName().."Text"]:SetText(text) + _G[cb:GetName().."Text"]:SetText(text and text or name) cb:SetScript("OnClick", function(self) ptable.TempConfig.items[name] = self:GetChecked() == 1 end) @@ -34,34 +34,37 @@ local description = RewardPanel:CreateFontString(nil, "ARTWORK", "GameFontHighli description:SetText("Reward loot options") RewardPanel.parent = _G["AutoTurnInOptionsPanel"] +local weapon = {GetAuctionItemSubClasses(1)} +local armor = {GetAuctionItemSubClasses(2)} + -- WEAPON local WeaponPanel = CreatePanel("WeaponPanel", C.WEAPONLABEL, 590, 170) -CreateCheckbox("One-Handed Axes", WeaponPanel, 10, -8, C.ITEMS['One-Handed Axes']) -CreateCheckbox("Two-Handed Axes", WeaponPanel, 206, -8, C.ITEMS['Two-Handed Axes'] ) -CreateCheckbox("One-Handed Maces", WeaponPanel, 402, -8, C.ITEMS['One-Handed Maces']) +CreateCheckbox(weapon[1], WeaponPanel, 10, -8) +CreateCheckbox(weapon[2], WeaponPanel, 206, -8) +CreateCheckbox(weapon[5], WeaponPanel, 402, -8) -- 2nd line -CreateCheckbox("Two-Handed Maces", WeaponPanel, 10, -40, C.ITEMS['Two-Handed Maces']) -CreateCheckbox("Polearms", WeaponPanel, 206, -40, C.ITEMS['Polearms']) -CreateCheckbox("One-Handed Swords", WeaponPanel, 402, -40, C.ITEMS['One-Handed Swords'] ) +CreateCheckbox(weapon[6], WeaponPanel, 10, -40) +CreateCheckbox(weapon[7], WeaponPanel, 206, -40) +CreateCheckbox(weapon[8], WeaponPanel, 402, -40) -- 3rd line -CreateCheckbox("Two-Handed Swords", WeaponPanel, 10, -72, C.ITEMS['Two-Handed Swords']) -CreateCheckbox("Staves", WeaponPanel, 206, -72, C.ITEMS['Staves']) -CreateCheckbox("Fist Weapons", WeaponPanel, 402, -72, C.ITEMS['Fist Weapons']) +CreateCheckbox(weapon[9], WeaponPanel, 10, -72) +CreateCheckbox(weapon[10], WeaponPanel, 206, -72) +CreateCheckbox(weapon[11], WeaponPanel, 402, -72) -- 4rd line -CreateCheckbox("Daggers", WeaponPanel, 10, -104, C.ITEMS['Daggers'] ) -CreateCheckbox("Thrown", WeaponPanel, 206, -104, C.ITEMS['Thrown']) -CreateCheckbox("Wands", WeaponPanel, 402, -104, C.ITEMS['Wands']) +CreateCheckbox(weapon[13], WeaponPanel, 10, -104) +CreateCheckbox(weapon[14], WeaponPanel, 206, -104) +CreateCheckbox(weapon[16], WeaponPanel, 402, -104) -- 5th line -CreateCheckbox("Ranged", WeaponPanel, 10, -136, string.format("%s, %s, %s", C.ITEMS['Crossbows'], C.ITEMS['Bows'], C.ITEMS['Guns']) ) +CreateCheckbox("Ranged", WeaponPanel, 10, -136, string.format("%s, %s, %s", weapon[3], weapon[4], weapon[15]) ) -- ARMOR local ArmorPanel = CreatePanel("ArmorPanel", C.ARMORLABEL, 590, 70) -CreateCheckbox("Cloth", ArmorPanel, 10, -8, C.ITEMS['Cloth']) -CreateCheckbox("Leather", ArmorPanel, 152, -8, C.ITEMS['Leather'] ) -CreateCheckbox("Mail", ArmorPanel, 292, -8, C.ITEMS['Mail']) -CreateCheckbox("Plate", ArmorPanel, 436, -8, C.ITEMS['Plate']) +CreateCheckbox(armor[2], ArmorPanel, 10, -8) +CreateCheckbox(armor[3], ArmorPanel, 152, -8) +CreateCheckbox(armor[4], ArmorPanel, 292, -8) +CreateCheckbox(armor[5], ArmorPanel, 436, -8) -- 2nd line -CreateCheckbox("Shields", ArmorPanel, 10, -40, C.ITEMS['Shields']) +CreateCheckbox(armor[6], ArmorPanel, 10, -40) CreateCheckbox("Jewelry", ArmorPanel, 292, -40, ptable.L['Jewelry'] ) -- ATTRIBUTES diff --git a/rewards.lua b/rewards.lua index b720eb1..578a2d6 100644 --- a/rewards.lua +++ b/rewards.lua @@ -5,25 +5,15 @@ local C = ptable.CONST local weapon = {GetAuctionItemSubClasses(1)} local armor = {GetAuctionItemSubClasses(2)} --- INVTYPE_RELIC INVTYPE_TRINKET - остановить лут вообще. C.WEAPONLABEL, C.ARMORLABEL = GetAuctionItemClasses() C.STOPTOKENS = {['INVTYPE_RELIC']='', ['INVTYPE_TRINKET']=''} C.JEWELRY = {['INVTYPE_FINGER']='', ['INVTYPE_NECK']=''} ---[[ - - -SPELL_STAT1_NAME = "Strength"; -SPELL_STAT2_NAME = "Agility"; -SPELL_STAT3_NAME = "Stamina"; -SPELL_STAT4_NAME = "Intellect"; -SPELL_STAT5_NAME = "Spirit"; - -STAT_CATEGORY_ATTRIBUTES = "Attributes"; -STAT_CATEGORY_DEFENSE = "Defense"; -STAT_CATEGORY_GENERAL = "General"; -STAT_CATEGORY_MELEE = "Melee"; -STAT_CATEGORY_RANGED = "Ranged"; -]]-- +C.STATS = { + ['ITEM_MOD_STRENGTH_SHORT'] = "Strength", + ['ITEM_MOD_AGILITY_SHORT'] = "Agility", + ['ITEM_MOD_INTELLECT_SHORT'] = "Intellect", + ['ITEM_MOD_SPIRIT_SHORT'] = "Spirit" +} C.ITEMS = { ['One-Handed Axes'] = weapon[1], @@ -43,7 +33,6 @@ C.ITEMS = { ['Crossbows'] = weapon[15], ['Wands'] = weapon[16], --['Fishing Pole'] = select(17, weapon) - -- armor --['Miscellaneous'] = armor[1] ['Cloth'] = armor[2], @@ -51,22 +40,18 @@ C.ITEMS = { ['Mail'] = armor[4], ['Plate'] = armor[5], ['Shields'] = armor[6], - --[[3rd slot - ['Librams'] = select(7, armor), - ['Idols'] = select(8, armor), - ['Totems'] = select(9, armor), + ['Librams'] = armor[7], + ['Idols'] = armor[8], + ['Totems'] = armor[9], ]]-- } -C.STATS = { - ['ITEM_MOD_STRENGTH_SHORT'] = "Strength", - ['ITEM_MOD_AGILITY_SHORT'] = "Agility", - ['ITEM_MOD_INTELLECT_SHORT'] = "Intellect", - ['ITEM_MOD_SPIRIT_SHORT'] = "Spirit" -} + --[[ +(\[('.+')\]\s+=\s+((weapon|armor)\[\d+\]),) + Статы: показываем актуальные для класса. Например, шаман - интеллект и ловкость. Воин - сила. Либрамы и триньки: останавливаем аддон и просим пользователя выбрать @@ -79,10 +64,24 @@ end /run table.foreach(OPEN_FILTER_LIST, function(value) for v,k in pairs(value) do print(v,k) end) /run for k,v in pairs(OPEN_FILTER_LIST) do for n,m in pairs(v) do print(n,m) end end +/run for k,v in pairs(InterfaceOptionsFrameAddOnsButton2.element) do print(k,v) end /run print(_G[INVTYPE_CLOAK]) /run print(select(6, GetItemInfo("Набедренники Прилива"))) /run function a(...) for i=1, select("#", ...), 2 do invType = _G[select(i, ...)] print(invType, select(i, ...)) end end a(GetAuctionInvTypes(2,2)) 00:08:47 Спина INVTYPE_CLOAK 1 INVTYPE_HOLDABLE nil + +SPELL_STAT1_NAME = "Strength"; +SPELL_STAT2_NAME = "Agility"; +SPELL_STAT3_NAME = "Stamina"; +SPELL_STAT4_NAME = "Intellect"; +SPELL_STAT5_NAME = "Spirit"; + +STAT_CATEGORY_ATTRIBUTES = "Attributes"; +STAT_CATEGORY_DEFENSE = "Defense"; +STAT_CATEGORY_GENERAL = "General"; +STAT_CATEGORY_MELEE = "Melee"; +STAT_CATEGORY_RANGED = "Ranged"; + ]]-- \ No newline at end of file -- 1.7.9.5