From 8b8dc6260384acbf377389570d29a09bf475ea21 Mon Sep 17 00:00:00 2001 From: Freewood <948+freewood@noreply.octowow.st> Date: Tue, 27 Oct 2026 14:09:39 +0000 Subject: [PATCH] Dateien nach "/" hochladen --- CodexTransport.lua | 230 +++ CodexTrust.lua | 309 ++++ CodexUI.lua | 4415 ++++++++++++++++++++++++++++++++++++++++++++ CodexWdbChain.lua | 1406 ++++++++++++++ 4 files changed, 6360 insertions(+) create mode 100644 CodexTransport.lua create mode 100644 CodexTrust.lua create mode 100644 CodexUI.lua create mode 100644 CodexWdbChain.lua diff --git a/CodexTransport.lua b/CodexTransport.lua new file mode 100644 index 0000000..a357702 --- /dev/null +++ b/CodexTransport.lua @@ -0,0 +1,230 @@ +-- Freewood-OctoWoW-Codex: Verkehrsverbindungen (Schiff, Zeppelin, U-Bahn, Portal) +-- +-- Berechtigte (Modul Freewood-OctoWoW-Dev, Rolle Bearbeiter oder hoeher) erfassen Verbindungen: Start hier, Fahrt, Ziel hier, +-- die Fahrzeit wird gemessen. Gespeichert wird in db.transport[id] und ueber das normale Teilen als Datensatz "g" +-- verschickt; angenommen werden sie nur von Absendern, die selbst berechtigt sind. +-- +-- db.transport[id] = { k = Art, f = "A" | "H" | nil, n = Name, t = Sekunden, a = { m, x, y }, b = { m, x, y }, +-- two = Rueckfahrt moeglich, del = geloescht, upd = Stand } +-- Die ID ist ein Pruefwert aus Art, Fraktion und beiden Orten: derselbe Weg, von zwei Berechtigten erfasst, ergibt denselben Datensatz. + +local ADDON, NS = ... + +local FW = _G.Freewood +local Codex = NS and NS.Codex +if not FW or not Codex then + return +end + +local Transport = { draft = {} } +Codex.Transport = Transport +NS.Transport = Transport + +Transport.KINDS = { "boat", "zeppelin", "subway", "portal" } +local KIND_OK = {} +for _, k in ipairs(Transport.KINDS) do KIND_OK[k] = true end + +local function Now() return _G.time and _G.time() or 0 end + +local function DB() + local db = Codex.db + if not db then return nil end + db.transport = db.transport or {} + return db +end + +local function CanEdit() + return Codex.Trust ~= nil and Codex.Trust.CanEdit() +end + +local function Round(v, f) return math.floor(v * f + 0.5) end + +local function Hash(text) + local h = 5381 + for i = 1, #text do h = (h * 33 + text:byte(i)) % 99999989 end + return h +end + +-- Pruefwert (0..99999988) aus Art, Fraktion und den auf etwa 0,5 % gerundeten Orten +function Transport.Id(rec) + local a, b = rec.a or {}, rec.b or {} + return Hash(table.concat({ tostring(rec.k), tostring(rec.f or "-"), tostring(a.m), Round(a.x or 0, 200), Round(a.y or 0, 200), + tostring(b.m), Round(b.x or 0, 200), Round(b.y or 0, 200) }, "|")) +end + +-- Aktueller Ort { m, x, y } oder nil +function Transport.Here() + local loc = FW.Util and FW.Util.GetPlayerLocation and FW.Util.GetPlayerLocation() + if loc and loc.mapID and loc.x and loc.y then + return { m = loc.mapID, x = math.floor(loc.x * 10000 + 0.5) / 10000, y = math.floor(loc.y * 10000 + 0.5) / 10000 } + end + return nil +end + +local function Clock() return _G.GetTime and _G.GetTime() or 0 end + +------------------------------------------------------------------------ +-- Erfassen (Entwurf) +------------------------------------------------------------------------ + +function Transport.Draft() + return Transport.draft +end + +function Transport.Reset() + local d = Transport.draft + d.a, d.b, d.t0, d.t = nil, nil, nil, nil + FW:Fire("CODEX_TRANSPORT_DRAFT") +end + +function Transport.Start() + local here = Transport.Here() + if not here then return false end + local d = Transport.draft + d.a, d.b, d.t = here, nil, nil + d.t0 = Clock() + FW:Fire("CODEX_TRANSPORT_DRAFT") + return true +end + +function Transport.Finish() + local d = Transport.draft + if not d.a or not d.t0 then return false end + local here = Transport.Here() + if not here then return false end + d.b = here + d.t = math.max(1, math.floor(Clock() - d.t0 + 0.5)) + FW:Fire("CODEX_TRANSPORT_DRAFT") + return true +end + +-- Laeuft gerade eine Aufnahme (Start gesetzt, Ziel noch nicht)? Dann zeichnet das Wegenetz nicht mit. +function Transport.Recording() + local d = Transport.draft + return d.a ~= nil and d.b == nil and d.t0 ~= nil +end + +function Transport.SetDraft(key, value) + Transport.draft[key] = value +end + +-- Entwurf pruefen. Rueckgabe: true oder false, Grund +function Transport.CheckDraft() + local d = Transport.draft + if not d.a then return false, "start" end + if not d.b or not d.t then return false, "finish" end + if not KIND_OK[d.kind or "boat"] then return false, "kind" end + if d.a.m == d.b.m and math.abs(d.a.x - d.b.x) < 0.005 and math.abs(d.a.y - d.b.y) < 0.005 then return false, "same" end + return true +end + +------------------------------------------------------------------------ +-- Speichern und Loeschen +------------------------------------------------------------------------ + +local function Touch(id) + if Codex.Share and Codex.Share.InvalidateScan then Codex.Share.InvalidateScan() end + Transport.rev = (Transport.rev or 0) + 1 + FW:Fire("CODEX_TRANSPORT_CHANGED", id) + FW:Fire("CODEX_CHANGED", "transport", id) +end + +local function Log(id, field, old, new) + if Codex.DevLog then + pcall(Codex.DevLog, { who = Codex.Trust and Codex.Trust.SelfKey() or "?", kind = "g", id = id, field = field, old = old, new = new }) + end +end + +local function Describe(rec) + local M = Codex.MapName + return string.format("%s: %s -> %s (%ds)", tostring(rec.k), M and M(rec.a.m) or rec.a.m, M and M(rec.b.m) or rec.b.m, rec.t or 0) +end + +-- Speichert den Entwurf. Rueckgabe: id oder nil, Grund +function Transport.Save() + if not CanEdit() then return nil, "rights" end + local ok, why = Transport.CheckDraft() + if not ok then return nil, why end + local d = Transport.draft + local rec = { + k = d.kind or "boat", f = (d.faction == "A" or d.faction == "H") and d.faction or nil, + n = type(d.name) == "string" and d.name:sub(1, 40) ~= "" and d.name:sub(1, 40) or nil, + t = d.t, a = { m = d.a.m, x = d.a.x, y = d.a.y }, b = { m = d.b.m, x = d.b.x, y = d.b.y }, + two = d.two ~= false, upd = Now(), + } + local db = DB() + local id = Transport.Id(rec) + local old = db.transport[id] + rec.upd = math.max(rec.upd, (old and old.upd or 0) + 1) + db.transport[id] = rec + Log(id, "add", old and not old.del and Describe(old) or nil, Describe(rec)) + Touch(id) + Transport.Reset() + return id +end + +function Transport.Delete(id) + if not CanEdit() then return false end + local db = DB() + local own = db.transport[id] + local rec = own + if not rec then + for _, r in ipairs(Transport.All(true)) do + if r.id == id then rec = r break end + end + end + if not rec then return false end + local del = { k = rec.k, f = rec.f, n = rec.n, t = rec.t, a = rec.a, b = rec.b, two = rec.two, del = true, + upd = math.max(Now(), (rec.upd or 0) + 1) } + db.transport[id] = del + Log(id, "del", Describe(rec), nil) + Touch(id) + return true +end + +------------------------------------------------------------------------ +-- Lesen: eigene und empfangene Verbindungen +------------------------------------------------------------------------ + +-- Liste { id, k, f, n, t, a, b, two, upd }, je ID der neueste Stand; geloeschte nur mit withDeleted +function Transport.All(withDeleted) + local best = {} + local db = DB() + if not db then return {} end + for id, rec in pairs(db.transport) do + if type(rec) == "table" and rec.a and rec.b then best[id] = rec end + end + if Codex.Share and Codex.Share.RemoteRecords then + for _, rec in ipairs(Codex.Share.RemoteRecords("g")) do + local cur = best[rec.id] + if not cur or (rec.upd or 0) > (cur.upd or 0) then best[rec.id] = rec end + end + end + local out = {} + for id, rec in pairs(best) do + if withDeleted or not rec.del then + out[#out + 1] = { id = id, k = rec.k, f = rec.f, n = rec.n, t = rec.t, a = rec.a, b = rec.b, two = rec.two ~= false, upd = rec.upd, del = rec.del } + end + end + table.sort(out, function(x, y) + if x.k ~= y.k then return x.k < y.k end + return x.id < y.id + end) + return out +end + +-- Fahrten als gerichtete Kanten { id, k, t, from = { m, x, y }, to = { m, x, y } }; faction = "A" | "H" | nil (alle) +function Transport.Edges(faction) + local out = {} + for _, r in ipairs(Transport.All()) do + if not (faction and r.f and r.f ~= faction) then + out[#out + 1] = { id = r.id, k = r.k, t = r.t, from = r.a, to = r.b, name = r.n } + if r.two then out[#out + 1] = { id = r.id, k = r.k, t = r.t, from = r.b, to = r.a, name = r.n } end + end + end + return out +end + +function Transport.Count() + return #Transport.All() +end diff --git a/CodexTrust.lua b/CodexTrust.lua new file mode 100644 index 0000000..c573333 --- /dev/null +++ b/CodexTrust.lua @@ -0,0 +1,309 @@ +-- Freewood-OctoWoW-Codex: Berechtigungen (wer darf Daten fuer alle bearbeiten?) +-- +-- Rollen: +-- owner steht in CodexOwners.lua, darf die Liste veroeffentlichen +-- moderator darf Namen aendern, Datensaetze als fehlerhaft markieren und fremde Markierungen aufheben +-- editor darf Namen aendern und Datensaetze als fehlerhaft markieren +-- blocked gesperrt: nichts wird mehr von diesem Charakter uebernommen +-- +-- Die Liste (Charakter -> Rolle) kommt von einem Eigentuemer ueber den Kanal (Nachricht "T"). Der Absender einer +-- Addon-Nachricht wird vom Spiel gesetzt; Listen anderer Absender werden ignoriert. +-- Battle.net-Namen und Notizen bleiben beim Eigentuemer (Modul Freewood-OctoWoW-Rechte) und werden nie verschickt. +-- Bearbeiten (Namen, Markierungen) geht nur, wenn zusaetzlich das Modul Freewood-OctoWoW-Dev vorhanden ist. + +local ADDON, NS = ... + +local FW = _G.Freewood +local Codex = NS and NS.Codex +if not FW or not Codex then + return +end + +local Trust = { buffers = {} } +NS.Trust = Trust +Codex.Trust = Trust + +local MAX_ENTRIES = 150 +local ROLE_CODE = { editor = "e", moderator = "m", blocked = "b" } +local CODE_ROLE = { e = "editor", m = "moderator", b = "blocked" } +Trust.ROLES = { "editor", "moderator", "blocked" } + +local ACTIONS = { + editor = { name = true, bad = true, export = true }, + moderator = { name = true, bad = true, unbad = true, export = true }, +} + +------------------------------------------------------------------------ +-- Namen +------------------------------------------------------------------------ + +local function Core(name) + if type(name) ~= "string" then return "" end + local n = name:gsub("\194\160", " "):match("^([^%-]*)") or "" + return (n:gsub("%s", ""):lower()) +end + +local function RealmPart(name) + local r = type(name) == "string" and name:match("%-(.+)$") + if r then + r = r:gsub("[%s%-']", ""):lower() + if r ~= "" then return r end + end + return nil +end + +local function OwnRealm() + local r = (GetNormalizedRealmName and GetNormalizedRealmName()) or (GetRealmName and GetRealmName()) or "" + return (tostring(r):gsub("[%s%-']", ""):lower()) +end + +-- Der eigene Realm hat im Spiel mehrere Schreibweisen (z.B. GetNormalizedRealmName = "ClassicBetaPvP2", +-- UnitFullName liefert "Steel"). Alle gelten als derselbe Realm und werden auf OwnRealm() vereinheitlicht. +local function IsOwnRealmVariant(r) + if r == OwnRealm() then return true end + local variants = {} + if GetRealmName then variants[#variants + 1] = GetRealmName() end + if UnitFullName then + local ok, _, ur = pcall(UnitFullName, "player") + if ok then variants[#variants + 1] = ur end + end + for _, v in ipairs(variants) do + if type(v) == "string" and v:gsub("[%s%-']", ""):lower() == r then return true end + end + return false +end + +-- "name-realm" in Kleinschreibung; ohne Realm gilt der eigene +function Trust.Key(name) + local core = Core(name) + if core == "" then return nil end + local realm = RealmPart(name) + if not realm or IsOwnRealmVariant(realm) then realm = OwnRealm() end + return core .. "-" .. realm +end + +-- Eintrag aus einer Liste oder von Hand getippt: "Name" (gilt fuer den eigenen Realm) oder "Name-Realm" +-- (z.B. "Fwaroki-NZoth"). Auf OctoWoW gibt es nur einen Namen, keinen Nachnamen: ein Bindestrich trennt den Realm ab. +function Trust.EntryKey(name) + if type(name) ~= "string" then return nil end + local clean = name:gsub("\194\160", " "):gsub("^%s+", ""):gsub("%s+$", "") + return Trust.Key(clean) +end + +-- Eigener voller Name (OctoWoW: nur ein Name; der zweite Rueckgabewert von UnitFullName ist der Realm, kein Nachname) +function Trust.SelfKey() + local name + if UnitFullName then + local ok, n = pcall(UnitFullName, "player") + if ok then name = n end + end + if not name and UnitName then name = (UnitName("player")) end + if not name then return nil end + return Trust.Key(name) +end + +local function Data() + local db = Codex.db + if not db then return { rev = 0, list = {} } end + db.trust = db.trust or { rev = 0, list = {} } + db.trust.list = db.trust.list or {} + return db.trust +end + +local function OwnerKeys() + local set = {} + for _, n in ipairs(NS.Owners or {}) do + local k = Trust.EntryKey(n) + if k then set[k] = true end + end + return set +end + +------------------------------------------------------------------------ +-- Abfragen +------------------------------------------------------------------------ + +local function ModeratorKeys() + local set = {} + for _, n in ipairs(NS.Moderators or {}) do + local k = Trust.EntryKey(n) + if k then set[k] = true end + end + return set +end + +function Trust.IsOwner(name) + local k = Trust.Key(name) + return k ~= nil and OwnerKeys()[k] == true +end + +function Trust.IsSelfOwner() + return Trust.IsOwner(Trust.SelfKey()) +end + +-- Rolle: "owner", "moderator", "editor", "blocked" oder nil +function Trust.RoleOf(name) + local k = Trust.Key(name) + if not k then return nil end + local entry = Data().list[k] + if entry and entry.role == "blocked" then return "blocked" end + if OwnerKeys()[k] then return "owner" end + if ModeratorKeys()[k] then return "moderator" end + return entry and entry.role or nil +end + +function Trust.IsDev(name) + local r = Trust.RoleOf(name) + return r == "owner" or r == "moderator" or r == "editor" +end + +function Trust.SelfRole() + -- OctoWoW-Test: Bypass der Berechtigungsliste (FW.OCTO.testBypass in Freewood-OctoWoW-Core/Core/Init.lua) + if FW.OCTO and FW.OCTO.testBypass then return "owner" end + return Trust.RoleOf(Trust.SelfKey()) +end + +-- Darf dieser Charakter eine Aktion ausfuehren? Aktion: name, bad, unbad, export. Braucht das Modul Freewood-OctoWoW-Dev. +function Trust.Can(action) + if not Codex.DevModule then return false end + if FW.OCTO and FW.OCTO.testBypass then return true end -- OctoWoW-Test + local role = Trust.SelfRole() + if role == "owner" then return true end + local a = role and ACTIONS[role] + return a ~= nil and a[action] == true +end + +function Trust.CanEdit() + return Trust.Can("name") +end + +function Trust.Revision() + return Data().rev or 0 +end + +function Trust.Entries() + local out = {} + for key, e in pairs(Data().list) do + out[#out + 1] = { key = key, role = e.role } + end + table.sort(out, function(a, b) return a.key < b.key end) + return out +end + +------------------------------------------------------------------------ +-- Liste setzen und verschicken +------------------------------------------------------------------------ + +local function Changed() + if Codex.Share and Codex.Share.TrustChanged then Codex.Share.TrustChanged() end + FW:Fire("CODEX_TRUST_CHANGED") + FW:Fire("CODEX_CHANGED", "trust") +end + +-- entries: Liste { key, role } +function Trust.SetList(entries, rev) + local d = Data() + local list = {} + local n = 0 + for _, e in ipairs(entries or {}) do + local key = Trust.Key(e.key) + if key and ROLE_CODE[e.role] and n < MAX_ENTRIES then + list[key] = { role = e.role } + n = n + 1 + end + end + d.list = list + d.rev = rev or math.max((d.rev or 0) + 1, time and time() or 1) -- Zeitstempel: bleibt auch nach einem Zuruecksetzen steigend + d.stamp = time and time() or 0 + Changed() + return d.rev +end + +-- Nachrichten "T|rev|i/n|text" (Eintraege "name-realm,e;name-realm,m;...") +function Trust.Chunks() + local d = Data() + local parts = {} + for _, e in ipairs(Trust.Entries()) do + local key = e.key:gsub("[;,|]", "") + parts[#parts + 1] = key .. "," .. ROLE_CODE[e.role] + end + local chunks, cur = {}, "" + for _, p in ipairs(parts) do + if #cur + #p + 1 > 190 then + chunks[#chunks + 1] = cur + cur = "" + end + cur = cur .. (cur ~= "" and ";" or "") .. p + end + chunks[#chunks + 1] = cur + local out = {} + for i, c in ipairs(chunks) do + out[i] = string.format("T|%d|%d/%d|%s", d.rev or 0, i, #chunks, c) + end + return out +end + +local function Parse(payload) + local list = {} + for item in (payload .. ";"):gmatch("([^;]*);") do + local key, code = item:match("^(.-),([emb])$") + if key and key ~= "" then + list[#list + 1] = { key = key, role = CODE_ROLE[code] } + end + end + return list +end + +-- Empfang: nur von Eigentuemern. body = "rev|i/n|text". Rueckgabe: true, wenn eine neue Liste uebernommen wurde +function Trust.Receive(sender, body) + if not Trust.IsOwner(sender) then return false end + local rev, i, n, payload = tostring(body):match("^(%d+)|(%d+)/(%d+)|(.*)$") + rev, i, n = tonumber(rev), tonumber(i), tonumber(n) + if not rev or not i or not n or n < 1 or n > 12 or i < 1 or i > n then return false end + local d = Data() + if rev <= (d.rev or 0) then return false end -- aelter oder schon vorhanden + local key = Trust.Key(sender) + local buf = Trust.buffers[key] + if not buf or buf.rev ~= rev or buf.n ~= n then + buf = { rev = rev, n = n, parts = {}, got = 0 } + Trust.buffers[key] = buf + end + if not buf.parts[i] then + buf.parts[i] = payload + buf.got = buf.got + 1 + end + if buf.got < n then return false end + Trust.buffers[key] = nil + local all = {} + for idx = 1, n do all[#all + 1] = buf.parts[idx] end + Trust.SetList(Parse(table.concat(all, ";")), rev) + return true +end + +------------------------------------------------------------------------ +-- Diagnose: /fwrolle +------------------------------------------------------------------------ + +SLASH_FREEWOODROLE1 = "/fwrolle" +SlashCmdList["FREEWOODROLE"] = function() + local d = Data() + local n = 0 + for _ in pairs(d.list) do n = n + 1 end + local L = FW.L + FW:Print(string.format(L.CODEX_ROLE_INFO, tostring(Trust.SelfKey()), tostring(Trust.SelfRole() or "-"), + Codex.DevModule and L.CODEX_YES or L.CODEX_NO, n, d.rev or 0)) + -- Ausfuehrliche Diagnose: was liefert das Spiel, und welche Schluessel stehen in der Eigentuemer-Liste? + local ok, un, ur = false, nil, nil + if UnitFullName then ok, un, ur = pcall(UnitFullName, "player") end + FW:Print(string.format("Rolle: UnitFullName = %s | %s, UnitName = %s, GetRealmName = %s, GetNormalizedRealmName = %s, eigener Realm = %s", + tostring(un), tostring(ur), tostring(UnitName and UnitName("player")), tostring(GetRealmName and GetRealmName()), + tostring(GetNormalizedRealmName and GetNormalizedRealmName()), OwnRealm())) + local self = Trust.SelfKey() + local found = false + for _, entry in ipairs(NS.Owners or {}) do + local k = Trust.EntryKey(entry) + if k == self then found = true end + FW:Print(string.format("Rolle: Eigentuemer \"%s\" -> %s%s", tostring(entry), tostring(k), k == self and " <== du" or "")) + end + FW:Print(string.format("Rolle: dein Schluessel %s steht %s in der Eigentuemer-Liste", tostring(self), found and "" or "NICHT")) +end diff --git a/CodexUI.lua b/CodexUI.lua new file mode 100644 index 0000000..2c40995 --- /dev/null +++ b/CodexUI.lua @@ -0,0 +1,4415 @@ +-- Freewood-OctoWoW-Codex: Tab "Datenbank" +-- Oben die Arten (Quests, Kreaturen, Objekte, Items), links Suche und Liste, rechts das Detail. +-- Das Detail ist eine Folge von Zeilen; Zeilen mit Verweis fuehren zum passenden Eintrag. + +local ADDON, NS = ... + +local FW = _G.Freewood +local Codex = NS.Codex +if not FW or not Codex then + return +end + +local UI = FW.UI +local Util = FW.Util + +local LIST_W = 540 +local ROW_H, ROW_GAP = 44, 4 +local DEFAULT_ROWS = 300 +local function MaxRows() + local n = Codex.db and Codex.db.settings and tonumber(Codex.db.settings.listMax) + if not n or n < 50 then return DEFAULT_ROWS end + return math.floor(n) +end +local LINE_H = 24 + +local KINDS = { + { id = "quests", label = "CODEX_KIND_QUESTS" }, + { id = "units", label = "CODEX_KIND_UNITS" }, + { id = "objects", label = "CODEX_KIND_OBJECTS" }, + { id = "items", label = "CODEX_KIND_ITEMS" }, + { id = "zones", label = "CODEX_KIND_ZONES" }, + { id = "xp", label = "CODEX_KIND_XP" }, + { id = "learn", label = "CODEX_KIND_LEARN" }, +} + +local SORTS = { + quests = { "name", "zone", "recent", "lvl", "xp", "money", "qtime", "dist" }, + units = { "name", "recent", "gold", "ttk", "gpm", "ahkill", "gpmah", "lvl", "xpm", "data", "dist" }, + objects = { "name", "recent", "gold", "data", "dist" }, + items = { "name", "price", "buy", "ah", "flip", "ilvl", "quality", "chance", "gph" }, + zones = { "name", "zlvl", "cnt", "recent" }, + xp = { "name", "recent", "xpm" }, + learn = { "step" }, +} +-- Standardrichtung: true = aufsteigend (kleinster Wert zuerst) +local SORT_ASC = { zlvl = true, zone = true, step = true, name = true, ttk = true, qtime = true, buy = true, dist = true, data = true } +-- Anzeige des Sortierwerts in der Zeile: "money" (Kupfer), "secs", "num" +local SORT_FORMAT = { + gold = "money", gpm = "money", ahkill = "money", gpmah = "money", price = "money", buy = "money", ah = "money", flip = "money", gph = "money", money = "money", + ttk = "secs", qtime = "secs", lvl = "num", xp = "num", xpm = "num", data = "num", cnt = "num", +} +local SORT_METRIC = { + step = "step", price = "price", ilvl = "ilvl", quality = "quality", chance = "chance", gold = "gold", ttk = "ttk", gpm = "gpm", ahkill = "ahkill", gpmah = "gpmah", + lvl = "lvl", xpm = "xpm", xp = "xp", money = "money", qtime = "qtime", buy = "buy", ah = "ah", flip = "flip", gph = "gph", data = "data", + zlvl = "zlvl", cnt = "cnt", +} + +local XPTitle, XPKey +local ICON = { + quests = "Interface\\GossipFrame\\AvailableQuestIcon", + units = "Interface\\Icons\\INV_Misc_Bone_HumanSkull_01", + objects = "Interface\\Icons\\INV_Misc_Bag_10", + items = "Interface\\Icons\\INV_Misc_QuestionMark", + zones = "Interface\\Icons\\INV_Misc_Map_01", + xp = "Interface\\Icons\\INV_Misc_Book_09", + learn = "Interface\\Icons\\INV_Misc_Note_01", + plus = "Interface\\Buttons\\UI-PlusButton-Up", + minus = "Interface\\Buttons\\UI-MinusButton-Up", +} + +-- Kreaturentypen, deren Modelle in ClassicAPI keinen Ankleide-Auftrag brauchen: +-- 1 Wildtier, 2 Drachkin, 3 Daemon, 4 Elementar, 5 Riese, 8 Kleintier, 9 Mechanisch +local SAFE_MODEL_TYPE = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [8] = true, [9] = true } + +-- Reihenfolge = Vorrang +local ROLE_ICONS = { + { "classtrainer", "Interface\\Icons\\INV_Misc_Book_09" }, + { "proftrainer", "Interface\\Icons\\INV_Misc_Book_06" }, + { "flight", "Interface\\Icons\\INV_Misc_Map_01" }, + { "banker", "Interface\\Icons\\INV_Misc_Coin_02" }, + { "auctioneer", "Interface\\Icons\\INV_Misc_Coin_01" }, + { "innkeeper", "Interface\\Icons\\INV_Misc_Key_03" }, + { "stablemaster", "Interface\\Icons\\Ability_Hunter_BeastTaming" }, + { "battlemaster", "Interface\\Icons\\INV_BannerPVP_01" }, + { "spirithealer", "Interface\\Icons\\Spell_Holy_GuardianSpirit" }, + { "repair", "Interface\\Icons\\Trade_BlackSmithing" }, + { "vendor", "Interface\\Icons\\INV_Misc_Bag_08" }, +} + +-- Symbole je Kreaturtyp (Spiel-Symbole; fehlt eines im Client, erscheint ein leeres Feld: dann hier tauschen) +local CT_ICONS = { + beast = "Interface\\Icons\\Ability_Hunter_BeastCall", + humanoid = "Interface\\Icons\\INV_Misc_Head_Human_01", + undead = "Interface\\Icons\\Spell_Shadow_RaiseDead", + demon = "Interface\\Icons\\Spell_Shadow_SummonImp", + dragonkin = "Interface\\Icons\\INV_Misc_Head_Dragon_01", + elemental = "Interface\\Icons\\Spell_Fire_Elemental_Totem", + giant = "Interface\\Icons\\Spell_Nature_StrengthOfEarthTotem", + mechanical = "Interface\\Icons\\INV_Gizmo_01", + critter = "Interface\\Icons\\INV_Misc_Rabbit_2", + totem = "Interface\\Icons\\Spell_Nature_ManaRegenTotem", + gascloud = "Interface\\Icons\\Spell_Nature_Cyclone", + other = "Interface\\Icons\\INV_Misc_QuestionMark", + pet = "Interface\\Icons\\INV_Box_PetCarrier_01", +} + +-- Symbol einer Kreatur: Familien-Symbol (wenn das Pet-Addon die Familie kennt), sonst Totenkopf +local function UnitIcon(u) + local Pet = FW.Pet + if u and u.f and Pet and Pet.GetFamilyID and Pet.FamilyIcon and Pet.GetFamilyID(u.f) then + return Pet.FamilyIcon(u.f) + end + -- Rolle (Haendler, Lehrer, Bank ...) als Symbol; ein 2D-Portrait gibt es fuer reine IDs nicht + local ro = u and u.ro + if type(ro) == "table" then + for _, pair in ipairs(ROLE_ICONS) do + if (ro[pair[1]] or 0) > 0 then + return pair[2] + end + end + end + -- Kreaturtyp (Wildtier, Untoter, ...) als Symbol + if u and u.ct and CT_ICONS[u.ct] then + return CT_ICONS[u.ct] + end + return ICON.units +end + +------------------------------------------------------------------------ +-- Formate +------------------------------------------------------------------------ + +local function FormatMoney(copper) + copper = math.floor(tonumber(copper) or 0) + local g = math.floor(copper / 10000) + local s = math.floor((copper % 10000) / 100) + local c = copper % 100 + local parts = {} + if g > 0 then parts[#parts + 1] = "|cffffd100" .. g .. "g|r" end + if s > 0 or g > 0 then parts[#parts + 1] = "|cffc7c7cf" .. s .. "s|r" end + parts[#parts + 1] = "|cffeda55f" .. c .. "c|r" + return table.concat(parts, " ") +end + +Codex.FormatMoney = FormatMoney + +-- Preise eines Artikels beim Haendler: hoechster Preis = 100 %, billigere mit Prozent (Ruf, Talente) +local function PriceText(prices, ec) + local list = {} + for price, n in pairs(prices or {}) do list[#list + 1] = { price = price, n = n } end + if #list == 0 then return nil end + table.sort(list, function(a, b) return a.price > b.price end) + local top = list[1].price + local parts = {} + for i, e in ipairs(list) do + if i > 3 then break end + local text = e.price > 0 and FormatMoney(e.price) or "-" + if i > 1 and top > 0 then + text = text .. string.format(" (%d %%)", math.floor(e.price / top * 100 + 0.5)) + end + parts[#parts + 1] = text + end + local out = table.concat(parts, " ") + if ec then out = out .. " +" .. FW.L.CODEX_WARE_TOKEN end + return out +end + +local function FormatDuration(seconds) + seconds = math.floor((tonumber(seconds) or 0) + 0.5) + if seconds >= 3600 then + return string.format("%d:%02d:%02d", math.floor(seconds / 3600), math.floor((seconds % 3600) / 60), seconds % 60) + end + return string.format("%d:%02d", math.floor(seconds / 60), seconds % 60) +end + +-- Kampfdauer fuer die eigene Klasse: Sekunden, Anzahl (Erfahrung-Zeilen und Details) +local function OwnTTK(pl, ml) + local token = Codex.Time and Codex.Time.PlayerToken() + if not (token and Codex.Share and Codex.Share.TTKMeasured) then + return nil + end + return Codex.Share.TTKMeasured(token, pl, ml - pl) +end + +local function FormatChance(chance) + local p = chance * 100 + if p >= 10 then + return string.format("%.0f%%", p) + end + return string.format("%.1f%%", p) +end + +local function Colored(text, quality) + return "|cff" .. UI.RarityHex(quality or 1) .. text .. "|r" +end + +local function SeedOK() + return Codex.Seed ~= nil and Codex.Seed.Available() +end + +-- Angaben des Servers zu einer Kreatur / einem Objekt ueber die ID (ClassicAPI: C_CreatureInfo, C_GameObjectInfo). +-- request = true laedt Unbekanntes einmal nach und zeichnet die Detailseite danach neu (nie in Listen: sonst Anfrageflut) +local srvAsked, srvRedraw = {}, false +local function ServerInfo(kind, id, request) + if type(id) ~= "number" then return nil end + local info, asked + local C = kind == "units" and _G.C_CreatureInfo or _G.C_GameObjectInfo + local get = C and (kind == "units" and C.GetCreatureInfoByID or C.GetGameObjectInfoByID) + if get then + local ok, r = pcall(get, id) + if ok and type(r) == "table" then info = r end + end + if not info and Codex.Catalog and Codex.Catalog.GetEntity then + local nm, sb, f = Codex.Catalog.GetEntity(kind == "units" and "c" or "o", id) + if nm then + info = { name = nm, subName = sb, type = f and f.type, rank = f and f.rank, family = f and f.family, fromCatalog = true } + end + end + if not info and request and C then + local key = (kind == "units" and "u" or "o") .. id + local req = kind == "units" and C.RequestLoadCreatureByID or C.RequestLoadGameObjectByID + if req and not srvAsked[key] then + srvAsked[key] = true + asked = true + pcall(req, id) + end + end + if asked and not srvRedraw and _G.C_Timer then + srvRedraw = true + _G.C_Timer.After(1.5, function() + srvRedraw = false + if Codex.RedrawDetail then Codex.RedrawDetail() end + end) + end + return info +end + +-- Spielobjekt-Typen (GameObjectType): englisch, deutsch +local GO_TYPES = { + [0] = { "Door", "Tür" }, [1] = { "Button", "Schalter" }, [2] = { "Quest giver", "Questgeber" }, [3] = { "Chest", "Truhe" }, + [5] = { "Generic", "Allgemein" }, [6] = { "Trap", "Falle" }, [7] = { "Chair", "Stuhl" }, [8] = { "Spell focus", "Zauberfokus" }, + [9] = { "Text", "Text" }, [10] = { "Interactive object", "Interaktives Objekt" }, [11] = { "Transport", "Transport" }, + [17] = { "Fishing node", "Angelstelle" }, [19] = { "Mailbox", "Briefkasten" }, [22] = { "Spell caster", "Zauberauslöser" }, + [25] = { "Fishing hole", "Fischschwarm" }, +} + +-- Name einer Kreatur / eines Objekts: eigener Eintrag, sonst die Vorlage (nur wenn die Art bekannt ist), sonst der Server +local function UnitTitle(u, id, kind) + local name = Codex.NameOf(u) + if not name and kind and SeedOK() then + name = Codex.Seed.Name(kind, id) + end + if not name and kind then + local si = ServerInfo(kind, id, false) + if si and type(si.name) == "string" and si.name ~= "" then name = si.name end + end + return name or ("#" .. tostring(id)) +end + +local function SeedTag() + return "|cff8a8a96[" .. FW.L.CODEX_SEED_TAG .. "]|r" +end + +local function SeedPct(chance) + if not chance or chance <= 0 then return "" end -- Chance unbekannt + if chance >= 10 then + return string.format(FW.L.CODEX_SEED_CHANCE, string.format("%.0f", chance)) + end + if chance < 1 then + return string.format(FW.L.CODEX_SEED_CHANCE, string.format("%.2f", chance)) + end + return string.format(FW.L.CODEX_SEED_CHANCE, string.format("%.1f", chance)) +end + +local function RoleNames(kind, id) + local list = {} + for _, role in ipairs(Codex.RoleList(kind, id)) do + list[#list + 1] = FW.L["CODEX_ROLE_" .. role] or role + end + return list +end + + +local function LevelText(u) + local L = FW.L + if u.l1 and u.l2 then + if u.l1 == u.l2 then + return string.format(L.CODEX_LEVEL, u.l1) + end + return string.format(L.CODEX_LEVEL_RANGE, u.l1, u.l2) + end + return nil +end + +------------------------------------------------------------------------ +-- Verzeichnisse (Rueckwaerts-Suche), bei Aenderung neu aufgebaut +------------------------------------------------------------------------ + +local dirty = true +local itemIndex, itemIds + +-- Rueckgabe: index[itemID] = { u, o, r, qi, zones = { [mapID] = true }, best = hoechste Drop-Chance }, Liste der IDs +local function ItemIndex() + if itemIndex and not dirty then + return itemIndex, itemIds + end + local index, ids = {}, {} + local grid2 = Codex.GRID * Codex.GRID + local function Facts(id) + local f = index[id] + if not f then + f = { zones = {}, best = 0 } + index[id] = f + ids[#ids + 1] = id + end + return f + end + local function FromEntities(tbl, flag) + for _, ent in pairs(tbl) do + local maps = {} + for key in pairs(ent.cells or {}) do + maps[math.floor(key / grid2)] = true + end + for _, m in ipairs(ent.ez or {}) do maps[m] = true end + for iid in pairs(ent.iz or {}) do maps[-iid] = true end + for id in pairs(ent.wa or {}) do + local f = Facts(id) + f.v = true + for m in pairs(maps) do f.zones[m] = true end + end + for bi, bucket in ipairs({ ent, ent.alt or {} }) do + for id, d in pairs(bucket.d or {}) do + local f = Facts(id) + f[flag] = true + if d.qi then f.qi = true end + if bi == 1 and (bucket.k or 0) > 0 and d.n then + local chance = d.n / bucket.k + if chance > f.best then f.best = chance end + end + for m in pairs(maps) do f.zones[m] = true end + end + end + end + end + FromEntities(Codex.V().units, "u") + FromEntities(Codex.V().objects, "o") + -- im Auktionshaus gescannte Items (nicht in ids: sonst Flut von Item-Anfragen) + if Codex.ExtraItems then + local ok, extra = pcall(Codex.ExtraItems) + if ok and type(extra) == "table" then + for id in pairs(extra) do + if not index[id] then index[id] = { zones = {}, best = 0, ah = true } end + end + end + end + -- Items aus den Startdaten, deren Itemdaten schon geladen sind (sonst nur Zahlen ohne Namen) + if Codex.Forever and Codex.Forever.ItemIds then + for id in pairs(Codex.Forever.ItemIds()) do + if not index[id] and Util.GetItem(id) then + local it = Codex.Forever.Item(id) + local f = { zones = {}, best = 0, fe = true } + if it then + f.u = (#it.u > 0) or nil + f.o = (#it.o > 0) or nil + f.v = (#it.v > 0) or nil + for _, e in ipairs(it.u) do if e.chance / 100 > f.best then f.best = e.chance / 100 end end + end + index[id] = f + end + end + end + for _, q in pairs(Codex.V().quests) do + for _, list in ipairs({ q.fixed or {}, q.choice or {} }) do + for _, r in ipairs(list) do + local f = Facts(r.id) + f.r = true + if q.zone then f.zones[q.zone] = true end + end + end + for id in pairs(q.qi or {}) do + local f = Facts(id) + f.qi = true + if q.zone then f.zones[q.zone] = true end + end + end + -- von Hand gesetzte Zonen der Items (nur lokal) + for id, rec in pairs(Codex.V().ied or Codex.db.ied or {}) do + local z = rec.ez or (rec.ed and rec.ed.z) + if z and index[id] then + for _, m in ipairs(z) do index[id].zones[m] = true end + end + end + itemIndex, itemIds = index, ids + dirty = false + return index, ids +end + +function Codex.AllItemIds() + local _, ids = ItemIndex() + local list, seen = {}, {} + for _, id in ipairs(ids) do seen[id] = true list[#list + 1] = id end + if Codex.Forever and Codex.Forever.ItemIds then + for id in pairs(Codex.Forever.ItemIds()) do + if not seen[id] then seen[id] = true list[#list + 1] = id end + end + end + for id in pairs(Codex.db.cat and Codex.db.cat.i or {}) do + if type(id) == "number" and not seen[id] then seen[id] = true list[#list + 1] = id end + end + return list +end +function Codex.MarkItemsDirty() dirty = true end + +-- Wert-Filter: flt.stats = { { key, min, max }, ... } (bis zu 3 Zeilen), flt.ops[i] = "and" | "or" zwischen +-- Zeile i und der naechsten. UND bindet staerker als ODER. Aeltere Form: flt.stat / statMin / statMax (eine Zeile). +local MAX_STAT_ROWS = 3 + +local function StatRows(flt) + local rows = {} + if flt.stats then + for i = 1, MAX_STAT_ROWS do + local r = flt.stats[i] + if r and r.key then + rows[#rows + 1] = { key = r.key, min = r.min, max = r.max, op = flt.ops and flt.ops[i] or "and" } + end + end + elseif flt.stat then + rows[1] = { key = flt.stat, min = flt.statMin, max = flt.statMax, op = "and" } + end + return rows +end + +local function StatRowPass(st, r) + local v = st[r.key] or 0 + if r.min then + if v < r.min then return false end + elseif v <= 0 then + return false + end + if r.max and v > r.max then return false end + return true +end + +-- Gruppen: ODER trennt, UND verbindet. Das Operatorfeld einer Zeile gilt zur naechsten aktiven Zeile. +local function StatGroups(rows) + local groups = {} + for i, r in ipairs(rows) do + if i == 1 or rows[i - 1].op == "or" then + groups[#groups + 1] = { r } + else + local g = groups[#groups] + g[#g + 1] = r + end + end + return groups +end + +local function StatsPass(st, flt) + local rows = StatRows(flt) + if #rows == 0 then return true end + if not st then return false end + for _, g in ipairs(StatGroups(rows)) do + local all = true + for _, r in ipairs(g) do + if not StatRowPass(st, r) then all = false break end + end + if all then return true end + end + return false +end + +local function StatRowText(r) + local name = Codex.StatName(r.key) + if r.min and r.max then + return string.format("%s %s-%s", name, Codex.FormatStat(r.min), Codex.FormatStat(r.max)) + elseif r.min then + return string.format("%s >= %s", name, Codex.FormatStat(r.min)) + elseif r.max then + return string.format("%s <= %s", name, Codex.FormatStat(r.max)) + end + return name +end + +-- Klartext des Wert-Filters, zum Beispiel "(Beweglichkeit 8-10 UND Intelligenz 5-7) ODER Schwimmtempo" +local function StatPreview(flt) + local rows = StatRows(flt) + if #rows < 2 then return "" end + local L = FW.L + local groups = StatGroups(rows) + local parts = {} + for _, g in ipairs(groups) do + local texts = {} + for _, r in ipairs(g) do texts[#texts + 1] = StatRowText(r) end + local text = table.concat(texts, " " .. L.CODEX_OP_AND .. " ") + if #g > 1 and #groups > 1 then text = "(" .. text .. ")" end + parts[#parts + 1] = text + end + return table.concat(parts, " " .. L.CODEX_OP_OR .. " ") +end + +-- Filter fuer Items. Filter, die Itemdaten brauchen, schliessen noch nicht geladene Items aus. +local function FilterActive(flt) + local n = 0 + if next(flt.q) then n = n + 1 end + for _, k in ipairs({ "type", "sub", "slot", "src", "zone", "ilMin", "ilMax", "rlMin", "rlMax", "pMin", "pMax", "aMin", "aMax", "stat", "statMin", "statMax" }) do + if flt[k] ~= nil then n = n + 1 end + end + for i = 1, MAX_STAT_ROWS do + local r = flt.stats and flt.stats[i] + if r and r.key then n = n + 1 end + end + return n +end + +local function PassFilter(flt, facts, info, id) + if flt.src == "vendor" and not (facts.v or (id and SeedOK() and Codex.Seed.ItemHasVendor(id)) or (id and Codex.Forever and Codex.Forever.ItemHasVendor and Codex.Forever.ItemHasVendor(id))) then return false end + if flt.src == "unit" and not facts.u then return false end + if flt.src == "object" and not facts.o then return false end + if flt.src == "reward" and not facts.r then return false end + if flt.src == "quest" and not facts.qi then return false end + if flt.zone and not facts.zones[flt.zone] then return false end + local hasStats = #StatRows(flt) > 0 + local needInfo = next(flt.q) or flt.type or flt.sub or flt.slot or flt.ilMin or flt.ilMax + or flt.rlMin or flt.rlMax or flt.pMin or flt.pMax or flt.aMin or flt.aMax or hasStats or flt.statMin or flt.statMax + if not needInfo then + return true + end + if not info then return false end + if next(flt.q) and not flt.q[info.light and (info.quality or -1) or (info.quality or 1)] then return false end + if flt.type and info.type ~= flt.type then return false end + if flt.sub and info.subType ~= flt.sub then return false end + if flt.slot and info.equipLoc ~= flt.slot then return false end + local il, rl, price = info.itemLevel or 0, info.minLevel or 0, (info.sellPrice or 0) / 10000 + if flt.ilMin and il < flt.ilMin then return false end + if flt.ilMax and il > flt.ilMax then return false end + if flt.rlMin and rl < flt.rlMin then return false end + if flt.rlMax and rl > flt.rlMax then return false end + if flt.pMin and price < flt.pMin then return false end + if flt.pMax and price > flt.pMax then return false end + if flt.aMin or flt.aMax then + local ah = info.id and Codex.AuctionProvider and Codex.AuctionPrice(info.id) + ah = (ah or 0) / 10000 + if not (ah > 0) then return false end + if flt.aMin and ah < flt.aMin then return false end + if flt.aMax and ah > flt.aMax then return false end + end + if hasStats then + local st = info.id and Codex.db.istats and Codex.db.istats[info.id] + if not StatsPass(st, flt) then return false end + elseif flt.statMin or flt.statMax then + if not (info.id and Codex.db.istats and Codex.db.istats[info.id]) then return false end + end + return true +end + +------------------------------------------------------------------------ +-- Eintraege fuer die Liste +------------------------------------------------------------------------ + +local function Match(text, haystack) + return haystack and haystack:lower():find(text, 1, true) ~= nil +end + +-- Suchtext passt auf einen der Namen (Spiel, Deutsch, Englisch)? +local function MatchNames(text, e) + return e and (Match(text, e.n) or Match(text, e.cde) or Match(text, e.cen)) +end + +local function MapOfCells(cells) + local m = Codex.MainMap(cells) + return m and Codex.MapName(m) or nil +end + +-- Zone eines Datensatzes: von Hand gesetzte zuerst, sonst die Hauptkarte der Fundorte +-- "Level 1-4" / "Level 3" fuer eine Gebietsspanne +local function RangeText(lo, hi) + if not lo then return nil end + if not hi or hi == lo then return string.format(FW.L.CODEX_LEVEL, lo) end + return string.format(FW.L.CODEX_LEVEL, lo .. "-" .. hi) +end + +local function ZoneOf(ent) + local z = Codex.ZonesOf(ent)[1] + return z and Codex.MapName(z) or nil +end + +local function ClassLabel(cls) + local L = FW.L + if cls == "elite" or cls == "rareelite" then return L.CODEX_XP_ELITE end + if cls == "rare" then return L.CODEX_XP_RARE end + if cls == "worldboss" then return L.CODEX_XP_BOSS end + return nil +end + +XPTitle = function(r) + local text = string.format(FW.L.CODEX_XP_TITLE, r.pl, r.ml) + local label = ClassLabel(r.cls) + if label then text = text .. " (" .. label .. ")" end + if r.rested then + text = text .. " [" .. FW.L.CODEX_XP_RESTED_TAG .. "]" + elseif r.bonus then + text = text .. " [" .. FW.L.CODEX_XP_BONUS_TAG .. "]" + end + return text +end + +XPKey = function(r) + return r.pl .. ":" .. r.ml .. ":" .. r.cls .. ":" .. (r.rested and "r" or r.bonus and "b" or "a") +end + +-- Vorlage: Eintraege fuer Quests, Kreaturen und Objekte, die es nur in der Vorlage gibt (einmal gebaut und gemerkt) +local seedEntries = {} +local mapNames = {} + +local function CachedMapName(m) + local n = mapNames[m] + if not n then + n = Codex.MapName(m) + mapNames[m] = n + end + return n +end + +local function RankLabel(rank) + local L = FW.L + if rank == 1 or rank == 2 then return L.CODEX_XP_ELITE end + if rank == 3 then return L.CODEX_XP_BOSS end + if rank == 4 then return L.CODEX_XP_RARE end + return nil +end + +local ChainText +local function SeedList(kind) + local key = kind .. ":" .. Codex.Lang() + local cached = seedEntries[key] + if cached then + return cached + end + local L = FW.L + local Seed = Codex.Seed + local list = {} + for _, id in ipairs(Seed.IDs(kind)) do + local e + if kind == "quests" then + local q = Seed.Quest(id) + local title = Seed.QuestTitle(id) or ("Quest #" .. id) + local sub = {} + if q.lvl and q.lvl > 0 then sub[#sub + 1] = string.format(L.CODEX_LEVEL, q.lvl) end + local ref = q.start[1] or q.stop[1] + local zone + if ref and ref.kind ~= "items" then + local m = Seed.MapOf(ref.kind, ref.id) + zone = m and CachedMapName(m) or nil + end + if zone then sub[#sub + 1] = zone end + local chainText = ChainText(id) + if chainText then sub[#sub + 1] = chainText end + sub[#sub + 1] = SeedTag() + e = { id = id, title = title, sub = table.concat(sub, " | "), icon = ICON.quests, name = title:lower(), + recent = 0, seed = true, zone = zone and zone:lower() or "", zoneName = zone, l1 = q.lvl, l2 = q.lvl } + else + local ent = Seed.Entity(kind, id) + local title = Seed.Name(kind, id) or ("#" .. id) + local sub = {} + if kind == "units" and ent.l1 then + sub[#sub + 1] = ent.l1 == ent.l2 and string.format(L.CODEX_LEVEL, ent.l1) or string.format(L.CODEX_LEVEL_RANGE, ent.l1, ent.l2) + end + local m = Seed.MapOf(kind, id) + local zone = m and CachedMapName(m) or nil + if zone then sub[#sub + 1] = zone end + local rank = kind == "units" and RankLabel(ent.rank) or nil + if rank then sub[#sub + 1] = rank end + local roles = RoleNames(kind, id) + if #roles > 0 then sub[#sub + 1] = table.concat(roles, ", ") end + sub[#sub + 1] = SeedTag() + e = { id = id, title = title, sub = table.concat(sub, " | "), icon = ICON[kind], name = title:lower(), recent = 0, + seed = true, gold = -1, unitID = kind == "units" and id or nil, zone = zone and zone:lower() or "", + l1 = ent.l1, l2 = ent.l2 } + end + list[#list + 1] = e + end + seedEntries[key] = list + return list +end + +-- Katalog: Quests, von denen nur Titel und Stufe bekannt sind (gebaut je Stand des Katalogs) +local catEntries, catRev, catLang +local function CatList() + local C = Codex.Catalog + if not C then return {} end + local rev = C.Rev() + if catEntries and catRev == rev then return catEntries end + local L = FW.L + local list = {} + for _, id in ipairs(C.IDs()) do + local title, lv = C.Get(id) + if title then + local sub = {} + if lv then sub[#sub + 1] = string.format(L.CODEX_LEVEL, lv) end + sub[#sub + 1] = "|cff8a8a96[" .. L.CODEX_CAT_TAG .. "]|r" + local meta = C.QuestMeta and C.QuestMeta(id) + if meta then + if meta.zone then table.insert(sub, #sub, meta.zone) end + if meta.info then table.insert(sub, #sub, meta.info) end + end + local zn = meta and meta.zone + list[#list + 1] = { id = id, title = title, sub = table.concat(sub, " | "), icon = ICON.quests, name = title:lower(), + recent = 0, cat = true, zone = zn and zn:lower() or "", zoneName = zn, l1 = lv, l2 = lv } + end + end + catEntries, catRev = list, rev + return list +end + +local function SeedHit(text, kind, e) + if Codex.Seed.Haystack(kind, e.id):find(text, 1, true) then + return true + end + return e.zone ~= nil and e.zone ~= "" and e.zone:find(text, 1, true) ~= nil +end + +local function RolePass(kind, id, role) + if not role then return true end + return Codex.RolesOf(kind, id)[role] ~= nil +end + +local CHAIN_STEPS = { "in", "start", "mid", "end", "none" } + +-- Questkette (nur mit Vorlage bekannt): chain = nil/"in"/"start"/"mid"/"end"/"none" +local function ChainPass(id, chain) + if not chain then return true end + local role = Codex.ChainRole(id) + if chain == "in" then return role ~= nil end + if chain == "none" then return role == nil end + return role == chain +end + +local STATUS_STEPS = { "done", "active", "open" } +local STATUS_MARK = { + done = "Interface\\RaidFrame\\ReadyCheck-Ready", + active = "Interface\\Icons\\Ability_Rogue_Sprint", +} + +local function StatusPass(id, status) + if not status then return true end + local st = Codex.QuestStatus(id) + if status == "open" then return st == nil end + return st == status +end + +-- "Kette 2/4" fuer die Zeile, wenn die Vorlage die Quest in einer Kette kennt +ChainText = function(id) + if not SeedOK() then return nil end + local pos, total = Codex.Seed.ChainPos(id) + if pos then return string.format(FW.L.CODEX_CHAIN_POS, pos, total) end + return nil +end + +-- Kampfdauer einer Kreatur: eigene Klasse, sonst Durchschnitt aller Klassen +local function UnitTTK(u) + if not (Codex.Time and u) then return nil end + local own = Codex.Time.UnitAverage(u) + if own and own > 0 then return own end + local list = Codex.Time.UnitClasses(u) + if #list == 0 then return nil end + local sum = 0 + for _, c in ipairs(list) do sum = sum + c.secs end + local avg = sum / #list + return avg > 0 and avg or nil +end + +-- Erfahrung je Kill der eigenen Stufe (sonst der hoechsten bekannten) +local function UnitXPAvg(u) + if not (u and u.xp) then return nil end + local pl = UnitLevel and UnitLevel("player") or nil + local s = pl and u.xp[pl] + if not s then + local best + for lv, st in pairs(u.xp) do + if not best or lv > best then best, s = lv, st end + end + end + return s and s.n and s.n > 0 and (s.sum / s.n) or nil +end + +-- niedrigster beobachteter Einkaufspreis bei Haendlern (Kupfer) je Item +local function LowestBuyPrices() + local lowest = {} + for _, u in pairs(Codex.V().units) do + for id, w in pairs(u.wa or {}) do + for price in pairs(w.pr or {}) do + if price > 0 and (not lowest[id] or price < lowest[id]) then lowest[id] = price end + end + end + end + return lowest +end + +local function ItemValueOf(id) + local ah = Codex.AuctionProvider and Codex.AuctionPrice(id) + if ah and ah > 0 then return ah end + local info = Util.GetItem(id) + return info and info.sellPrice or nil +end + + +-- Suchkuerzel: stufe:20-25, zone:Durotar, haendler:Ruestung (werden aus dem Suchtext herausgenommen) +local OP_KEYS = { + stufe = "lvl", level = "lvl", lvl = "lvl", lv = "lvl", + zone = "zone", gebiet = "zone", + ["händler"] = "vendor", haendler = "vendor", vendor = "vendor", ["verkäufer"] = "vendor", +} + +local function ParseSearch(text) + local ops + local rest = text:gsub("(%S-):(%S+)", function(key, value) + local op = OP_KEYS[key] + if not op then + return nil + end + ops = ops or {} + if op == "lvl" then + local a, b = value:match("^(%d+)%-(%d+)$") + if not a then a = value:match("^(%d+)$"); b = a end + if not a then return nil end + ops.lvl = { tonumber(a), tonumber(b) } + else + ops[op] = value:gsub("_", " ") + end + return "" + end) + rest = rest:gsub("^%s+", ""):gsub("%s+$", ""):gsub("%s+", " ") + return rest, ops +end + +-- Nachfilter fuer die Kuerzel; e = Listeneintrag (mit l1/l2/zone) +local function OpsPass(kind, e, ops) + if not ops then return true end + if ops.lvl then + local lo, hi = e.l1, e.l2 or e.l1 + if kind == "items" then + local info = Util.GetItem(e.id) + lo = info and info.minLevel or nil + hi = lo + end + if not lo or hi < ops.lvl[1] or lo > ops.lvl[2] then return false end + end + if ops.zone then + if not (e.zone and e.zone:find(ops.zone, 1, true)) then return false end + end + if ops.vendor then + if kind ~= "units" then return false end + local want = ops.vendor + local found = false + local live = Codex.V().units[e.id] + for itemID in pairs(live and live.wa or {}) do + local name = Codex:ItemName(itemID) + if name and name:lower():find(want, 1, true) then found = true break end + end + if not found and SeedOK() then + local roles = Codex.Seed.Roles("units", e.id) + if roles and roles.vendor then + for _, itemID in ipairs(Codex.Seed.VendorItems(e.id)) do + local name = Codex:ItemName(itemID) or Codex.Seed.Name("items", itemID) + if name and name:lower():find(want, 1, true) then found = true break end + end + end + end + if not found then return false end + end + return true +end + + +-- Katalog-Eintraege fuer Kreaturen/Objekte (aus der Server-Abfrage und den Zielen der Quests), je Stand des Katalogs gemerkt +local catEnt, catEntRev = {}, {} +local ctNames = {} +local function CreatureTypeName(t) + if type(t) ~= "number" then return nil end + local n = ctNames[t] + if n == nil then + n = false + local CC = _G.C_CreatureInfo + if CC and CC.GetCreatureTypeInfo then + local ok, ti = pcall(CC.GetCreatureTypeInfo, t) + if ok and type(ti) == "table" and type(ti.name) == "string" then n = ti.name end + end + ctNames[t] = n + end + return n or nil +end + +local function CatEntities(kind) + local C = Codex.Catalog + if not (C and C.Reverse) then return {} end + local rev = C.Rev() .. ":" .. Codex.Lang() + if catEnt[kind] and catEntRev[kind] == rev then return catEnt[kind] end + local L = FW.L + local store = Codex.db and Codex.db.cat and Codex.db.cat[kind == "units" and "c" or "o"] or {} + local targets = C.Reverse()[kind == "units" and "monster" or "object"] + local list, seen = {}, {} + local function Add(id) + if seen[id] then return end + seen[id] = true + local name, subName, f = C.GetEntity(kind == "units" and "c" or "o", id) + local qs = targets[id] + local sub = {} + if f then + if kind == "units" then + local tn = CreatureTypeName(f.type) + if tn then sub[#sub + 1] = tn end + if RankLabel(f.rank) then sub[#sub + 1] = RankLabel(f.rank) end + else + local g = GO_TYPES[f.type] + if g then sub[#sub + 1] = Codex.Lang() == "en" and g[1] or g[2] end + end + end + if subName then sub[#sub + 1] = "<" .. subName .. ">" end + if qs then sub[#sub + 1] = string.format(L.CODEX_CAT_TARGET, #qs) end + sub[#sub + 1] = "|cff8a8a96[" .. L.CODEX_CAT_TAG .. "]|r" + local title = name or ("#" .. id) + list[#list + 1] = { + id = id, title = title, name = title:lower(), subName = subName, sub = table.concat(sub, " | "), + icon = kind == "units" and ICON.units or ICON[kind], recent = 0, cat = true, + unitID = kind == "units" and id or nil, gold = -1, zone = "", + } + end + for id in pairs(store) do if type(id) == "number" then Add(id) end end + for id in pairs(targets) do Add(id) end + catEnt[kind], catEntRev[kind] = list, rev + return list +end + +-- opts: seed = Vorlage anzeigen, role = nur Kreaturen/Objekte mit dieser Rolle, chain = Questkette +local function BuildEntries(kind, text, flt, opts) + local L = FW.L + local db = Codex.V() + opts = opts or {} + text = (text or ""):lower() + local ops + text, ops = ParseSearch(text) + local list = {} + local useSeed = opts.seed and SeedOK() + local role = opts.role + local chain = SeedOK() and opts.chain or nil + local status = opts.status + + if kind == "quests" then + for id, q in pairs(db.quests) do + local zone = q.zone and Codex.MapName(q.zone) or nil + if not zone and Codex.Catalog and Codex.Catalog.QuestMeta then + local m = Codex.Catalog.QuestMeta(id) + zone = m and m.zone or nil + end + local ok = text == "" + or MatchNames(text, q) or Match(text, q.t) or Match(text, zone) + or (q.give and Match(text, q.give.n)) or (q.turn and Match(text, q.turn.n)) + or tostring(id) == text + if ok and ChainPass(id, chain) and StatusPass(id, status) then + local sub = {} + local title = Codex.QuestTitle(q, id) + if q.lvl then sub[#sub + 1] = string.format(L.CODEX_LEVEL, q.lvl) end + if zone then sub[#sub + 1] = zone end + local chainText = ChainText(id) + if chainText then sub[#sub + 1] = chainText end + if (q.done or 0) > 0 then sub[#sub + 1] = string.format(L.CODEX_DONE, q.done) end + list[#list + 1] = { + id = id, title = title, sub = table.concat(sub, " | "), + icon = ICON.quests, name = title:lower(), recent = q.last or 0, + l1 = q.lvl, l2 = q.lvl, zone = zone and zone:lower() or "", zoneName = zone, + } + end + end + if useSeed then + for _, e in ipairs(SeedList("quests")) do + if not db.quests[e.id] and (text == "" or SeedHit(text, "quests", e) or tostring(e.id) == text) + and ChainPass(e.id, chain) and StatusPass(e.id, status) then + list[#list + 1] = e + end + end + end + -- Katalog: nur Titel und Stufe (nicht, wenn es schon einen Datensatz oder die Vorlage gibt) + if not chain then + local seedOn = SeedOK() + for _, e in ipairs(CatList()) do + if not db.quests[e.id] and not (seedOn and Codex.Seed.Quest(e.id)) + and (text == "" or e.name:find(text, 1, true) or tostring(e.id) == text) + and StatusPass(e.id, status) then + list[#list + 1] = e + end + end + end + elseif kind == "units" or kind == "objects" then + local src = kind == "units" and db.units or db.objects + for id, u in pairs(src) do + local zone = ZoneOf(u) + if (text == "" or MatchNames(text, u) or Match(text, zone) or Match(text, u.ti) or tostring(id) == text) + and RolePass(kind, id, role) then + local sub = {} + local lvl = LevelText(u) + if lvl then sub[#sub + 1] = lvl end + if zone then sub[#sub + 1] = zone end + if (u.k or 0) > 0 then sub[#sub + 1] = string.format(L.CODEX_KILLS, u.k) end + local value = Codex.KillValue(u) + if value and value >= 1 then sub[#sub + 1] = string.format(L.CODEX_VALUE_SHORT, FormatMoney(value)) end + local roles = RoleNames(kind, id) + if #roles > 0 then sub[#sub + 1] = table.concat(roles, ", ") end + if u.ti then sub[#sub + 1] = u.ti end + if kind == "units" and u.ct and CT_ICONS[u.ct] then sub[#sub + 1] = L["CODEX_CT_" .. u.ct] end + list[#list + 1] = { + id = id, title = UnitTitle(u, id, kind), sub = table.concat(sub, " | "), + icon = kind == "units" and UnitIcon(u) or ICON[kind], name = (UnitTitle(u, id, kind)):lower(), recent = u.lt or 0, + unitID = kind == "units" and id or nil, + gold = value or -1, + l1 = u.l1, l2 = u.l2, zone = zone and zone:lower() or "", + } + end + end + if useSeed then + for _, e in ipairs(SeedList(kind)) do + if not src[e.id] and (text == "" or SeedHit(text, kind, e) or tostring(e.id) == text) + and RolePass(kind, e.id, role) then + list[#list + 1] = e + end + end + end + -- Katalog: Kreaturen/Objekte aus der Server-Abfrage und Ziele aus den Quest-Einzelheiten + if not role then + for _, e in ipairs(CatEntities(kind)) do + if not src[e.id] and not (useSeed and Codex.Seed.Name(kind, e.id)) + and (text == "" or e.name:find(text, 1, true) or tostring(e.id) == text + or (e.subName and e.subName:lower():find(text, 1, true))) then + list[#list + 1] = e + end + end + end + elseif kind == "zones" then + local pl = UnitLevel and UnitLevel("player") or 1 + for key, z in pairs(Codex.Zones.All()) do + local name = Codex.MapName(key) + local pass = true + if opts.zoneSel == "world" then pass = not z.dungeon + elseif opts.zoneSel == "dungeon" then pass = z.dungeon + elseif opts.zoneSel == "fit" then pass = Codex.Zones.Compare(key, pl, 2) == "in" + elseif opts.zoneSel == "data" then pass = not z.few end + if pass and (text == "" or Match(text, name) or tostring(math.abs(key)) == text) then + local sub = {} + local range = RangeText(z.lo, z.hi) + if range then + sub[#sub + 1] = range .. ((z.avg and not z.manual) and string.format(" (%s %.1f)", L.CODEX_ZONE_AVG, z.avg) or "") + end + if z.manual then sub[#sub + 1] = L.CODEX_ZONE_MANUAL end + if z.few and not z.manual then sub[#sub + 1] = L.CODEX_ZONE_FEW end + sub[#sub + 1] = string.format(L.CODEX_ZONE_UNITS, z.units) + if #z.out > 0 then sub[#sub + 1] = string.format(L.CODEX_ZONE_OUTLIERS, #z.out) end + if #z.special > 0 then sub[#sub + 1] = string.format(L.CODEX_ZONE_SPECIAL, #z.special) end + if z.dungeon then sub[#sub + 1] = L.CODEX_PROPS_DG_YES end + list[#list + 1] = { + id = key, title = name, sub = table.concat(sub, " | "), icon = ICON.zones, name = name:lower(), + recent = z.units, l1 = z.lo, l2 = z.hi, zone = name:lower(), + zlvl = z.lo and (z.lo * 1000 + (z.hi or z.lo)) or -1, cnt = z.units, + } + end + end + elseif kind == "learn" then + local plan = opts.class and Codex.LearnPlan(opts.class) + if plan then + local pl = UnitLevel and UnitLevel("player") or 1 + for _, lv in ipairs(plan.order) do + local g = plan.levels[lv] + local hit = text == "" or tostring(lv) == text + if not hit then + for _, sp in ipairs(g.spells) do + if Match(text, sp.nm) then hit = true break end + end + end + if hit then + local sub = string.format(L.CODEX_LEARN_SUB, #g.spells, FormatMoney(g.cost)) + if lv > pl then + sub = sub .. " | " .. string.format(L.CODEX_LEARN_SUMSHORT, FormatMoney(Codex.LearnCost(plan, pl, lv))) + end + list[#list + 1] = { + id = lv, title = lv > 0 and string.format(L.CODEX_LEARN_TITLE, lv) or L.CODEX_LEARN_LVUNKNOWN, + sub = sub, icon = ICON.learn, name = string.format("%03d", lv), recent = lv, + step = lv > 0 and lv or 1e9, + } + end + end + end + elseif kind == "xp" then + for _, r in ipairs(Codex:XPRows(true)) do + local title = XPTitle(r) + if text == "" or Match(text, title) or tostring(r.pl) == text or tostring(r.ml) == text then + local secs = (not r.bonus and r.cls == "normal") and OwnTTK(r.pl, r.ml) or nil + list[#list + 1] = { + id = XPKey(r), title = title, + sub = string.format(L.CODEX_XP_ROW, r.avg, r.pred, r.diff, r.n) + .. ((secs and secs > 0) and (" | " .. string.format(L.CODEX_TTK_ROW, secs, r.avg / secs * 60)) or ""), + xpm = (secs and secs > 0) and (r.avg / secs * 60) or nil, + icon = ICON.xp, name = string.format("%03d%03d%s%s", 999 - r.pl, r.ml, r.cls, r.bonus and "b" or "a"), + recent = r.n, + } + end + end + else + local index = ItemIndex() + local function ItemEntry(id, facts, name, seed) + local info = Util.GetItem(id) + -- Das Spiel kennt viele Items noch nicht (nicht im Zwischenspeicher). Dann reichen gemerkte Werte: + -- Qualitaet aus dem Merker, Stufe/Mindeststufe/Preis aus dem Katalog. So filtern Qualitaet, Stufe und Preis + -- auch fuer Items, die noch nicht geladen sind (Typ, Platz und Werte brauchen weiter echte Itemdaten). + local light + if not info then + local nm, cq, il, ml, sp = nil, nil, nil, nil, nil + local Cat = Codex.Catalog + if Cat and Cat.GetItem then nm, cq, il, ml, sp = Cat.GetItem(id) end + local q = (Codex.db.iq and Codex.db.iq[id]) or cq + if q or il then + light = { id = id, name = nm, quality = q, itemLevel = il, minLevel = ml, sellPrice = sp, light = true } + end + end + if not PassFilter(flt, facts, info or light, id) then + return + end + if not info then info = light end + local sub = {} + if info then + if (info.itemLevel or 0) > 1 then sub[#sub + 1] = string.format(L.CODEX_ILVL_SHORT, info.itemLevel) end + if info.type then + sub[#sub + 1] = info.type .. ((info.subType and info.subType ~= "" and info.subType ~= info.type) and (" · " .. info.subType) or "") + end + if (info.sellPrice or 0) > 0 then sub[#sub + 1] = FormatMoney(info.sellPrice) end + if info.light then sub[#sub + 1] = "#" .. id end + else + sub[#sub + 1] = "#" .. id + end + if seed then sub[#sub + 1] = SeedTag() end + if facts.ah then sub[#sub + 1] = "|cff8a8a96[" .. L.CODEX_AH_TAG .. "]|r" end + list[#list + 1] = { + id = id, title = name or ("#" .. id), sub = table.concat(sub, " | "), itemID = id, + name = (name or ""):lower(), recent = seed and 0 or id, + price = info and (info.sellPrice or 0) or -1, ilvl = info and (info.itemLevel or 0) or -1, + quality = info and (info.quality or (info.light and -1 or 1)) or -1, chance = facts.best or 0, seed = seed or nil, + } + end + for id, facts in pairs(index) do + local name = Codex:ItemName(id) + if text == "" or Match(text, name) or tostring(id) == text then + ItemEntry(id, facts, name, false) + end + end + -- Items, die es nur in der Vorlage gibt + if useSeed then + local Seed = Codex.Seed + for _, id in ipairs(Seed.IDs("items")) do + if not index[id] and (text == "" or Seed.Haystack("items", id):find(text, 1, true) or tostring(id) == text) then + local it = Seed.Item(id) + local facts = { zones = {}, best = it and it.u[1] and it.u[1].chance / 100 or 0, + u = it and #it.u > 0 or nil, o = it and #it.o > 0 or nil } + ItemEntry(id, facts, Seed.Name("items", id), true) + end + end + end + end + if opts.fav and Codex.FavSupported(kind) then + local kept = {} + for _, e in ipairs(list) do + if Codex.IsFav(kind, e.id) then kept[#kept + 1] = e end + end + list = kept + end + if ops then + local kept = {} + for _, e in ipairs(list) do + if OpsPass(kind, e, ops) then kept[#kept + 1] = e end + end + list = kept + end + return list +end + +------------------------------------------------------------------------ +-- Tab +------------------------------------------------------------------------ + +local function Build(content) + local L = FW.L + local f = CreateFrame("Frame", nil, content) + + local kind, selected, search = "quests", nil, "" + local sortBy, sortRev, flt, filterOpen = {}, {}, { q = {} }, false + local farmOn = false -- Farm-Ranking (Kreaturen) + local history = {} -- Verlauf fuer "Zurueck" + local listRows, detailRows = {}, {} + local Refresh, RefreshList, ShowDetail, Go, UpdateFilterUI, Layout + local nameCtl + local roleSel = {} -- gewaehlte Rolle je Art (Kreaturen, Objekte) + local chainSel = nil -- gewaehlte Questkette (nur Quests) + local statusSel = nil -- gewaehlter Quest-Status (nur Quests) + local zoneSel = nil -- gewaehlte Gebietsart (nur Gebiete) + local learnSel = nil -- gewaehlte Klasse (Lernplan) + local favOnly = {} -- nur Favoriten je Art + local collapsed = {} -- eingeklappte Gebiete (Quests nach Gebiet) + local dataVersion = 0 -- zaehlt jede Datenaenderung; merkt sich die sortierte Liste dazwischen + local memo = {} + + local function SeedOn() + return SeedOK() and Codex.db.settings.showSeed ~= false + end + + ---------------- Kopf: Arten ---------------- + local kindButtons = {} + local KIND_GAP = 4 + for i, k in ipairs(KINDS) do local k = k + local b = UI.CreateButton(f, L[k.label], 60, 28, function() + kind, selected = k.id, nil + Refresh() + end, "default") + kindButtons[k.id] = b + end + -- "Erfahrung" ist ein Werkzeug fuer Entwickler: der Knopf erscheint nur mit dem Modul Freewood-OctoWoW-Dev + local function KindVisible(id) + return id ~= "xp" or FW.Dev ~= nil + end + local function LayoutKinds() + local shown = {} + for _, k in ipairs(KINDS) do + if KindVisible(k.id) then shown[#shown + 1] = k end + end + local w = math.floor((LIST_W - KIND_GAP * (#shown - 1)) / #shown) + for _, k in ipairs(KINDS) do + local b = kindButtons[k.id] + if KindVisible(k.id) then + local idx + for i, s in ipairs(shown) do if s == k then idx = i end end + b:SetWidth(w) + b:ClearAllPoints() + b:SetPoint("TOPLEFT", f, "TOPLEFT", (idx - 1) * (w + KIND_GAP), 0) + b:Show() + -- OctoWoW: die Schrift ist breiter als im Forever-Client; Text verkleinern, bis er in den Knopf passt + local size = 12 + UI.SetFont(b.label, "body", size) + while size > 8 and (b.label:GetStringWidth() or 0) > w - 8 do + size = size - 1 + UI.SetFont(b.label, "body", size) + end + else + b:Hide() + end + end + if not KindVisible(kind) then kind, selected = "quests", nil end + end + LayoutKinds() + + ---------------- links: Suche und Liste ---------------- + local box = UI.CreatePanel(f, "bgDeep", "bronze") + box:SetHeight(26) + box:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -38) + box:SetWidth(LIST_W - 188 - 30) + local edit = CreateFrame("EditBox", nil, box) + edit:SetAutoFocus(false) + edit:SetPoint("TOPLEFT", box, "TOPLEFT", 8, -2) + edit:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -8, 2) + edit:SetMaxLetters(60) + if not edit:SetFont(UI.GetFontPath("body"), 12, "") then + edit:SetFont("Fonts\\FRIZQT__.TTF", 12, "") + end + edit:SetTextColor(UI.Color("text")) + edit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end) + local hint = UI.CreateLabel(box, L.CODEX_SEARCH, { size = 12, color = "textDim" }) + hint:SetPoint("LEFT", box, "LEFT", 10, 0) + edit:SetScript("OnTextChanged", function(self) + search = self:GetText() or "" + if search == "" then hint:Show() else hint:Hide() end + if Refresh then Refresh() end + end) + + local function CurrentSort() + return sortBy[kind] or SORTS[kind][1] + end + local function SortModes() + local list = {} + for _, m in ipairs(SORTS[kind]) do + if (m ~= "ah" and m ~= "ahkill" and m ~= "gpmah" and m ~= "flip") or Codex.AuctionProvider then + list[#list + 1] = { value = m, text = L["CODEX_SORTBY_" .. m] or m } + end + end + return list + end + local sortDD = UI.CreateDropdown(f, 150, 26, { + getOptions = SortModes, + textOf = function(v) return L["CODEX_SORTBY_" .. v] or v end, + onChange = function(v) + sortBy[kind] = v + sortRev[kind] = false + Refresh() + end, + }) + sortDD:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W - 150, -38) + local dirButton = UI.CreateButton(f, "", 26, 26, function() + sortRev[kind] = not sortRev[kind] + Refresh() + end, "default") + dirButton:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W - 180, -38) + local dirTip = function(self) + if GameTooltip then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + GameTooltip:SetText(L.CODEX_SORT_DIR_TIP) + GameTooltip:Show() + end + end + if dirButton.HookScript then + dirButton:HookScript("OnEnter", dirTip) + dirButton:HookScript("OnLeave", function() if GameTooltip then GameTooltip:Hide() end end) + end + -- Pfeil als Textur: haengt davon ab, ob aktuell aufsteigend sortiert wird + dirButton.arrow = dirButton:CreateTexture(nil, "OVERLAY") + -- derselbe Pfeil wie bei der Wegfindung (zeigt nach oben); abwaerts wird er gespiegelt + dirButton.arrow:SetTexture("Interface\\Minimap\\ROTATING-MINIMAPARROW") + dirButton.arrow:SetVertexColor(UI.Color("goldLight")) + dirButton.arrow:SetSize(16, 16) + dirButton.arrow:SetPoint("CENTER", dirButton, "CENTER", 0, 0) + + -- nur Favoriten (Stern neben der Suche) + local favToggle = UI.CreateButton(f, "", 26, 26, function() + favOnly[kind] = not favOnly[kind] + dataVersion = dataVersion + 1 + Refresh() + end, "default") + favToggle:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W - 188 - 26, -38) + favToggle.star = favToggle:CreateTexture(nil, "OVERLAY") + -- gelber Stern aus dem Zielmarkierungs-Bogen (Feld oben links) + favToggle.star:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons") + favToggle.star:SetTexCoord(0, 0.25, 0, 0.25) + favToggle.star:SetSize(16, 16) + favToggle.star:SetPoint("CENTER", favToggle, "CENTER", 0, 0) + if favToggle.HookScript then + favToggle:HookScript("OnEnter", function(self) + if GameTooltip then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + GameTooltip:SetText(L.CODEX_FAV_ONLY) + GameTooltip:Show() + end + end) + favToggle:HookScript("OnLeave", function() if GameTooltip then GameTooltip:Hide() end end) + end + + local countLabel = UI.CreateLabel(f, "", { size = 11, color = "textDim" }) + countLabel:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -72) + countLabel:SetWidth(LIST_W) + countLabel:SetWordWrap(false) + + ---------------- Filter (nur Items) ---------------- + local ROW, PAD = 26, 4 + local function FilterH() + return (Codex.AuctionProvider and 9 or 8) * (ROW + PAD) - PAD + end + local FILTER_H = FilterH() + local fp = CreateFrame("Frame", nil, f) + fp:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -92) + fp:SetSize(LIST_W, FILTER_H) + fp:Hide() + local syncing = false + local qualityButtons, dropdowns, numBoxes, opButtons = {}, {}, {}, {} + local previewLabel, ahFilter + + local function RowY(row) return -(row * (ROW + PAD)) end + + local qw = math.floor((LIST_W - 5 * PAD) / 6) + for q = 0, 5 do local q = q + local b = UI.CreateButton(fp, Colored(L["CODEX_QUAL_" .. q], q), qw, ROW - 2, function() + if flt.q[q] then flt.q[q] = nil else flt.q[q] = true end + UpdateFilterUI() + RefreshList() + end, "default") + b:SetPoint("TOPLEFT", fp, "TOPLEFT", q * (qw + PAD), RowY(0)) + qualityButtons[q] = b + end + + local function InfoValues(getter, pred) + local seen, list = {}, {} + for id in pairs((ItemIndex())) do + local info = Util.GetItem(id) + if info and (not pred or pred(info)) then + local v = getter(info) + if v and v ~= "" and not seen[v] then + seen[v] = true + list[#list + 1] = v + end + end + end + table.sort(list, function(a, b) return tostring(a) < tostring(b) end) + return list + end + + local SRC_KEYS = { "unit", "object", "reward", "quest", "vendor" } + local function SrcLabel(v) return L["CODEX_SRC_" .. v:upper()] or v end + local function Zones() + local seen, list = {}, {} + for _, facts in pairs((ItemIndex())) do + for m in pairs(facts.zones) do + if not seen[m] then seen[m] = true; list[#list + 1] = m end + end + end + table.sort(list, function(a, b) return Codex.MapName(a) < Codex.MapName(b) end) + return list + end + + -- Liste von Werten in Dropdown-Eintraege umwandeln + local function AsOptions(values, display) + local list = {} + for _, v in ipairs(values) do + list[#list + 1] = { value = v, text = display and display(v) or tostring(v) } + end + return list + end + local function Prefix(key) return (L[key]:gsub(":%s*%%s%s*$", "")) end + + local third = math.floor((LIST_W - 2 * PAD) / 3) + local function MakeDrop(x, row, w, prefix, getValue, setValue, optionsFn, display) + local dd = UI.CreateDropdown(fp, w, ROW - 2, { + prefix = prefix, allText = L.CODEX_FILTER_ALL, + getOptions = function() return AsOptions(optionsFn(), display) end, + textOf = function(v) return display and display(v) or tostring(v) end, + onChange = function(v) + setValue(v) + UpdateFilterUI() + RefreshList() + end, + }) + dd:SetPoint("TOPLEFT", fp, "TOPLEFT", x, RowY(row)) + dropdowns[#dropdowns + 1] = { dd = dd, get = getValue } + return dd + end + local function FieldDrop(col, row, labelKey, field, optionsFn, display, onSet) + return MakeDrop(col * (third + PAD), row, third, Prefix(labelKey), + function() return flt[field] end, + function(v) flt[field] = v; if onSet then onSet() end end, optionsFn, display) + end + FieldDrop(0, 1, "CODEX_FILTER_TYPE", "type", function() return InfoValues(function(i) return i.type end) end, tostring, + function() flt.sub = nil end) + FieldDrop(1, 1, "CODEX_FILTER_SUB", "sub", function() + return InfoValues(function(i) return i.subType end, function(i) return not flt.type or i.type == flt.type end) + end, tostring) + FieldDrop(2, 1, "CODEX_FILTER_SLOT", "slot", function() return InfoValues(function(i) return i.equipLoc end) end, + function(v) return _G[v] or v end) + FieldDrop(0, 2, "CODEX_FILTER_SRC", "src", function() return SRC_KEYS end, SrcLabel) + FieldDrop(1, 2, "CODEX_FILTER_ZONE", "zone", Zones, Codex.MapName) + + local resetButton = UI.CreateButton(fp, L.CODEX_FILTER_RESET, third, ROW - 2, function() + flt = { q = {} } + UpdateFilterUI() + RefreshList() + end, "default") + resetButton:SetPoint("TOPLEFT", fp, "TOPLEFT", 2 * (third + PAD), RowY(2)) + + local NUM_W = 38 + local function MakeNum(x, row, getValue, setValue) + local box = UI.CreatePanel(fp, "bgDeep", "bronze") + box:SetSize(NUM_W, ROW - 2) + box:SetPoint("TOPLEFT", fp, "TOPLEFT", x, RowY(row)) + local e = CreateFrame("EditBox", nil, box) + e:SetAutoFocus(false) + e:SetPoint("TOPLEFT", box, "TOPLEFT", 5, -2) + e:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -5, 2) + e:SetMaxLetters(7) + if not e:SetFont(UI.GetFontPath("body"), 11, "") then + e:SetFont("Fonts\\FRIZQT__.TTF", 11, "") + end + e:SetTextColor(UI.Color("text")) + e:SetScript("OnEscapePressed", function(self) self:ClearFocus() end) + e:SetScript("OnTextChanged", function(self) + if syncing then return end + setValue(tonumber(((self:GetText() or ""):gsub(",", ".")))) + UpdateFilterUI() + RefreshList() + end) + numBoxes[#numBoxes + 1] = { e = e, box = box, get = getValue } + end + local function FieldNum(x, row, field) + MakeNum(x, row, function() return flt[field] end, function(v) flt[field] = v end) + end + local function NumLabel(x, row, text, w) + local l = UI.CreateLabel(fp, text, { size = 10, color = "textDim" }) + l:SetPoint("TOPLEFT", fp, "TOPLEFT", x, RowY(row) - 7) + l:SetWidth(w) + l:SetWordWrap(false) + end + -- Zeile 3: Itemstufe, Benoetigt, Preis, je mit Min und Max + local LBL_W = math.max(44, math.min(92, third - 2 * NUM_W - 8)) -- Beschriftung bekommt den Platz, der neben den zwei Feldern bleibt + local groupsDef = { { "CODEX_FILTER_ILVL", "ilMin", "ilMax" }, { "CODEX_FILTER_RLVL", "rlMin", "rlMax" }, + { "CODEX_FILTER_PRICE", "pMin", "pMax" } } + for i, g in ipairs(groupsDef) do + local x0 = (i - 1) * (third + PAD) + NumLabel(x0, 3, L[g[1]], LBL_W) + FieldNum(x0 + LBL_W, 3, g[2]) + FieldNum(x0 + LBL_W + NUM_W + 2, 3, g[3]) + end + + -- Zeilen 4 bis 6: bis zu drei Werte, dahinter UND/ODER fuer die naechste Zeile + local OP_W = 62 + local statDropW = LIST_W - 2 * NUM_W - OP_W - 3 * PAD + local function StatRow(i) + flt.stats = flt.stats or {} + flt.stats[i] = flt.stats[i] or {} + return flt.stats[i] + end + local function StatOptions() + local _, ids = ItemIndex() + Codex:CaptureStats(ids) + return Codex:StatKeys(ids) + end + for i = 1, MAX_STAT_ROWS do local i = i + local row = 3 + i + MakeDrop(0, row, statDropW, Prefix("CODEX_FILTER_STAT") .. " " .. i, + function() return flt.stats and flt.stats[i] and flt.stats[i].key end, + function(v) + local r = StatRow(i) + r.key = v + if v == nil then r.min, r.max = nil, nil end + end, StatOptions, Codex.StatName) + MakeNum(statDropW + PAD, row, + function() return flt.stats and flt.stats[i] and flt.stats[i].min end, + function(v) StatRow(i).min = v end) + MakeNum(statDropW + PAD + NUM_W + PAD, row, + function() return flt.stats and flt.stats[i] and flt.stats[i].max end, + function(v) StatRow(i).max = v end) + if i < MAX_STAT_ROWS then + local b = UI.CreateButton(fp, "", OP_W, ROW - 2, function() + flt.ops = flt.ops or {} + flt.ops[i] = (flt.ops[i] == "or") and "and" or "or" + UpdateFilterUI() + RefreshList() + end, "default") + b:SetPoint("TOPLEFT", fp, "TOPLEFT", statDropW + 2 * PAD + 2 * NUM_W + PAD, RowY(row)) + opButtons[i] = b + end + end + previewLabel = UI.CreateLabel(fp, "", { size = 10, color = "textDim" }) + previewLabel:SetPoint("TOPLEFT", fp, "TOPLEFT", 2, RowY(7) - 4) + -- Zeile 8: Auktionspreis (nur mit Auktions-Modul) + ahFilter = {} + ahFilter.label = UI.CreateLabel(fp, L.CODEX_FILTER_AH, { size = 10, color = "textDim" }) + ahFilter.label:SetPoint("TOPLEFT", fp, "TOPLEFT", 0, RowY(8) - 7) + ahFilter.label:SetWidth(LBL_W + 20) + ahFilter.label:SetWordWrap(false) + MakeNum(LBL_W + 24, 8, function() return flt.aMin end, function(v) flt.aMin = v end) + MakeNum(LBL_W + 24 + NUM_W + 2, 8, function() return flt.aMax end, function(v) flt.aMax = v end) + numBoxes[#numBoxes].ah, numBoxes[#numBoxes - 1].ah = true, true + previewLabel:SetWidth(LIST_W - 4) + previewLabel:SetWordWrap(false) + + local filterButton = UI.CreateButton(f, L.CODEX_FILTER, 96, 20, function() + filterOpen = not filterOpen + Layout() + end, "default") + filterButton:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W - 96, -68) + filterButton:Hide() + + -- Vorlage (Vanilla-Startdaten) ein/aus und Rolle (Haendler, Flugmeister ...) + local seedButton = UI.CreateButton(f, "", 100, 20, function() + Codex.db.settings.showSeed = not SeedOn() + dataVersion = dataVersion + 1 + Refresh() + end, "default") + seedButton:Hide() + -- Auswahl-Listen unter der Zaehlzeile: Rolle (Kreaturen, Objekte), Kette und Status (Quests) + local function BumpAndRefresh() + dataVersion = dataVersion + 1 + Refresh() + end + local roleDD = UI.CreateDropdown(f, 186, 20, { + prefix = Prefix("CODEX_FILTER_ROLE"), allText = L.CODEX_FILTER_ALL, + getOptions = function() + local list = {} + for _, r in ipairs(Codex.Roles.ORDER[kind] or {}) do + list[#list + 1] = { value = r, text = L["CODEX_ROLE_" .. r] or r } + end + return list + end, + textOf = function(v) return L["CODEX_ROLE_" .. v] or v end, + onChange = function(v) roleSel[kind] = v; Refresh() end, + }) + roleDD:Hide() + local chainDD = UI.CreateDropdown(f, 186, 20, { + prefix = Prefix("CODEX_FILTER_CHAIN"), allText = L.CODEX_FILTER_ALL, + getOptions = function() + local list = {} + for _, c in ipairs(CHAIN_STEPS) do list[#list + 1] = { value = c, text = L["CODEX_CHAIN_" .. c:upper()] } end + return list + end, + textOf = function(v) return L["CODEX_CHAIN_" .. v:upper()] end, + onChange = function(v) chainSel = v; BumpAndRefresh() end, + }) + chainDD:Hide() + local statusDD = UI.CreateDropdown(f, 186, 20, { + prefix = Prefix("CODEX_FILTER_STATUS"), allText = L.CODEX_FILTER_ALL, + getOptions = function() + local list = {} + for _, c in ipairs(STATUS_STEPS) do list[#list + 1] = { value = c, text = L["CODEX_STATUS_" .. c:upper()] } end + return list + end, + textOf = function(v) return L["CODEX_STATUS_" .. v:upper()] end, + onChange = function(v) statusSel = v; BumpAndRefresh() end, + }) + statusDD:Hide() + local ZONE_STEPS = { "world", "dungeon", "fit", "data" } + local zoneDD = UI.CreateDropdown(f, 186, 20, { + prefix = Prefix("CODEX_FILTER_ZONE"), allText = L.CODEX_FILTER_ALL, + getOptions = function() + local list = {} + for _, c in ipairs(ZONE_STEPS) do list[#list + 1] = { value = c, text = L["CODEX_ZONEF_" .. c:upper()] } end + return list + end, + textOf = function(v) return L["CODEX_ZONEF_" .. v:upper()] end, + onChange = function(v) zoneSel = v; BumpAndRefresh() end, + }) + zoneDD:Hide() + -- Klasse des Lernplans: die eigene, sonst die erste mit Daten + local function EnsureLearnSel() + local classes = Codex.LearnClasses() + local have = {} + for _, t in ipairs(classes) do have[t] = true end + if not (learnSel and have[learnSel]) then + local mine = Codex.Time and Codex.Time.PlayerToken() + learnSel = (mine and have[mine]) and mine or classes[1] + end + return learnSel + end + local learnDD = UI.CreateDropdown(f, 186, 20, { + prefix = Prefix("CODEX_LEARN_CLASS"), + getOptions = function() + local list = {} + for _, t in ipairs(Codex.LearnClasses()) do + list[#list + 1] = { value = t, text = Codex.Time.ClassLabel(t) } + end + return list + end, + textOf = function(v) return Codex.Time.ClassLabel(v) end, + onChange = function(v) learnSel = v; selected = nil; BumpAndRefresh() end, + }) + learnDD:Hide() + -- Routen-Planer: Stufenbereich (leer = keine Grenze), Haken = +/- 3 Stufen + local routeOpen, routeSyncing = false, false + local routeLvl = {} + local ROUTE_H = 62 + local rp = CreateFrame("Frame", nil, f) + rp:SetSize(LIST_W, ROUTE_H) + rp:Hide() + local routeBoxes = {} + local routeCheck + local function RouteBox(x, getValue, setValue) + local box = UI.CreatePanel(rp, "bgDeep", "bronze") + box:SetSize(38, 22) + box:SetPoint("TOPLEFT", rp, "TOPLEFT", x, -34) + local e = CreateFrame("EditBox", nil, box) + e:SetAutoFocus(false) + e:SetPoint("TOPLEFT", box, "TOPLEFT", 5, -2) + e:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -5, 2) + e:SetMaxLetters(3) + if not e:SetFont(UI.GetFontPath("body"), 11, "") then e:SetFont("Fonts\\FRIZQT__.TTF", 11, "") end + e:SetTextColor(UI.Color("text")) + e:SetScript("OnEscapePressed", function(self) self:ClearFocus() end) + e:SetScript("OnTextChanged", function(self) + if routeSyncing then return end + local v = tonumber(self:GetText() or "") + setValue(v and math.max(0, math.floor(v)) or nil) + if routeCheck then routeCheck:Refresh() end + end) + routeBoxes[#routeBoxes + 1] = { e = e, get = getValue } + end + local function RouteSync() + routeSyncing = true + for _, b in ipairs(routeBoxes) do + local v = b.get() + local text = v ~= nil and tostring(v) or "" + if b.e:GetText() ~= text and not b.e:HasFocus() then b.e:SetText(text) end + end + routeSyncing = false + if routeCheck then routeCheck:Refresh() end + end + routeCheck = UI.CreateCheckbox(rp, L.CODEX_ROUTE_RANGE, function() + return routeLvl.below == 3 and routeLvl.above == 3 + end, function(on) + if on then routeLvl.below, routeLvl.above = 3, 3 else routeLvl.below, routeLvl.above = nil, nil end + RouteSync() + end) + routeCheck:SetPoint("TOPLEFT", rp, "TOPLEFT", 0, -2) + local lblBelow = UI.CreateLabel(rp, L.CODEX_ROUTE_BELOW, { size = 10, color = "textDim" }) + lblBelow:SetPoint("TOPLEFT", rp, "TOPLEFT", 0, -41) + lblBelow:SetWidth(86) + lblBelow:SetWordWrap(false) + RouteBox(88, function() return routeLvl.below end, function(v) routeLvl.below = v end) + local lblAbove = UI.CreateLabel(rp, L.CODEX_ROUTE_ABOVE, { size = 10, color = "textDim" }) + lblAbove:SetPoint("TOPLEFT", rp, "TOPLEFT", 140, -41) + lblAbove:SetWidth(86) + lblAbove:SetWordWrap(false) + RouteBox(228, function() return routeLvl.above end, function(v) routeLvl.above = v end) + local routeGo = UI.CreateButton(rp, L.CODEX_ROUTE_GO, 140, 22, function() + local ids = {} + for _, e in ipairs(f.Entries()) do ids[#ids + 1] = e.id end + Codex.Map:StartRoute(ids, (routeLvl.below or routeLvl.above) and { below = routeLvl.below, above = routeLvl.above } or nil) + end, "primary") + routeGo:SetPoint("TOPLEFT", rp, "TOPLEFT", 280, -33) + local routeButton = UI.CreateButton(f, L.CODEX_ROUTE, 96, 20, function() + routeOpen = not routeOpen + RouteSync() + Layout() + end, "default") + if routeButton.HookScript then + routeButton:HookScript("OnEnter", function(self) + if GameTooltip then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + GameTooltip:SetText(L.CODEX_ROUTE_TIP, nil, nil, nil, nil, true) + GameTooltip:Show() + end + end) + routeButton:HookScript("OnLeave", function() if GameTooltip then GameTooltip:Hide() end end) + end + routeButton:Hide() + + function UpdateFilterUI() + for q, b in pairs(qualityButtons) do + b:SetStyle(flt.q[q] and "primary" or "default") + end + for _, d in ipairs(dropdowns) do + d.dd:SetValue(d.get()) + end + syncing = true + for _, n in ipairs(numBoxes) do + local v = n.get() + local text = v ~= nil and tostring(v) or "" + if n.e:GetText() ~= text and not n.e:HasFocus() then + n.e:SetText(text) + end + end + syncing = false + for i, b in pairs(opButtons) do + local isOr = flt.ops and flt.ops[i] == "or" + b:SetLabel(isOr and L.CODEX_OP_OR or L.CODEX_OP_AND) + b:SetStyle(isOr and "primary" or "default") + end + previewLabel:SetText(StatPreview(flt)) + local n = FilterActive(flt) + filterButton:SetLabel(n > 0 and string.format(L.CODEX_FILTER_N, n) or L.CODEX_FILTER) + filterButton:SetStyle(n > 0 and "primary" or "default") + end + + local farmButton = UI.CreateButton(f, L.CODEX_FARM, 120, 20, function() + farmOn = not farmOn + if farmOn then + roleSel.units = "combat" + sortBy.units = "gpm" + sortRev.units = false + else + roleSel.units = nil + sortBy.units = nil + end + Refresh() + end, "default") + farmButton:Hide() + local backButton = UI.CreateButton(f, L.CODEX_BACK, 100, 26, function() + local prev = table.remove(history) + if prev then + kind, selected = prev.kind, prev.id + edit:SetText("") + edit:ClearFocus() + Refresh() + end + end, "default") + backButton:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, 0) + backButton:Hide() + + local listScroll = UI.CreateScrollFrame(f) + listScroll:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -92) + listScroll:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0) + listScroll:SetWidth(LIST_W) + + function Layout() + local isItems = kind == "items" + local open = isItems and filterOpen + if isItems then filterButton:Show() else filterButton:Hide() end + if open then fp:Show() else fp:Hide() end + -- rechts neben dem Zaehler: [Vorlage] [Filter] + local right = LIST_W - (isItems and 100 or 0) + local hasSeed = SeedOK() and kind ~= "xp" and kind ~= "learn" + if hasSeed then + right = right - 100 + seedButton:ClearAllPoints() + seedButton:SetPoint("TOPLEFT", f, "TOPLEFT", right, -68) + seedButton:SetLabel(SeedOn() and L.CODEX_SEED_ON or L.CODEX_SEED_OFF) + seedButton:SetStyle(SeedOn() and "primary" or "default") + seedButton:Show() + else + seedButton:Hide() + end + countLabel:SetWidth(math.max(60, right - 6)) + -- eigene Zeile fuer die Auswahl-Listen: Rolle, Kette, Status + local extra = false + local hasRole = Codex.Roles.ORDER[kind] ~= nil + if hasRole then + roleDD:ClearAllPoints() + roleDD:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -94) + roleDD:SetValue(roleSel[kind]) + roleDD:Show() + extra = true + else + roleDD:Hide() + end + if kind == "units" then + farmButton:ClearAllPoints() + farmButton:SetPoint("TOPLEFT", f, "TOPLEFT", 192, -94) + farmButton:SetStyle(farmOn and "primary" or "default") + farmButton:Show() + else + farmButton:Hide() + end + local isQuests = kind == "quests" + local x = 0 + if isQuests and hasSeed then + chainDD:ClearAllPoints() + chainDD:SetPoint("TOPLEFT", f, "TOPLEFT", x, -94) + chainDD:SetValue(chainSel) + chainDD:Show() + x = x + 190 + extra = true + else + chainDD:Hide() + end + if isQuests then + statusDD:ClearAllPoints() + statusDD:SetPoint("TOPLEFT", f, "TOPLEFT", x, -94) + statusDD:SetValue(statusSel) + statusDD:Show() + routeButton:ClearAllPoints() + routeButton:SetPoint("TOPLEFT", f, "TOPLEFT", x + 190, -94) + routeButton:Show() + extra = true + else + statusDD:Hide() + routeButton:Hide() + end + if kind == "zones" then + zoneDD:ClearAllPoints() + zoneDD:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -94) + zoneDD:SetValue(zoneSel) + zoneDD:Show() + extra = true + else + zoneDD:Hide() + end + if Codex.FavSupported(kind) then + favToggle:Show() + favToggle:SetStyle(favOnly[kind] and "primary" or "default") + else + favToggle:Hide() + end + if kind == "learn" and EnsureLearnSel() then + learnDD:ClearAllPoints() + learnDD:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -94) + learnDD:SetValue(learnSel) + learnDD:Show() + extra = true + else + learnDD:Hide() + end + local top = 92 + (extra and 28 or 0) + local showRoute = kind == "quests" and routeOpen + if showRoute then + rp:ClearAllPoints() + rp:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -top) + rp:Show() + else + rp:Hide() + end + routeButton:SetStyle(showRoute and "primary" or "default") + if showRoute then top = top + ROUTE_H + 6 end + listScroll:ClearAllPoints() + FILTER_H = FilterH() + fp:SetHeight(FILTER_H) + if ahFilter then ahFilter.label:SetShown(Codex.AuctionProvider ~= nil) end + for _, nb in ipairs(numBoxes) do + if nb.ah then nb.box:SetShown(Codex.AuctionProvider ~= nil) end + end + listScroll:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -(top + (open and (FILTER_H + 6) or 0))) + listScroll:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0) + listScroll:SetWidth(LIST_W) + end + local listEmpty = UI.CreateLabel(listScroll.child, "", { size = 12, color = "textDim", justifyV = "TOP" }) + listEmpty:SetPoint("TOPLEFT", listScroll.child, "TOPLEFT", 4, -6) + listEmpty:SetPoint("TOPRIGHT", listScroll.child, "TOPRIGHT", -4, -6) + listEmpty:SetWordWrap(true) + + local separator = f:CreateTexture(nil, "ARTWORK") + separator:SetColorTexture(UI.Color("bronze", 0.5)) + separator:SetWidth(1) + separator:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 10, 0) + separator:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", LIST_W + 10, 0) + + ---------------- rechts: Detail ---------------- + local detail = UI.CreateScrollFrame(f) + detail:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -34) + detail:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0) + local detailEmpty = UI.CreateLabel(detail.child, L.CODEX_SELECT, { size = 12, color = "textDim" }) + detailEmpty:SetPoint("TOPLEFT", detail.child, "TOPLEFT", 4, -6) + + -- Namen von Hand eintragen (Deutsch / Englisch) + local UpdateFavUIRef + if Codex.NameUI then + nameCtl = Codex.NameUI.Attach(f, function() return kind, selected end, function() + dataVersion = dataVersion + 1 + Refresh() + end, { x = LIST_W + 22, y = 34, relayout = function() if UpdateFavUIRef then UpdateFavUIRef() end end }) + end + + ---------------- Favorit und Notiz ---------------- + local favButton = UI.CreateButton(f, L.CODEX_FAV_ADD, 140, 26, function() + if selected ~= nil and Codex.FavSupported(kind) then + Codex.SetFav(kind, selected, not Codex.IsFav(kind, selected)) + dataVersion = dataVersion + 1 + Refresh() + end + end, "default") + favButton:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22 + 108, 0) + favButton:Hide() + local noteBox = UI.CreatePanel(f, "bgDeep", "bronze") + noteBox:SetHeight(24) + noteBox:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -34) + noteBox:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -34) + noteBox:Hide() + local noteEdit = CreateFrame("EditBox", nil, noteBox) + noteEdit:SetAutoFocus(false) + noteEdit:SetPoint("TOPLEFT", noteBox, "TOPLEFT", 8, -2) + noteEdit:SetPoint("BOTTOMRIGHT", noteBox, "BOTTOMRIGHT", -8, 2) + noteEdit:SetMaxLetters(200) + if not noteEdit:SetFont(UI.GetFontPath("body"), 12, "") then + noteEdit:SetFont("Fonts\\FRIZQT__.TTF", 12, "") + end + noteEdit:SetTextColor(UI.Color("text")) + local noteHint = UI.CreateLabel(noteBox, L.CODEX_NOTE_HINT, { size = 11, color = "textDim" }) + noteHint:SetPoint("LEFT", noteBox, "LEFT", 10, 0) + local noteTarget = nil + local function SaveNote() + if noteTarget then Codex.SetNote(noteTarget.kind, noteTarget.id, noteEdit:GetText()) end + end + noteEdit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end) + noteEdit:SetScript("OnEnterPressed", function(self) SaveNote(); self:ClearFocus() end) + noteEdit:SetScript("OnEditFocusLost", function() SaveNote() end) + noteEdit:SetScript("OnTextChanged", function(self) + if (self:GetText() or "") == "" then noteHint:Show() else noteHint:Hide() end + end) + + -- Dev-Notiz (nur mit dem Modul Freewood-OctoWoW-Dev und Bearbeitungsrecht): lokal, wird nicht geteilt + local devNoteBox = UI.CreatePanel(f, "bgDeep", "gold") + devNoteBox:SetHeight(24) + devNoteBox:Hide() + local devNoteEdit = CreateFrame("EditBox", nil, devNoteBox) + devNoteEdit:SetAutoFocus(false) + devNoteEdit:SetPoint("TOPLEFT", devNoteBox, "TOPLEFT", 8, -2) + devNoteEdit:SetPoint("BOTTOMRIGHT", devNoteBox, "BOTTOMRIGHT", -8, 2) + devNoteEdit:SetMaxLetters(500) + if not devNoteEdit:SetFont(UI.GetFontPath("body"), 12, "") then + devNoteEdit:SetFont("Fonts\\FRIZQT__.TTF", 12, "") + end + devNoteEdit:SetTextColor(UI.Color("text")) + local devNoteHint = UI.CreateLabel(devNoteBox, L.CODEX_DEVNOTE_HINT, { size = 11, color = "textDim" }) + devNoteHint:SetPoint("LEFT", devNoteBox, "LEFT", 10, 0) + local devNoteTarget = nil + local function SaveDevNote() + if devNoteTarget then Codex.SetDevNote(devNoteTarget.kind, devNoteTarget.id, devNoteEdit:GetText()) end + end + devNoteEdit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end) + devNoteEdit:SetScript("OnEnterPressed", function(self) SaveDevNote(); self:ClearFocus() end) + devNoteEdit:SetScript("OnEditFocusLost", function() SaveDevNote() end) + devNoteEdit:SetScript("OnTextChanged", function(self) + if (self:GetText() or "") == "" then devNoteHint:Show() else devNoteHint:Hide() end + end) + + local function UpdateFavUI() + local ok = selected ~= nil and Codex.FavSupported(kind) + local same = noteTarget and noteTarget.kind == kind and noteTarget.id == selected + if noteEdit:HasFocus() then + if same and ok and Codex.IsFav(kind, selected) then return end + SaveNote() + noteEdit:ClearFocus() + end + noteTarget = nil + local devH = nameCtl and nameCtl.height or 0 -- Reihe mit den Bearbeiten-Knoepfen (nur fuer Berechtigte) + local top = 34 + devH + noteBox:ClearAllPoints() + noteBox:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -top) + noteBox:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -top) + if ok then + local fav = Codex.IsFav(kind, selected) + favButton:Show() + favButton:SetLabel(fav and L.CODEX_FAV_REMOVE or L.CODEX_FAV_ADD) + favButton:SetStyle(fav and "primary" or "default") + if fav then + noteTarget = { kind = kind, id = selected } + local e = Codex.GetFav(kind, selected) + noteEdit:SetText(e and e.note or "") + noteBox:Show() + top = top + 30 + else + noteBox:Hide() + end + else + favButton:Hide() + noteBox:Hide() + end + -- Dev-Notiz + if devNoteEdit:HasFocus() then SaveDevNote() devNoteEdit:ClearFocus() end + devNoteTarget = nil + if selected ~= nil and Codex.DevNoteSupported(kind) and Codex.CanDevNote() then + devNoteTarget = { kind = kind, id = selected } + devNoteBox:ClearAllPoints() + devNoteBox:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -top) + devNoteBox:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -top) + devNoteEdit:SetText(Codex.GetDevNote(kind, selected) or "") + devNoteBox:Show() + top = top + 30 + else + devNoteBox:Hide() + end + detail:ClearAllPoints() + detail:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -top) + detail:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0) + end + UpdateFavUIRef = UpdateFavUI + + -- Bild (Kreatur: 3D-Modell mit Symbol als Rueckfall, Objekt: Symbol) + local portrait = UI.CreatePanel(detail.child, "bgDeep", "bronze") + portrait:SetSize(64, 64) + portrait:SetPoint("TOPLEFT", detail.child, "TOPLEFT", 0, 0) + portrait:Hide() + local portraitIcon = portrait:CreateTexture(nil, "ARTWORK") + portraitIcon:SetPoint("TOPLEFT", portrait, "TOPLEFT", 6, -6) + portraitIcon:SetPoint("BOTTOMRIGHT", portrait, "BOTTOMRIGHT", -6, 6) + portraitIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92) + -- Modell haengt am Hauptfenster (nicht am Scroll-Kind), sonst landet es an falscher Stelle + local model = CreateFrame("PlayerModel", nil, f) + model:SetAlpha(0) + model:Hide() + local function PlaceModel() + model:ClearAllPoints() + model:SetPoint("TOPLEFT", portrait, "TOPLEFT", 2, -2) + model:SetPoint("BOTTOMRIGHT", portrait, "BOTTOMRIGHT", -2, 2) + model:SetFrameLevel((detail.scroll and detail.scroll:GetFrameLevel() or 1) + 6) + local sc = detail.scroll and detail.scroll:GetVerticalScroll() or 0 + if portrait:IsShown() and model.fwNPC and sc <= 2 then + model:Show() + else + model:Hide() + end + end + if detail.scroll and detail.scroll.HookScript then + detail.scroll:HookScript("OnVerticalScroll", function() PlaceModel() end) + end + pcall(model.SetScript, model, "OnModelLoaded", function(self) + self:SetAlpha(1) + portraitIcon:Hide() + if self.fwNPC then + local ok, d = pcall(function() return self.GetDisplayInfo and self:GetDisplayInfo() end) + if ok and type(d) == "number" and Codex:SetDisplayID(self.fwNPC, d) then + if f.UpdateRowModels then f.UpdateRowModels() end + end + end + end) + + local function ShowPortrait(iconPath, npcID) + portrait:Show() + portraitIcon:SetTexture(iconPath) + portraitIcon:Show() + model:SetAlpha(0) + model.fwNPC = npcID + PlaceModel() + if npcID then + local function Check() + if model.fwNPC ~= npcID then return end + local fileID = model.GetModelFileID and model:GetModelFileID() + local ok, d = pcall(function() return model.GetDisplayInfo and model:GetDisplayInfo() end) + if model.fwShown or (type(fileID) == "number" and fileID > 0) or (ok and type(d) == "number" and d > 0) then + model:SetAlpha(1) + portraitIcon:Hide() + if ok and type(d) == "number" and Codex:SetDisplayID(npcID, d) and f.UpdateRowModels then + f.UpdateRowModels() + end + end + end + Codex.EnsureCreature(npcID, function() + if model.fwNPC ~= npcID then return end + -- ClassicAPI zieht "humanoide" Anzeigen (mit Extra-Eintrag) ueber einen Ankleide-Auftrag an. + -- Dessen Aufraeumen beim /reload stuerzt das Spiel ab. Nur Typen ohne solche Modelle zeigen. + local okI, info = pcall(function() return C_CreatureInfo.GetCreatureInfoByID(npcID) end) + local ctype = okI and type(info) == "table" and tonumber(info.type) or nil + if not (ctype and SAFE_MODEL_TYPE[ctype]) then return end + local cd = Codex.CacheDisplayID(npcID) + if cd and Codex:SetDisplayID(npcID, cd) and f.UpdateRowModels then + f.UpdateRowModels() + end + model.fwShown = nil + pcall(function() + model:ClearModel() + if cd and model.SetDisplayInfo then + model:SetDisplayInfo(cd) + model.fwShown = true + else + model:SetCreature(npcID) + end + if model.SetPortraitZoom then + model:SetPortraitZoom(1) + end + end) + Check() + C_Timer.After(0.4, Check) + C_Timer.After(0.1, function() + if model.fwNPC == npcID and model.SetPortraitZoom then pcall(model.SetPortraitZoom, model, 1) end + end) + end) + end + end + + local D = { y = 0, used = 0 } + + local function NewDetailRow() + local row = CreateFrame("Button", nil, detail.child) + row.bg = row:CreateTexture(nil, "BACKGROUND") + row.bg:SetAllPoints() + row.bg:SetColorTexture(UI.Color("hover", 0)) + row.icon = row:CreateTexture(nil, "ARTWORK") + row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) + row.left = UI.CreateLabel(row, "", { size = 12 }) + row.right = UI.CreateLabel(row, "", { size = 11, color = "textDim", justify = "RIGHT" }) + row.line = row:CreateTexture(nil, "ARTWORK") + row.line:SetColorTexture(UI.Color("bronze", 0.6)) + row.line:SetHeight(1) + row:SetScript("OnEnter", function(self) + if self.clickable then + self.bg:SetColorTexture(UI.Color("hover", 0.8)) + end + if self.itemID and GameTooltip then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + pcall(GameTooltip.SetItemByID, GameTooltip, self.itemID) + GameTooltip:Show() + elseif self.spellID and GameTooltip then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + local ok = pcall(GameTooltip.SetSpellByID, GameTooltip, self.spellID) + if not ok then pcall(GameTooltip.SetHyperlink, GameTooltip, "spell:" .. self.spellID) end + GameTooltip:Show() + end + end) + row:SetScript("OnLeave", function(self) + self.bg:SetColorTexture(UI.Color("hover", 0)) + if GameTooltip then GameTooltip:Hide() end + end) + row:SetScript("OnClick", function(self) + if self.onClick then + self.onClick() + end + end) + return row + end + + -- Verlaufsdiagramm: history = Liste { day, avg, min }, neuester zuerst + local chart + local CHART_H = 84 + function D:Chart(history) + if not history or #history < 2 then + if chart then chart:Hide() end + return + end + if not chart then + chart = CreateFrame("Frame", nil, detail.child) + chart.segs, chart.dots = {}, {} + chart.bg = chart:CreateTexture(nil, "BACKGROUND") + chart.bg:SetAllPoints() + chart.bg:SetColorTexture(UI.Color("bgDeep", 0.6)) + chart.hi = UI.CreateLabel(chart, "", { size = 10, color = "textDim", justify = "RIGHT" }) + chart.lo = UI.CreateLabel(chart, "", { size = 10, color = "textDim", justify = "RIGHT" }) + chart.from = UI.CreateLabel(chart, "", { size = 10, color = "textDim" }) + chart.to = UI.CreateLabel(chart, "", { size = 10, color = "textDim", justify = "RIGHT" }) + end + local w = detail.child:GetWidth() + if not w or w < 120 then w = 320 end + local LABEL_W, PADX, PADY = 78, 6, 8 + local pw, ph = w - LABEL_W - PADX * 2, CHART_H - PADY * 2 - 12 + local pts = {} + local lo, hi = math.huge, 0 + for i = #history, 1, -1 do + local v = history[i].avg or history[i].min or 0 + pts[#pts + 1] = { day = history[i].day, v = v } + if v < lo then lo = v end + if v > hi then hi = v end + end + if hi == lo then lo = lo * 0.9; hi = hi * 1.1 + 1 end + local n = #pts + local firstDay, lastDay = pts[1].day, pts[n].day + local span = math.max(1, lastDay - firstDay) + for i, p in ipairs(pts) do + p.x = PADX + (p.day - firstDay) / span * pw + p.y = PADY + (1 - (p.v - lo) / (hi - lo)) * ph + end + chart:ClearAllPoints() + chart:SetPoint("TOPLEFT", detail.child, "TOPLEFT", 0, -(self.y + 6)) + chart:SetSize(w, CHART_H) + local function Tex(list, k) + local t = list[k] + if not t then + t = chart:CreateTexture(nil, "ARTWORK") + list[k] = t + end + return t + end + for i = 1, n - 1 do + local a, b = pts[i], pts[i + 1] + local dx, dy = b.x - a.x, b.y - a.y + local t = Tex(chart.segs, i) + t:SetColorTexture(1, 0.82, 0, 0.9) + t:ClearAllPoints() + t:SetSize(math.max(1, math.sqrt(dx * dx + dy * dy)), 2) + t:SetPoint("CENTER", chart, "TOPLEFT", (a.x + b.x) / 2, -(a.y + b.y) / 2) + if t.SetRotation then t:SetRotation(math.atan2 and math.atan2(-dy, dx) or math.atan(-dy, dx)) end + t:Show() + end + for i = n, #chart.segs do if chart.segs[i] then chart.segs[i]:Hide() end end + for i, p in ipairs(pts) do + local t = Tex(chart.dots, i) + t:SetColorTexture(1, 0.92, 0.4, 1) + t:SetSize(5, 5) + t:ClearAllPoints() + t:SetPoint("CENTER", chart, "TOPLEFT", p.x, -p.y) + t:Show() + end + for i = n + 1, #chart.dots do chart.dots[i]:Hide() end + chart.hi:ClearAllPoints(); chart.hi:SetPoint("TOPRIGHT", chart, "TOPRIGHT", -4, -4); chart.hi:SetWidth(LABEL_W) + chart.lo:ClearAllPoints(); chart.lo:SetPoint("BOTTOMRIGHT", chart, "BOTTOMRIGHT", -4, 16); chart.lo:SetWidth(LABEL_W) + chart.hi:SetText(FormatMoney(hi)); chart.lo:SetText(FormatMoney(lo)) + chart.from:ClearAllPoints(); chart.from:SetPoint("BOTTOMLEFT", chart, "BOTTOMLEFT", PADX, 2) + chart.to:ClearAllPoints(); chart.to:SetPoint("BOTTOMRIGHT", chart, "BOTTOMRIGHT", -LABEL_W - PADX, 2) + chart.from:SetText(string.format(L.CODEX_AH_DAYS, lastDay - firstDay)) + chart.to:SetText(L.CODEX_AH_TODAY) + chart:Show() + self.y = self.y + 6 + CHART_H + 4 + end + + function D:Reset() + if chart then chart:Hide() end + portrait:Hide() + model.fwNPC = nil + model:Hide() + for _, row in ipairs(detailRows) do + row:Hide() + end + self.y, self.used = 0, 0 + end + + -- Hoehe eines umbrechenden Textblocks (grobe Schaetzung nach Zeichenzahl und Breite) + local function TextHeight(text) + local width = detail.child and detail.child.GetWidth and detail.child:GetWidth() or 0 + if not width or width < 100 then width = detail.GetWidth and detail:GetWidth() or 0 end + if not width or width < 100 then width = 900 end + local perLine = math.max(20, math.floor((width - 40) / 6.8)) + local lines = 0 + text = (text or "") .. "\n" + for seg in text:gmatch("([^\n]*)\n") do + lines = lines + math.max(1, math.ceil(#seg / perLine)) + end + return lines * 14 + 8 + end + + -- opts: style ("title","sub","heading","line","item","link","text"), text, right, icon, itemID, onClick, indent + function D:Add(opts) + self.used = self.used + 1 + local row = detailRows[self.used] + if not row then + row = NewDetailRow() + detailRows[self.used] = row + end + local style = opts.style or "line" + local h = LINE_H + local top = 0 + if style == "title" then h = 32 elseif style == "sub" then h = 22 + elseif style == "heading" then h = 28; top = 12 + elseif style == "item" or style == "link" then h = 26 + elseif style == "text" then h = TextHeight(opts.text) end + if opts.spellID then h = 26 end + row:ClearAllPoints() + row:SetPoint("TOPLEFT", detail.child, "TOPLEFT", 0, -(self.y + top)) + row:SetPoint("TOPRIGHT", detail.child, "TOPRIGHT", 0, -(self.y + top)) + row:SetHeight(h) + self.y = self.y + top + h + + local indent = opts.indent or 0 + row.left:ClearAllPoints() + row.right:ClearAllPoints() + row.icon:Hide() + row.line:Hide() + row.clickable = opts.onClick ~= nil + row.onClick = opts.onClick + row.itemID = opts.itemID + row.spellID = opts.spellID + row:EnableMouse(row.clickable or opts.itemID ~= nil or opts.spellID ~= nil) + + local leftX = 4 + indent + if opts.icon then + row.icon:SetSize(h - 4, h - 4) + row.icon:ClearAllPoints() + row.icon:SetPoint("LEFT", row, "LEFT", leftX, 0) + row.icon:SetTexture(opts.icon) + row.icon:Show() + leftX = leftX + h + end + row.left:SetPoint("LEFT", row, "LEFT", leftX, 0) + row.right:SetPoint("RIGHT", row, "RIGHT", -6, 0) + row.left:SetPoint("RIGHT", row, "RIGHT", opts.right and -(opts.rightWidth or 150) or -6, 0) + row.left:SetWordWrap(false) + + if style == "title" then + UI.SetFont(row.left, "heading", 20) + row.left:SetTextColor(UI.Color("goldLight")) + elseif style == "sub" then + UI.SetFont(row.left, "body", 12) + row.left:SetTextColor(UI.Color("textDim")) + elseif style == "heading" then + UI.SetFont(row.left, "heading", 14) + row.left:SetTextColor(UI.Color("goldLight")) + row.line:ClearAllPoints() + row.line:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 0, 0) + row.line:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", 0, 0) + row.line:Show() + else + UI.SetFont(row.left, "body", 12) + row.left:SetTextColor(UI.Color(row.clickable and "goldLight" or "text")) + end + if style == "text" then + -- umbrechender Block ueber die ganze Breite + row.left:ClearAllPoints() + row.left:SetPoint("TOPLEFT", row, "TOPLEFT", leftX, -3) + row.left:SetPoint("TOPRIGHT", row, "TOPRIGHT", -6, -3) + row.left:SetWordWrap(true) + row.left:SetJustifyH("LEFT") + row.left:SetJustifyV("TOP") + -- feste Hoehe: ohne sie schneidet der Client den Text nach den ersten Zeilen mit "..." ab + row.left:SetHeight(math.max(16, h - 4)) + end + row.left:SetText(opts.text or "") + row.right:SetText(opts.right or "") + row:Show() + return row + end + + function D:Finish() + detail:SetContentHeight(self.y + 16) + detailEmpty:SetShown(self.used == 0) + end + + -- Zeile fuer ein Item (Symbol und Name asynchron) + local function ItemRow(itemID, right, indent, extraText) + local row = D:Add({ style = "item", text = "#" .. itemID, right = right, itemID = itemID, indent = indent, + icon = "Interface\\Icons\\INV_Misc_QuestionMark", + onClick = function() Go("items", itemID) end }) + local resolved = false + Util.RequestItem(itemID, function(info) + if row.itemID ~= itemID or not info then + return + end + resolved = true + Codex.RememberQuality(itemID, info.quality) + row.icon:SetTexture(info.icon) + row.left:SetText(Colored(info.name, info.quality) .. (extraText or "")) + end) + local cached = Codex.db.names[itemID] + if cached and not resolved then + row.left:SetText(Colored(cached, Codex.QualityOf(itemID) or 1) .. (extraText or "")) + end + return row + end + + local function RefRow(ref, labelKind) + if not ref then + D:Add({ text = "-" }) + return + end + local tkind = ref.k == "npc" and "units" or ref.k == "object" and "objects" or nil + local refEnt = tkind and ref.id and Codex.V()[tkind][ref.id] + local text = (refEnt and Codex.NameOf(refEnt)) or ref.n or (ref.id and ("#" .. ref.id)) or "-" + D:Add({ style = tkind and ref.id and "link" or "line", text = text, + onClick = tkind and ref.id and function() Go(tkind, ref.id) end or nil, + right = ref.m and ref.x and string.format(FW.L.CODEX_POS, Codex.MapName(ref.m), (ref.x or 0) * 100, (ref.y or 0) * 100) or nil }) + end + + local function QuestLink(id, q, right) + local lvl = q and q.lvl + if not q and SeedOK() then + local sq = Codex.Seed.Quest(id) + lvl = sq and sq.lvl ~= 0 and sq.lvl or nil + right = right or SeedTag() + end + local title = Codex.QuestTitle(q, id) + if not q and Codex.Catalog then + local ct, cl = Codex.Catalog.Get(id) + if ct then + title = ct + lvl = lvl or cl + end + end + D:Add({ style = "link", text = title .. (lvl and (" (" .. string.format(FW.L.CODEX_LEVEL, lvl) .. ")") or ""), + right = right, onClick = function() Go("quests", id) end, icon = ICON.quests }) + end + + local function EntityLink(tkind, id, ent, right) + local lvl = ent and LevelText(ent) + if not lvl and tkind == "units" and SeedOK() then + lvl = LevelText(Codex.Seed.Entity(tkind, id) or {}) + end + D:Add({ style = "link", text = UnitTitle(ent, id, tkind) .. (lvl and (" (" .. lvl .. ")") or ""), + right = right, onClick = function() Go(tkind, id) end, icon = ICON[tkind] }) + end + + -- Verweis auf eine Kreatur / ein Objekt / ein Item aus der Vorlage + local function SeedRef(ref) + if ref.kind == "items" then + ItemRow(ref.id, SeedTag(), 0) + return + end + local m, x, y = Codex.Seed.FirstSpot(ref.kind, ref.id) + local live = Codex.V()[ref.kind][ref.id] + local lvl = ref.kind == "units" and LevelText(Codex.Seed.Entity(ref.kind, ref.id) or {}) or nil + D:Add({ style = "link", text = UnitTitle(live, ref.id, ref.kind) .. (lvl and (" (" .. lvl .. ")") or "") .. " " .. SeedTag(), + icon = ICON[ref.kind], onClick = function() Go(ref.kind, ref.id) end, + right = m and string.format(FW.L.CODEX_POS, Codex.MapName(m), x * 100, y * 100) or nil }) + end + + ---------------- Details je Art ---------------- + local function LootSection(ent, alt) + local list = Codex.DropList(ent, alt) + if #list == 0 then + return + end + D:Add({ style = "heading", text = alt and L.CODEX_SEC_ALT or L.CODEX_SEC_LOOT }) + local k = list[1].k + D:Add({ style = "sub", text = string.format(L.CODEX_KILLS, k) .. ((k < 10) and (" | " .. L.CODEX_LOW_SAMPLE) or "") }) + for _, e in ipairs(list) do + local extra = e.qi and (" |cff9d9d9d[" .. L.CODEX_QUEST_ITEM .. "]|r") or "" + local ahp = Codex.AuctionProvider and Codex.AuctionPrice(e.id) + if ahp and ahp > 0 then + extra = extra .. " |cffffd100" .. L.CODEX_AH_SHORT .. " " .. FormatMoney(ahp) .. "|r" + end + local right = string.format(L.CODEX_DROP_CHANCE, FormatChance(e.chance), e.n, e.k) + if e.k < 10 then right = "|cff9d9d9d~ " .. right .. "|r" end + ItemRow(e.id, right, 0, extra) + end + end + + local detailMissing = false + local function ValueSection(ent) + local total, coin, items, missing = Codex.KillValue(ent) + detailMissing = false + if not total then + return + end + D:Add({ style = "heading", text = L.CODEX_VALUE_HEAD }) + D:Add({ text = L.CODEX_VALUE_COIN, right = FormatMoney(coin) }) + D:Add({ text = L.CODEX_VALUE_ITEMS, right = FormatMoney(items) }) + D:Add({ text = L.CODEX_VALUE_TOTAL, right = FormatMoney(total) }) + if Codex.AuctionProvider then + local ahTotal, _, ahItems, ahMissing = Codex.KillValue(ent, true) + if ahTotal then + D:Add({ text = L.CODEX_VALUE_ITEMS_AH, right = FormatMoney(ahItems) }) + D:Add({ text = L.CODEX_VALUE_TOTAL_AH, right = FormatMoney(ahTotal) }) + if ahMissing > 0 then + D:Add({ style = "sub", text = string.format(L.CODEX_VALUE_MISSING, ahMissing) }) + end + end + end + if missing > 0 then + detailMissing = true + D:Add({ style = "sub", text = string.format(L.CODEX_VALUE_MISSING, missing) }) + end + end + + local function QuestsOfUnit(tkind, id, uname) + local gives, turns, targets = {}, {}, {} + local refKind = tkind == "units" and "npc" or "object" + if SeedOK() and Codex.RepairObjectives then Codex.RepairObjectives() end + local lname = uname and uname:lower() or nil + for qid, q in pairs(Codex.V().quests) do + if q.give and q.give.k == refKind and q.give.id == id then gives[#gives + 1] = qid end + if q.turn and q.turn.k == refKind and q.turn.id == id then turns[#turns + 1] = qid end + if tkind == "units" then + for _, o in ipairs(q.obj or {}) do + if (o.ids and o.ids[id]) or (lname and o.ty == "monster" and o.name and o.name:lower() == lname) then + targets[#targets + 1] = qid + break + end + end + end + end + if SeedOK() then + -- Vorlage: Quests, die wir noch nicht mit diesem Geber / Abgabeort / Ziel kennen + local sg, st, sx = Codex.Seed.QuestsOf(tkind, id) + for _, def in ipairs({ { gives, sg }, { turns, st }, { targets, sx } }) do + local have = {} + for _, qid in ipairs(def[1]) do have[qid] = true end + for _, qid in ipairs(def[2]) do + if not have[qid] then + have[qid] = true + def[1][#def[1] + 1] = qid + end + end + end + end + if Codex.Catalog and Codex.Catalog.Reverse then + local list = Codex.Catalog.Reverse()[tkind == "units" and "monster" or "object"][id] + if list then + local have = {} + for _, qid in ipairs(targets) do have[qid] = true end + for _, qid in ipairs(list) do + if not have[qid] then + have[qid] = true + targets[#targets + 1] = qid + end + end + end + end + local function QInfo(qid) + local q = Codex.V().quests[qid] + local lvl = q and q.lvl + if not lvl and SeedOK() then + local sq = Codex.Seed.Quest(qid) + lvl = sq and sq.lvl + end + local title = Codex.QuestTitle(q, qid) + if not q and Codex.Catalog then + local ct, cl = Codex.Catalog.Get(qid) + if ct then + title = ct + lvl = lvl or cl + end + end + return lvl or 0, title + end + local function Sorted(list) + table.sort(list, function(a, b) + local la, ta = QInfo(a) + local lb, tb = QInfo(b) + if la ~= lb then return la < lb end + if ta ~= tb then return ta < tb end + return a < b + end) + return list + end + -- von Hand zugeordnet (Properties) und gelernte Quest-Item-Quellen + local manualKill, manualItems = Codex.ManualQuestLinks(tkind, id) + do + local have = {} + for _, qid in ipairs(targets) do have[qid] = true end + for _, qid in ipairs(manualKill) do + if not have[qid] then have[qid] = true targets[#targets + 1] = qid end + end + end + local items, haveItem = {}, {} + local srcKey = (tkind == "units" and "u" or "o") .. id + for qid, q in pairs(Codex.V().quests) do + for itemID, srcs in pairs(q.qi or {}) do + if srcs[srcKey] and not haveItem[qid .. ":" .. itemID] then + haveItem[qid .. ":" .. itemID] = true + items[#items + 1] = { qid = qid, item = itemID } + end + end + end + for _, s in ipairs(manualItems) do + local qs, is = tostring(s):match("^(%d+):(%d+)$") + local qid, itemID = tonumber(qs), tonumber(is) + if qid and itemID and not haveItem[qid .. ":" .. itemID] then + haveItem[qid .. ":" .. itemID] = true + items[#items + 1] = { qid = qid, item = itemID, manual = true } + end + end + if #items > 0 then + table.sort(items, function(a, b) if a.qid ~= b.qid then return a.qid < b.qid end return a.item < b.item end) + D:Add({ style = "heading", text = L.CODEX_SEC_QITEMS }) + for i, e in ipairs(items) do + if i > 30 then break end + QuestLink(e.qid, Codex.V().quests[e.qid], (Codex:ItemName(e.item) or ("#" .. e.item)) .. (e.manual and (" [" .. L.CODEX_MANUAL_TAG .. "]") or "")) + end + end + local belongs = Codex.EntityQuests(tkind == "units" and "u" or "o", id) + if #belongs > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_QBEL }) + for i, qid in ipairs(belongs) do + if i > 30 then break end + QuestLink(qid, Codex.V().quests[qid], L.CODEX_MANUAL_TAG) + end + end + for _, def in ipairs({ { gives, L.CODEX_SEC_GIVES }, { turns, L.CODEX_SEC_TURNS }, { targets, L.CODEX_SEC_TARGET } }) do + if #def[1] > 0 then + D:Add({ style = "heading", text = def[2] }) + for i, qid in ipairs(Sorted(def[1])) do + if i > 30 then break end + QuestLink(qid, Codex.V().quests[qid]) + end + end + end + end + + local MAP_ICON = "Interface\\Icons\\INV_Misc_Map_01" + + local function MapLink(spec, label) + D:Add({ style = "link", text = L.CODEX_MAP_SHOW, icon = MAP_ICON, + onClick = function() + Codex.Map:Show(Codex.CollectPoints(spec), label) + end }) + end + + local function SpotRows(cells, limit, noHits) + for _, s in ipairs(Codex.TopSpots(cells, limit or 8)) do + D:Add({ text = string.format(L.CODEX_POS, Codex.MapName(s.m), s.x * 100, s.y * 100), + right = (not noHits) and string.format(L.CODEX_SPOT_HITS, s.n) or nil }) + end + end + + -- Fundorte: eigene Beobachtungen, sonst die Vorlage + local function PlacesSection(ent, spec, label, seedCells) + if ent and ent.cells and next(ent.cells) ~= nil then + D:Add({ style = "heading", text = L.CODEX_SEC_SPOTS }) + SpotRows(ent.cells, 8) + elseif seedCells and next(seedCells) ~= nil then + D:Add({ style = "heading", text = L.CODEX_SEC_SPOTS .. " " .. SeedTag() }) + SpotRows(seedCells, 8, true) + else + return + end + if spec then + MapLink(spec, label) + end + end + + local function ShowQuest(id) + local live = Codex.V().quests[id] + local sq = SeedOK() and Codex.Seed.Quest(id) or nil + local catTitle, catLvl + if not live and not sq and Codex.Catalog then catTitle, catLvl = Codex.Catalog.Get(id) end + if not live and not sq and not catTitle then return end + local q = live or {} + D:Add({ style = "title", text = catTitle or Codex.QuestTitle(live, id) }) + local sub = {} + local lvl = q.lvl or (sq and sq.lvl and sq.lvl > 0 and sq.lvl) or catLvl or nil + if lvl then sub[#sub + 1] = string.format(L.CODEX_LEVEL, lvl) end + if sq and sq.min and sq.min > 0 then sub[#sub + 1] = string.format(L.CODEX_MINLEVEL, sq.min) end + if q.zone then + sub[#sub + 1] = Codex.MapName(q.zone) + elseif sq then + local ref = sq.start[1] or sq.stop[1] + local m = ref and ref.kind ~= "items" and Codex.Seed.MapOf(ref.kind, ref.id) + if m then sub[#sub + 1] = Codex.MapName(m) end + end + local wm = Codex.Catalog and Codex.Catalog.QuestMeta and Codex.Catalog.QuestMeta(id) + if wm then + if wm.zone and not q.zone and not (sq and sq.start[1]) then sub[#sub + 1] = wm.zone end + if wm.info then sub[#sub + 1] = wm.info end + end + if q.dg ~= nil then sub[#sub + 1] = q.dg and L.CODEX_PROPS_DG_YES or L.CODEX_PROPS_DG_NO end + if (q.seen or 0) > 0 then sub[#sub + 1] = string.format(L.CODEX_SEEN, q.seen) end + if (q.done or 0) > 0 then sub[#sub + 1] = string.format(L.CODEX_DONE, q.done) end + local det0 = Codex.Catalog and Codex.Catalog.Details and Codex.Catalog.Details(id) + if det0 and det0.qtype then sub[#sub + 1] = det0.qtype end + sub[#sub + 1] = "ID " .. id + local startOnly = live and Codex.Share and Codex.Share.Origin and Codex.Share.Origin("q", id) == "start" + if not live then sub[#sub + 1] = catTitle and ("|cff8a8a96[" .. L.CODEX_CAT_TAG .. "]|r") or SeedTag() + elseif startOnly then sub[#sub + 1] = "|cff8a8a96[" .. L.CODEX_START_TAG .. "]|r" end + D:Add({ style = "sub", text = table.concat(sub, " | ") }) + if not live then + D:Add({ style = "sub", text = catTitle and L.CODEX_CAT_NOTE or L.CODEX_SEED_NOTE }) + elseif startOnly then + D:Add({ style = "sub", text = L.CODEX_START_NOTE }) + end + local status = Codex.QuestStatus(id) + D:Add({ style = "sub", text = string.format(L.CODEX_STATUS_LINE, + status == "done" and L.CODEX_STATUS_DONE or status == "active" and L.CODEX_STATUS_ACTIVE or L.CODEX_STATUS_OPEN) }) + if q.rem then + D:Add({ style = "sub", text = L.CODEX_REMOTE_ONLY }) + end + if q.partial then + D:Add({ style = "sub", text = L.CODEX_PARTIAL }) + end + + if q.tm and q.tm.n and q.tm.n > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_TIME }) + D:Add({ text = L.CODEX_QT_EFF, right = FormatDuration(q.tm.sum / q.tm.n / 10) }) + if q.tr and q.tr.n and q.tr.n > 0 then + D:Add({ text = L.CODEX_QT_RAW, right = FormatDuration(q.tr.sum / q.tr.n / 10) }) + end + if q.ta and q.ta.n and q.ta.n > 0 then + D:Add({ text = L.CODEX_QT_ALL, right = FormatDuration(q.ta.sum / q.ta.n / 10) }) + end + D:Add({ text = L.CODEX_QT_N, right = tostring(q.tm.n) }) + end + + D:Add({ style = "heading", text = L.CODEX_SEC_GIVE }) + if q.si then + -- Quest startet durch ein Item: das Item (mit seinen Fundorten im Item-Eintrag) statt einer Spielerposition + D:Add({ style = "sub", text = L.CODEX_GIVE_BY_ITEM }) + ItemRow(q.si, nil, 0, " |cff9d9d9d[" .. L.CODEX_START_ITEM .. "]|r") + elseif q.give or not (sq and #sq.start > 0) then + RefRow(q.give) + else + for _, r in ipairs(sq.start) do SeedRef(r) end + end + D:Add({ style = "heading", text = L.CODEX_SEC_TURN }) + if q.turn or not (sq and #sq.stop > 0) then + RefRow(q.turn) + else + for _, r in ipairs(sq.stop) do SeedRef(r) end + end + if #Codex.CollectPoints({ kind = "quests", id = id }) > 0 then + MapLink({ kind = "quests", id = id }, Codex.QuestTitle(q, id)) + end + + if q.si then + D:Add({ style = "sub", text = L.CODEX_PROPS_STARTITEM .. " " .. tostring(q.si) .. " " .. tostring(Codex.ItemName and Codex:ItemName(q.si) or "") }) + end + if q.dtx then + D:Add({ style = "heading", text = L.CODEX_SEC_QTEXT }) + D:Add({ style = "sub", text = q.dtx }) + end + + local hasReward = q.xp or q.money or q.rep or q.fixed or q.choice + if hasReward then + D:Add({ style = "heading", text = L.CODEX_SEC_REWARD }) + if q.xp then D:Add({ text = L.CODEX_XP, right = tostring(q.xp) }) end + if q.money then + D:Add({ text = L.CODEX_MONEY, right = FormatMoney(q.money) }) + end + if q.rep then + local names = {} + for name in pairs(q.rep) do names[#names + 1] = name end + table.sort(names) + for _, name in ipairs(names) do + local v = q.rep[name] + D:Add({ text = L.CODEX_REP .. ": " .. name, right = (v > 0 and "+" or "") .. v }) + end + end + for _, r in ipairs(q.fixed or {}) do + ItemRow(r.id, r.c and r.c > 1 and ("x" .. r.c) or nil, 0, " |cff9d9d9d[" .. L.CODEX_FIXED .. "]|r") + end + for _, r in ipairs(q.choice or {}) do + local chosen = q.chosen and q.chosen[r.id] + ItemRow(r.id, chosen and string.format(L.CODEX_CHOSEN, chosen) or (r.c and r.c > 1 and ("x" .. r.c) or nil), 0, + " |cff9d9d9d[" .. L.CODEX_CHOICE .. "]|r") + end + end + + if q.obj and #q.obj > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_OBJ }) + for _, o in ipairs(q.obj) do + local label = L["CODEX_TYPE_" .. tostring(o.ty)] or L.CODEX_TYPE_other + local itemIDs = o.ty == "item" and Codex.ObjectiveItems(q, o, id) or nil + local shownName = o.name + if not shownName and itemIDs and itemIDs[1] then + shownName = Codex:ItemName(itemIDs[1]) + end + D:Add({ text = label .. ": " .. (shownName or o.txt or "?"), right = o.req and ("x" .. o.req) or nil }) + local lname = o.name and o.name:lower() or nil + if o.ty == "monster" then + local shown = {} + local ids = {} + for uid, hits in pairs(o.ids or {}) do ids[#ids + 1] = { id = uid, n = hits } end + table.sort(ids, function(a, b) return a.n > b.n end) + for _, e in ipairs(ids) do + shown[e.id] = true + EntityLink("units", e.id, Codex.V().units[e.id], nil) + end + for key in pairs(Codex.QuestKillKeys(id)) do + local sid = tonumber(key:sub(2)) + if key:sub(1, 1) == "u" and sid and not shown[sid] then + shown[sid] = true + EntityLink("units", sid, Codex.V().units[sid], L.CODEX_MANUAL_TAG) + end + end + if lname then + local count = 0 + for uid, u in pairs(Codex.V().units) do + if not shown[uid] and ((u.n and u.n:lower() == lname) or (u.cde and u.cde:lower() == lname) or (u.cen and u.cen:lower() == lname)) then + count = count + 1 + if count > 4 then break end + EntityLink("units", uid, u, nil) + end + end + end + elseif itemIDs then + for _, itemID in ipairs(itemIDs) do + for key in pairs(Codex.QuestItemKeys(id, itemID)) do + local tk = key:sub(1, 1) == "u" and "units" or "objects" + local sid = tonumber(key:sub(2)) + local ent = tk == "units" and Codex.V().units[sid] or Codex.V().objects[sid] + EntityLink(tk, sid, ent, L.CODEX_MANUAL_TAG) + end + local srcs = q.qi and q.qi[itemID] + if srcs then + local list = {} + for key, n in pairs(srcs) do list[#list + 1] = { key = key, n = n } end + table.sort(list, function(a, b) return a.n > b.n end) + for i, e in ipairs(list) do + if i > 6 then break end + local tk = e.key:sub(1, 1) == "u" and "units" or "objects" + local sid = tonumber(e.key:sub(2)) + local ent = tk == "units" and Codex.V().units[sid] or Codex.V().objects[sid] + EntityLink(tk, sid, ent, tostring(e.n) .. "x") + end + end + end + end + end + elseif sq and #sq.obj > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_OBJ .. " " .. SeedTag() }) + for _, r in ipairs(sq.obj) do SeedRef(r) end + end + + -- Gehoert zur Quest (von Hand zugeordnet): Items, Kreaturen, Objekte + do + local rel = Codex.QuestRelated(id) + if #rel.i + #rel.u + #rel.o > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_QREL }) + for _, itemID in ipairs(rel.i) do ItemRow(itemID, L.CODEX_MANUAL_TAG, 0) end + for _, uid in ipairs(rel.u) do EntityLink("units", uid, Codex.V().units[uid], L.CODEX_MANUAL_TAG) end + for _, oid in ipairs(rel.o) do EntityLink("objects", oid, Codex.V().objects[oid], L.CODEX_MANUAL_TAG) end + end + end + + -- Quest-Text (Beschreibung, Ziel, Zwischentext, Abschlusstext); $N wird zum eigenen Namen + do + local qv = Codex.V().quests[id] + local tx = qv and qv.tx + if type(tx) == "table" then + local myName = (UnitName and UnitName("player")) or "?" + local first = true + for _, f in ipairs({ "d", "o", "p", "r" }) do + local v = tx[f] + if type(v) == "string" and v ~= "" then + if first then + D:Add({ style = "heading", text = L.CODEX_SEC_QTEXT }) + first = false + end + D:Add({ style = "sub", text = L["CODEX_QT_" .. f:upper()] }) + local shown = v:gsub("{br}", "\n\n"):gsub("%$[nN]", (myName:gsub("%%", "%%%%"))) + D:Add({ style = "text", text = shown }) + end + end + end + end + + -- Ruf-Ziel aus dem Quest-Cache + do + local m = Codex.Catalog and Codex.Catalog.QuestMeta and Codex.Catalog.QuestMeta(id) + if m and m.rep then + D:Add({ style = "heading", text = L.CODEX_SEC_REP .. " |cff8a8a96[" .. L.CODEX_CAT_TAG .. "]|r" }) + D:Add({ text = m.rep }) + end + end + + -- Laut Server (Katalog): Ziele, Belohnung und Texte aus der Server-Antwort; nur, was die eigenen Daten nicht haben + do + local det = Codex.Catalog and Codex.Catalog.Details and Codex.Catalog.Details(id) + if det then + local qv = Codex.V().quests[id] + local tag = " |cff8a8a96[" .. L.CODEX_CAT_TAG .. "]|r" + if #det.req > 0 and not (qv and qv.obj and #qv.obj > 0) then + D:Add({ style = "heading", text = L.CODEX_SEC_OBJ .. tag }) + for _, r in ipairs(det.req) do + local cnt = r.count and r.count > 1 and ("x" .. r.count) or nil + if r.kind == "monster" then + ServerInfo("units", r.id, true) + EntityLink("units", r.id, Codex.V().units[r.id], cnt) + elseif r.kind == "object" then + ServerInfo("objects", r.id, true) + EntityLink("objects", r.id, Codex.V().objects[r.id], cnt) + else + ItemRow(r.id, cnt, 0) + end + end + end + local hasRew = (det.money or 0) > 0 or #det.rew > 0 or #det.choice > 0 or det.spell + if hasRew and not (qv and (qv.fixed or qv.choice or qv.money)) then + D:Add({ style = "heading", text = L.CODEX_SEC_REWARD .. tag }) + if (det.money or 0) > 0 then D:Add({ text = L.CODEX_MONEY, right = FormatMoney(det.money) }) end + for _, it in ipairs(det.rew) do + ItemRow(it.id, it.count > 1 and ("x" .. it.count) or nil, 0, " |cff9d9d9d[" .. L.CODEX_FIXED .. "]|r") + end + for _, it in ipairs(det.choice) do + ItemRow(it.id, it.count > 1 and ("x" .. it.count) or nil, 0, " |cff9d9d9d[" .. L.CODEX_CHOICE .. "]|r") + end + if det.spell then D:Add({ text = L.CODEX_SRV_SPELL, right = tostring(det.spell) }) end + end + if det.src and not (qv and qv.si) then + D:Add({ style = "heading", text = L.CODEX_PROPS_STARTITEM .. tag }) + ItemRow(det.src, nil, 0) + end + if not (qv and type(qv.tx) == "table") and (det.desc or det.obj or det.done) then + local myName = (UnitName and UnitName("player")) or "?" + local function Fill(v) + v = v:gsub("%$[bB]", "\n"):gsub("%$[nN]", (myName:gsub("%%", "%%%%"))) + return v + end + D:Add({ style = "heading", text = L.CODEX_SEC_QTEXT .. tag }) + for _, def in ipairs({ { "D", det.desc }, { "O", det.obj }, { "R", det.done } }) do + if def[2] and def[2] ~= "" then + D:Add({ style = "sub", text = L["CODEX_QT_" .. def[1]] }) + D:Add({ style = "text", text = Fill(def[2]) }) + end + end + end + end + end + + -- Questkette: Vorquests und Folgequests (Daten und Vorlage) + do + local function Chain(heading, ids) + if #ids == 0 then return end + D:Add({ style = "heading", text = heading }) + for i, qid in ipairs(ids) do + if i > 30 then break end + local lq = Codex.V().quests[qid] + QuestLink(qid, lq, lq and (lq.done or 0) > 0 and string.format(L.CODEX_DONE, lq.done) or nil) + end + end + Chain(L.CODEX_SEC_PRE, Codex.QuestPre(id)) + Chain(L.CODEX_SEC_NEXT, Codex.QuestNext(id)) + end + end + + local function XPSection(ent) + if not ent.xp or next(ent.xp) == nil then + return + end + D:Add({ style = "heading", text = L.CODEX_SEC_XP }) + local levels = {} + for pl in pairs(ent.xp) do levels[#levels + 1] = pl end + table.sort(levels, function(a, b) return a > b end) + local rows = 0 + for _, pl in ipairs(levels) do + local xm = ent.xm and ent.xm[pl] + if xm and next(xm) then + -- nach Gegnerstufe getrennt: zu jeder Zeile gehoert ein Formelwert + local mls = {} + for ml in pairs(xm) do mls[#mls + 1] = ml end + table.sort(mls, function(a, b) return a > b end) + for _, ml in ipairs(mls) do + if rows >= 12 then break end + rows = rows + 1 + local s = xm[ml] + local pred = Codex.PredictXP(pl, ml, ent.c) + D:Add({ + text = string.format(L.CODEX_XP_UNIT_ROW2, pl, ml), + right = string.format("Ø %.1f (n=%d)", s.sum / s.n, s.n) .. " | " .. pred, + }) + local rs = ent.xr and ent.xr[pl] and ent.xr[pl][ml] + if rs and rs.n and rs.n > 0 and rows < 12 then + rows = rows + 1 + D:Add({ + style = "sub", + text = " " .. L.CODEX_XP_WITH_RESTED, + right = string.format("Ø %.1f (n=%d)", rs.sum / rs.n, rs.n), + }) + end + end + elseif rows < 12 then + rows = rows + 1 + local s = ent.xp[pl] + local right = string.format("Ø %.1f (n=%d)", s.sum / s.n, s.n) + if ent.l1 and ent.l1 == ent.l2 then + right = right .. " | " .. Codex.PredictXP(pl, ent.l1, ent.c) + end + D:Add({ text = string.format(L.CODEX_XP_UNIT_ROW, pl), right = right }) + end + end + end + + -- Beute und Waren laut Vorlage; was wir selbst gesehen haben, steht schon oben und wird hier uebersprungen + local function SeedLootSection(tkind, id, ent) + local shown = {} + for _, e in ipairs(Codex.Seed.Drops(tkind, id)) do + local seen = (ent and ent.d and ent.d[e.item]) or (ent and ent.alt and ent.alt.d and ent.alt.d[e.item]) + if not seen then shown[#shown + 1] = e end + end + if #shown > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_LOOT_SEED }) + for i, e in ipairs(shown) do + if i > 40 then break end + ItemRow(e.item, SeedPct(e.chance), 0) + end + end + local roles = Codex.Seed.Roles(tkind, id) + if tkind == "units" and roles and roles.vendor then + local goods = Codex.Seed.VendorItems(id) + if #goods > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_SELLS }) + local shownWares = 0 + for _, itemID in ipairs(goods) do + if not (ent and ent.wa and ent.wa[itemID]) then + shownWares = shownWares + 1 + if shownWares > 60 then break end + ItemRow(itemID, nil, 0) + end + end + end + end + end + + -- Rollen laut eigenen und geteilten Beobachtungen: Waren mit allen Preisen, Lehrstoff, Flugziele + local function RolesSection(tkind, ent) + if tkind ~= "units" then return end + if ent.ti then + D:Add({ style = "sub", text = string.format(L.CODEX_TITLE_LINE, ent.ti) }) + end + if ent.wa and next(ent.wa) then + local goods = {} + for itemID, w in pairs(ent.wa) do goods[#goods + 1] = { id = itemID, w = w } end + table.sort(goods, function(a, b) return a.id < b.id end) + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_WARES, #goods) }) + for i, g in ipairs(goods) do + if i > 120 then break end + local extra = {} + if g.w.st and g.w.st > 1 then extra[#extra + 1] = "x" .. g.w.st end + if g.w.lim then extra[#extra + 1] = L.CODEX_WARE_LIMITED end + ItemRow(g.id, PriceText(g.w.pr, g.w.ec), 0, #extra > 0 and (" |cff9a9aa3" .. table.concat(extra, " ") .. "|r") or nil) + end + end + if ent.tr and next(ent.tr) then + local list = {} + for _, r in pairs(ent.tr) do list[#list + 1] = r end + table.sort(list, function(a, b) + if (a.lv or 0) ~= (b.lv or 0) then return (a.lv or 0) < (b.lv or 0) end + return (a.nm or "") < (b.nm or "") + end) + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_TRAINS, #list) }) + for i, r in ipairs(list) do + if i > 150 then break end + local right = {} + if r.lv then right[#right + 1] = string.format(L.CODEX_TRAIN_LEVEL, r.lv) end + if r.sn then right[#right + 1] = r.sr and string.format("%s %d", r.sn, r.sr) or r.sn end + local price = PriceText(r.pr) + if price then right[#right + 1] = price end + local rank = r.rk or (r.sp and Codex.SpellRank(r.sp)) or nil + local icon = r.sp and Codex.SpellIcon(r.sp) or nil + D:Add({ text = (r.nm or "?") .. (rank and (" |cff9a9aa3(" .. rank .. ")|r") or ""), + right = table.concat(right, " | "), rightWidth = 330, + spellID = r.sp, icon = icon or (r.sp and "Interface\\Icons\\INV_Misc_QuestionMark") or nil }) + end + end + if ent.fl and next(ent.fl) then + local list = {} + for dest, pr in pairs(ent.fl) do list[#list + 1] = { dest = dest, pr = pr } end + table.sort(list, function(a, b) return a.dest < b.dest end) + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_FLIGHTS, #list) }) + if ent.fn then D:Add({ style = "sub", text = string.format(L.CODEX_FLIGHT_FROM, ent.fn) }) end + for _, e in ipairs(list) do + D:Add({ text = e.dest, right = PriceText(e.pr) }) + end + end + end + + local function ShowEntity(tkind, id) + local live = tkind == "units" and Codex.V().units[id] or Codex.V().objects[id] + local seedEnt = SeedOK() and Codex.Seed.Entity(tkind, id) or nil + local srv = ServerInfo(tkind, id, true) + local catRev = Codex.Catalog and Codex.Catalog.Reverse and Codex.Catalog.Reverse()[tkind == "units" and "monster" or "object"][id] + if not live and not seedEnt and not srv and not catRev then return end + local ent = live or {} + ShowPortrait(tkind == "units" and UnitIcon(ent) or ICON.objects, tkind == "units" and id or nil) + D:Add({ style = "title", text = UnitTitle(ent, id, tkind), indent = 76 }) + local sub = {} + local lvl = LevelText(ent) or (seedEnt and tkind == "units" and LevelText(seedEnt)) or nil + if lvl then sub[#sub + 1] = lvl end + if ent.c then + sub[#sub + 1] = (ent.ed and ent.ed.cl and L["CODEX_PROPS_CLASS_" .. ent.ed.cl]) or ent.c + elseif ent.c == false then + sub[#sub + 1] = L.CODEX_PROPS_CLASS_normal + elseif seedEnt and tkind == "units" and RankLabel(seedEnt.rank) then + sub[#sub + 1] = RankLabel(seedEnt.rank) + end + if ent.dg ~= nil then + sub[#sub + 1] = ent.dg and L.CODEX_PROPS_DG_YES or L.CODEX_PROPS_DG_NO + elseif ent.iz and next(ent.iz) then + sub[#sub + 1] = L.CODEX_PROPS_DG_YES + end + if not (ent.ez and #ent.ez > 0) and ent.iz and next(ent.iz) then + local names = {} + for iid in pairs(ent.iz) do names[#names + 1] = Codex.InstanceName(iid) end + table.sort(names) + sub[#sub + 1] = string.format(L.CODEX_PROPS_ZONES_LINE, table.concat(names, ", ")) + end + if ent.ez and #ent.ez > 0 then + local names = {} + for _, m in ipairs(ent.ez) do names[#names + 1] = Codex.MapName(m) end + sub[#sub + 1] = string.format(L.CODEX_PROPS_ZONES_LINE, table.concat(names, ", ")) + end + if ent.f then sub[#sub + 1] = string.format(L.CODEX_FAMILY, ent.f) end + if seedEnt and (seedEnt.fac == "A" or seedEnt.fac == "H") then + sub[#sub + 1] = seedEnt.fac == "A" and L.CODEX_FAC_A or L.CODEX_FAC_H + end + if srv then + if tkind == "units" then + local CC = _G.C_CreatureInfo + local okT, ti = pcall(CC and CC.GetCreatureTypeInfo or function() end, srv.type) + if okT and type(ti) == "table" and type(ti.name) == "string" then sub[#sub + 1] = ti.name end + if not ent.c and RankLabel(srv.rank) then sub[#sub + 1] = RankLabel(srv.rank) end + if type(srv.subName) == "string" and srv.subName ~= "" then sub[#sub + 1] = "<" .. srv.subName .. ">" end + else + local g = GO_TYPES[srv.type] + if g then sub[#sub + 1] = Codex.Lang() == "en" and g[1] or g[2] end + end + end + local roleNames = RoleNames(tkind, id) + if #roleNames > 0 then sub[#sub + 1] = table.concat(roleNames, ", ") end + sub[#sub + 1] = "ID " .. id + local startOnly = live and Codex.Share and Codex.Share.Origin and Codex.Share.Origin(tkind == "units" and "u" or "o", id) == "start" + if not live then sub[#sub + 1] = seedEnt and SeedTag() or ("|cff8a8a96[" .. L.CODEX_CAT_TAG .. "]|r") + elseif startOnly then sub[#sub + 1] = "|cff8a8a96[" .. L.CODEX_START_TAG .. "]|r" end + D:Add({ style = "sub", text = table.concat(sub, " | "), indent = 76 }) + D.y = math.max(D.y, 72) + if not live then + D:Add({ style = "sub", text = seedEnt and L.CODEX_SEED_NOTE or L.CODEX_SRV_NOTE }) + elseif startOnly then + D:Add({ style = "sub", text = L.CODEX_START_NOTE }) + end + -- Gebiet mit Stufenspanne (Verweis in die Gebietsansicht) + for i, zkey in ipairs(Codex.ZonesOf(ent)) do local zkey = zkey + if i > 3 then break end + local zd = Codex.Zones and Codex.Zones.Get(zkey) + D:Add({ style = "link", text = Codex.MapName(zkey), icon = ICON.zones, + right = zd and RangeText(zd.lo, zd.hi) or nil, onClick = function() Go("zones", zkey) end }) + end + local ttkClasses = Codex.Time and Codex.Time.UnitClasses(ent) or {} + if #ttkClasses > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_TTK_CLASSES }) + for _, c in ipairs(ttkClasses) do + D:Add({ + text = Codex.Time.ClassLabel(c.cls) .. (c.own and (" " .. L.CODEX_TTK_YOU) or ""), + right = string.format("%.1f s (n=%d)", c.secs, c.n), + }) + end + end + if ent.rk and ent.rk > 0 then + D:Add({ style = "sub", text = string.format(L.CODEX_REMOTE_HINT, ent.rk, ent.k or 0) }) + elseif ent.remote and ent.remote > 0 then + D:Add({ style = "sub", text = L.CODEX_REMOTE_ONLY }) + end + local avg = Codex.AverageCoin(ent) + if avg then + D:Add({ text = string.format(L.CODEX_COIN_AVG, ""), right = FormatMoney(avg) }) + end + PlacesSection(ent, { kind = tkind, id = id }, UnitTitle(ent, id, tkind), seedEnt and Codex.Seed.Cells(tkind, id) or nil) + RolesSection(tkind, ent) + XPSection(ent) + ValueSection(ent) + QuestsOfUnit(tkind, id, UnitTitle(ent, id, tkind)) + LootSection(ent, false) + if ent.alt then LootSection(ent, true) end + if seedEnt then SeedLootSection(tkind, id, live) end + end + + local function ShowZone(key) + local zd = Codex.Zones.Get(key) + if not zd then return end + ShowPortrait(ICON.zones, nil) + D:Add({ style = "title", text = Codex.MapName(key), indent = 76 }) + local sub = { zd.dungeon and L.CODEX_ZONE_DUNGEON or L.CODEX_ZONE_WORLD, (key < 0 and "Instanz " or "Karte ") .. math.abs(key) } + D:Add({ style = "sub", text = table.concat(sub, " | "), indent = 76 }) + D.y = math.max(D.y, 72) + D:Add({ style = "heading", text = L.CODEX_SEC_ZONE_LEVELS }) + D:Add({ text = L.CODEX_ZONE_TYPICAL, right = RangeText(zd.lo, zd.hi) or "-" }) + if zd.avg then D:Add({ text = L.CODEX_ZONE_AVG, right = string.format("%.1f", zd.avg) }) end + D:Add({ text = L.CODEX_ZONE_COUNT, right = tostring(zd.units) }) + if zd.manual then D:Add({ style = "sub", text = L.CODEX_ZONE_MANUAL_NOTE }) end + if zd.few and not zd.manual then D:Add({ style = "sub", text = L.CODEX_ZONE_FEW_NOTE }) end + if #zd.out > 0 then + local parts = {} + for _, e in ipairs(zd.out) do + local ent = Codex.V().units[e.id] + parts[#parts + 1] = string.format("%s (%s)", UnitTitle(ent, e.id, "units"), RangeText(e.l1, e.l2) or "?") + if #parts >= 6 then break end + end + D:Add({ style = "sub", text = L.CODEX_ZONE_OUTLIER_LIST .. ": " .. table.concat(parts, ", ") }) + end + -- eigene Messung (Modul Quest): Erfahrung pro Stunde in diesem Gebiet, nur fuer die aktuellen Einstellungen + local rates = Codex.ZoneRateProvider and Codex.ZoneRateProvider(key) or {} + if #rates > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_ZONE_RATE }) + D:Add({ style = "sub", text = L.CODEX_ZONE_RATE_NOTE }) + for _, r in ipairs(rates) do + local mins = r.hours and (r.hours * 60) or nil + D:Add({ text = string.format(L.CODEX_ZONE_RATE_LINE, r.pl), right = string.format("%d XP/h%s (%d min)", + r.rate, mins and string.format(L.CODEX_ZONE_RATE_LEVEL, mins) or "", r.secs / 60) }) + end + end + -- Kreaturen des Gebiets, nach Stufe + local members = Codex.Zones.Members(key) + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_ZONE_UNITS, #members) }) + for i, m in ipairs(members) do local m = m + if i > 150 then break end + local ent = Codex.V().units[m.id] + local tags = {} + if m.c then tags[#tags + 1] = (L["CODEX_PROPS_CLASS_" .. tostring(m.c)] or tostring(m.c)) end + if m.out then tags[#tags + 1] = L.CODEX_ZONE_OUTLIER end + D:Add({ style = "link", text = UnitTitle(ent, m.id, "units") .. " (" .. (RangeText(m.l1, m.l2) or "?") .. ")", + right = #tags > 0 and table.concat(tags, ", ") or nil, onClick = function() Go("units", m.id) end, icon = ICON.units }) + end + -- Quests, deren Geber in diesem Gebiet steht (nur beim Oeffnen berechnet) + if key > 0 then + local pl = UnitLevel and UnitLevel("player") or 1 + local here, foryou = {}, {} + for qid, q in pairs(Codex.V().quests) do + local g = q.give + if g and g.m == key then + local e = { id = qid, q = q, lvl = q.lvl or 0, mn = q.mn or 0, title = Codex.QuestTitle(q, qid) or "" } + here[#here + 1] = e + if e.mn <= pl and e.lvl >= pl - 4 then + local st = Codex.QuestStatus(qid) + if st ~= "done" and st ~= "active" then foryou[#foryou + 1] = e end + end + end + end + local function ByLevel(a, b) + if a.lvl ~= b.lvl then return a.lvl < b.lvl end + if a.title ~= b.title then return a.title < b.title end + return a.id < b.id + end + table.sort(here, ByLevel) + table.sort(foryou, ByLevel) + local function Row(e) + local right = e.mn > 1 and string.format(L.CODEX_ZONE_QMIN, e.mn) or nil + local st = Codex.QuestStatus(e.id) + if st == "done" then right = "|cff6fd66f" .. L.CODEX_STATUS_DONE .. "|r" elseif st == "active" then right = "|cffffd060" .. L.CODEX_STATUS_ACTIVE .. "|r" end + QuestLink(e.id, e.q, right) + end + if #foryou > 0 then + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_ZONE_FORYOU, #foryou, pl) }) + for i, e in ipairs(foryou) do + if i > 20 then break end + Row(e) + end + end + if #here > 0 then + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_ZONE_QUESTS, #here) }) + for i, e in ipairs(here) do + if i > 80 then break end + Row(e) + end + end + -- Flugpunkte aus dem Karten-Scan + local flights = {} + for _, v in pairs((Codex.db.cat and Codex.db.cat.x) or {}) do + if type(v) == "string" then + local a = tonumber(v:match("areaID=(%d+)")) + local name = v:match("|(.+)$") + if a == key and name then flights[#flights + 1] = name end + end + end + table.sort(flights) + if #flights > 0 then + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_ZONE_FLIGHT, #flights) }) + for _, name in ipairs(flights) do D:Add({ text = name }) end + end + end + -- Spanne von Hand setzen (nur Berechtigte) + if Codex.Trust and Codex.Trust.CanEdit() and Codex.NameUI and Codex.NameUI.OpenZone then + D:Add({ style = "heading", text = L.CODEX_SEC_ZONE_EDIT }) + D:Add({ style = "link", text = L.CODEX_ZONE_EDIT, onClick = function() Codex.NameUI.OpenZone(key) end }) + end + end + + local function ShowLearn(lv) + local plan = learnSel and Codex.LearnPlan(learnSel) + local g = plan and plan.levels[lv] + if not g then return end + local pl = UnitLevel and UnitLevel("player") or 1 + ShowPortrait(ICON.learn, nil) + local head = lv > 0 and string.format(L.CODEX_LEARN_TITLE, lv) or L.CODEX_LEARN_LVUNKNOWN + D:Add({ style = "title", text = head .. " - " .. Codex.Time.ClassLabel(learnSel), indent = 76 }) + D:Add({ style = "sub", text = string.format(L.CODEX_LEARN_SUB, #g.spells, FormatMoney(g.cost)), indent = 76 }) + D.y = math.max(D.y, 72) + if lv > pl then + D:Add({ text = string.format(L.CODEX_LEARN_CUM, pl + 1, FormatMoney(Codex.LearnCost(plan, pl, lv))) }) + end + D:Add({ style = "sub", text = L.CODEX_LEARN_NOTE }) + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_LEARN_SPELLS, #g.spells) }) + for _, sp in ipairs(g.spells) do + local rank = sp.rk or (sp.sp and Codex.SpellRank(sp.sp)) or nil + local icon = sp.sp and Codex.SpellIcon(sp.sp) or nil + D:Add({ text = (sp.nm or "?") .. (rank and (" |cff9a9aa3(" .. rank .. ")|r") or ""), + right = (sp.cost and sp.cost > 0) and FormatMoney(sp.cost) or "-", rightWidth = 150, + spellID = sp.sp, icon = icon or (sp.sp and "Interface\\Icons\\INV_Misc_QuestionMark") or nil }) + end + D:Add({ style = "heading", text = string.format(L.CODEX_SEC_LEARN_TRAINERS, #g.trainers) }) + for i, id in ipairs(g.trainers) do + if i > 20 then break end + local ent = Codex.V().units[id] + local spot = ent and ZoneOf(ent) + EntityLink("units", id, ent, spot) + end + end + + local function ShowXP(key) + local pl, ml, cls, kindFlag = key:match("^(%d+):(%d+):(%a+):(%a)$") + pl, ml = tonumber(pl), tonumber(ml) + if not pl then return end + local rows = Codex:XPRows(true) + local r + for _, row in ipairs(rows) do + if XPKey(row) == key then r = row break end + end + if not r then return end + ShowPortrait(ICON.xp, nil) + D:Add({ style = "title", text = string.format(L.CODEX_XP_TITLE, pl, ml), indent = 76 }) + local sub = {} + local label = ClassLabel(cls) + if label then sub[#sub + 1] = label end + if r.rested then + sub[#sub + 1] = L.CODEX_XP_RESTED_TAG + elseif r.bonus then + sub[#sub + 1] = L.CODEX_XP_BONUS_TAG + end + D:Add({ style = "sub", text = table.concat(sub, " | "), indent = 76 }) + D.y = math.max(D.y, 72) + + D:Add({ style = "heading", text = L.CODEX_SEC_XPMEAS }) + D:Add({ text = L.CODEX_XP_SAMPLES, right = tostring(r.n) }) + D:Add({ text = L.CODEX_XP_AVG, right = string.format("%.2f", r.avg) }) + D:Add({ text = L.CODEX_XP_MINMAX, right = string.format("%d / %d", r.min, r.max) }) + + local secs, nTTK + if not r.bonus and cls == "normal" then + secs, nTTK = OwnTTK(pl, ml) + end + if secs and secs > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_TIME }) + D:Add({ text = string.format(L.CODEX_TTK_AVG, Codex.Time.ClassName()), right = string.format("%.1f s (n=%d)", secs, nTTK) }) + D:Add({ text = L.CODEX_TTK_XPM, right = string.format("%d", r.avg / secs * 60) }) + end + + if not r.bonus and cls == "normal" and Codex.Share and Codex.Share.TTKClasses then + local classes = Codex.Share.TTKClasses(pl, ml - pl) + if #classes > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_TTK_CLASSES }) + local mine = Codex.Time and Codex.Time.PlayerToken() + for _, c in ipairs(classes) do + D:Add({ + text = Codex.Time.ClassLabel(c.cls) .. (c.cls == mine and (" " .. L.CODEX_TTK_YOU) or ""), + right = string.format("%.1f s (n=%d) | %d XP/min", c.secs, c.n, r.avg / c.secs * 60), + }) + end + end + end + + D:Add({ style = "heading", text = L.CODEX_SEC_XPCALC }) + D:Add({ text = L.CODEX_XP_BASE, right = tostring((ml >= pl and pl or ml) * 5 + 45) }) + D:Add({ text = L.CODEX_XP_COLOR, right = L["CODEX_COLOR_" .. r.color] or r.color }) + D:Add({ text = L.CODEX_XP_ZD, right = tostring(Codex.ZeroDiff(pl)) }) + D:Add({ text = L.CODEX_XP_GRAY, right = tostring(Codex.GrayLevel(pl)) }) + D:Add({ text = L.CODEX_XP_PRED, right = tostring(r.pred) }) + D:Add({ text = L.CODEX_XP_DIFF, right = string.format("%+.2f", r.diff) }) + D:Add({ style = "sub", text = L.CODEX_XP_NOTE }) + end + + local function ShowItem(itemID) + local row = D:Add({ style = "title", text = Codex:ItemName(itemID) or ("#" .. itemID), icon = "Interface\\Icons\\INV_Misc_QuestionMark" }) + row.itemID = itemID + row:EnableMouse(true) + local q0 = Codex.QualityOf(itemID) + if q0 then row.left:SetText(Colored(Codex:ItemName(itemID) or ("#" .. itemID), q0)) end + Util.RequestItem(itemID, function(info) + if info then + Codex.RememberQuality(itemID, info.quality) + row.icon:SetTexture(info.icon) + row.left:SetText(Colored(Codex:ItemName(itemID) or info.name, info.quality)) + end + end) + do + local fx = ItemIndex()[itemID] + if fx and fx.ah then + D:Add({ style = "sub", text = "ID " .. itemID .. " | |cff8a8a96[" .. L.CODEX_AH_TAG .. "]|r" }) + D:Add({ style = "sub", text = L.CODEX_AH_NOTE }) + else + D:Add({ style = "sub", text = "ID " .. itemID }) + end + end + local ied = (Codex.V().ied or {})[itemID] + local iz = ied and (ied.ez or (ied.ed and ied.ed.z)) + local idg = ied and (ied.dg ~= nil and ied.dg or (ied.ed and ied.ed.dg)) + if iz or idg ~= nil then + local bits = {} + if iz and #iz > 0 then + local names = {} + for _, m in ipairs(iz) do names[#names + 1] = Codex.MapName(m) end + bits[#bits + 1] = string.format(L.CODEX_PROPS_ZONES_LINE, table.concat(names, ", ")) + end + if idg ~= nil then bits[#bits + 1] = idg and L.CODEX_PROPS_DG_YES or L.CODEX_PROPS_DG_NO end + D:Add({ style = "sub", text = table.concat(bits, " | ") }) + end + do + local belongs = Codex.EntityQuests("i", itemID) + if #belongs > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_QBEL }) + for i, qid in ipairs(belongs) do + if i > 30 then break end + QuestLink(qid, Codex.V().quests[qid], L.CODEX_MANUAL_TAG) + end + end + end + + -- Auktionshaus (nur mit Auktions-Modul) + local ai = Codex.AuctionInfo and Codex.AuctionInfo(itemID) + if ai then + D:Add({ style = "heading", text = L.CODEX_SEC_AH }) + local thin = ai.thin and " |cffff8000~|r" or "" + if ai.price then D:Add({ text = L.CODEX_AH_PRICE, right = FormatMoney(ai.price) .. thin }) end + if ai.min then D:Add({ text = L.CODEX_AH_MIN, right = FormatMoney(ai.min) }) end + if ai.avg then D:Add({ text = L.CODEX_AH_AVG, right = FormatMoney(ai.avg) }) end + if ai.qty then D:Add({ text = L.CODEX_AH_QTY, right = tostring(ai.qty) .. thin }) end + if ai.age then + local when = ai.age == 0 and L.CODEX_AH_TODAY or string.format(L.CODEX_AH_DAYS, ai.age) + if ai.stale then when = "|cff9d9d9d" .. when .. " (" .. L.CODEX_AH_OLD .. ")|r" end + D:Add({ text = L.CODEX_AH_AGE, right = when }) + end + if ai.thin then D:Add({ style = "sub", text = L.CODEX_AH_THIN }) end + local function Pct(v) + local color = v > 0.005 and "|cff1eff00" or (v < -0.005 and "|cffff4040" or "|cff9d9d9d") + return string.format("%s%+.0f %%|r", color, v * 100) + end + if ai.trend then D:Add({ text = L.CODEX_AH_TREND_DAY, right = Pct(ai.trend) }) end + if ai.trendAll then D:Add({ text = L.CODEX_AH_TREND_ALL, right = Pct(ai.trendAll) }) end + if ai.net then D:Add({ text = L.CODEX_AH_NET, right = FormatMoney(ai.net) }) end + local info = Util.GetItem(itemID) + local vendor = info and info.sellPrice or 0 + if vendor > 0 and ai.net then + D:Add({ text = L.CODEX_AH_VENDOR_SELL, right = FormatMoney(vendor) }) + local diff = ai.net - vendor + if diff > 0 then + D:Add({ text = L.CODEX_AH_SELL_AH, right = "|cff1eff00+" .. FormatMoney(diff) .. "|r" }) + else + D:Add({ text = L.CODEX_AH_SELL_VENDOR, right = "|cff9d9d9d+" .. FormatMoney(-diff) .. "|r" }) + end + end + local buy = LowestBuyPrices()[itemID] + if buy and ai.net then + D:Add({ text = L.CODEX_AH_VENDOR_BUY, right = FormatMoney(buy) }) + local margin = ai.net - buy + if margin > 0 then + D:Add({ text = L.CODEX_AH_FLIP, right = "|cff1eff00+" .. FormatMoney(margin) .. " (" .. string.format("%+.0f %%", margin / buy * 100) .. ")|r" }) + else + D:Add({ text = L.CODEX_AH_FLIP, right = "|cffff4040-" .. FormatMoney(-margin) .. "|r" }) + end + end + D:Chart(ai.history) + end + + -- Werte (Staerke, Beweglichkeit ...), vom Spiel gelesen + local stats = Codex:GetStats(itemID) + if stats and next(stats) then + local keys = Codex:StatKeys({ itemID }) + D:Add({ style = "heading", text = L.CODEX_SEC_STATS }) + if stats._dmin and stats._dmax and stats._spd then + D:Add({ style = "line", text = L.CODEX_WEAPON_DAMAGE, + right = string.format("%s - %s", Codex.FormatStat(stats._dmin), Codex.FormatStat(stats._dmax)) }) + D:Add({ style = "line", text = L.CODEX_WEAPON_SPEED, right = string.format("%.2f", stats._spd) }) + end + for _, key in ipairs(keys) do + if not Codex.FXFLAGS[key] and type(stats[key]) == "number" then + D:Add({ style = "line", text = Codex.StatName(key), right = Codex.FormatStat(stats[key]) }) + end + end + if type(stats._fx) == "table" and #stats._fx > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_EFFECTS }) + for _, txt in ipairs(stats._fx) do + D:Add({ style = "text", text = txt }) + end + end + end + + local sources = {} + for _, pair in ipairs({ { "units", Codex.V().units }, { "objects", Codex.V().objects } }) do + for id, ent in pairs(pair[2]) do + local chance, n, k = Codex.DropChance(ent, itemID, false) + if chance then + sources[#sources + 1] = { kind = pair[1], id = id, ent = ent, chance = chance, n = n, k = k } + end + end + end + table.sort(sources, function(a, b) + if a.chance ~= b.chance then return a.chance > b.chance end + return a.k > b.k + end) + local value = ItemValueOf(itemID) + if value and value > 0 then + local ranked = {} + for _, src in ipairs(sources) do + local ttk = src.kind == "units" and UnitTTK(src.ent) or nil + if ttk then + ranked[#ranked + 1] = { src = src, ttk = ttk, gph = src.chance * value / ttk * 3600 } + end + end + table.sort(ranked, function(a, b) return a.gph > b.gph end) + if #ranked > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_BESTSRC }) + for i = 1, math.min(3, #ranked) do + local r = ranked[i] + EntityLink(r.src.kind, r.src.id, r.src.ent, string.format(L.CODEX_BESTSRC_ROW, FormatMoney(r.gph), r.ttk)) + end + local top = ranked[1].src + D:Add({ style = "link", text = L.CODEX_MAP_SHOW, icon = MAP_ICON, + onClick = function() Codex.Map:Show(Codex.CollectPoints({ kind = top.kind, id = top.id }), UnitTitle(top.ent, top.id, top.kind)) end }) + end + end + if #sources > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_DROPS }) + for i, s in ipairs(sources) do + if i > 40 then break end + EntityLink(s.kind, s.id, s.ent, string.format(L.CODEX_DROP_CHANCE, FormatChance(s.chance), s.n, s.k)) + end + local merged = {} + for _, s in ipairs(sources) do + Codex.AddCells(merged, s.ent.cells) + end + if next(merged) then + D:Add({ style = "heading", text = L.CODEX_SEC_SPOTS }) + SpotRows(merged, 6) + MapLink({ kind = "items", id = itemID }, Codex:ItemName(itemID) or ("#" .. itemID)) + end + end + + -- Haendler laut eigenen und geteilten Beobachtungen (mit allen Preisen) + local liveVendors = {} + for vid, vent in pairs(Codex.V().units) do + local w = vent.wa and vent.wa[itemID] + if w then liveVendors[#liveVendors + 1] = { id = vid, ent = vent, w = w } end + end + for _, v in ipairs(liveVendors) do + local low + for price in pairs(v.w.pr or {}) do + if not low or price < low then low = price end + end + v.low = low or 0 + end + table.sort(liveVendors, function(a, b) + if a.low ~= b.low then return a.low < b.low end + return a.id < b.id + end) + local liveVendorSet = {} + if #liveVendors > 0 then + D:Add({ style = "heading", text = L.CODEX_SEC_SOLDBY_LIVE }) + for i, v in ipairs(liveVendors) do + liveVendorSet[v.id] = true + if i <= 30 then + local text = PriceText(v.w.pr, v.w.ec) + if i == 1 and #liveVendors > 1 then text = "|cff6fd66f" .. L.CODEX_CHEAPEST .. "|r " .. (text or "") end + EntityLink("units", v.id, v.ent, text) + end + end + end + + -- Quellen laut Vorlage (Vanilla): nur das, was wir selbst noch nicht gesehen haben + local it = SeedOK() and Codex.Seed.Item(itemID) or nil + local itFromStart = false + if not it and Codex.Forever and Codex.Forever.Item then + it = Codex.Forever.Item(itemID) + itFromStart = it ~= nil + end + if it then + local liveSet = {} + for _, src in ipairs(sources) do liveSet[src.kind .. src.id] = true end + local rows = {} + for _, def in ipairs({ { "units", it.u, 25 }, { "objects", it.o, 8 } }) do + local n = 0 + for _, src in ipairs(def[2]) do + if not liveSet[def[1] .. src.id] and n < def[3] then + n = n + 1 + rows[#rows + 1] = { kind = def[1], id = src.id, chance = src.chance } + end + end + end + if #rows > 0 then + D:Add({ style = "heading", text = itFromStart and L.CODEX_SEC_SRC_START or L.CODEX_SEC_SRC_SEED }) + for _, r in ipairs(rows) do + EntityLink(r.kind, r.id, Codex.V()[r.kind][r.id], SeedPct(r.chance)) + end + end + if #it.v > 0 then + D:Add({ style = "heading", text = itFromStart and L.CODEX_SEC_SOLDBY_START or L.CODEX_SEC_SOLDBY }) + local shownV = 0 + for _, vid in ipairs(it.v) do + if not liveVendorSet[vid] then + shownV = shownV + 1 + if shownV > 20 then break end + EntityLink("units", vid, Codex.V().units[vid], nil) + end + end + end + if #sources == 0 and #Codex.CollectPoints({ kind = "items", id = itemID }) > 0 then + MapLink({ kind = "items", id = itemID }, Codex:ItemName(itemID) or ("#" .. itemID)) + end + end + + local rewardOf, itemFor = {}, {} + for qid, q in pairs(Codex.V().quests) do + local found = false + for _, r in ipairs(q.fixed or {}) do if r.id == itemID then found = true end end + for _, r in ipairs(q.choice or {}) do if r.id == itemID then found = true end end + if found then rewardOf[#rewardOf + 1] = qid end + if q.qi and q.qi[itemID] then itemFor[#itemFor + 1] = qid end + end + local startsQ = {} + if Codex.Catalog and Codex.Catalog.Reverse then + local rev = Codex.Catalog.Reverse() + for _, def in ipairs({ { rewardOf, rev.reward[itemID] }, { itemFor, rev.item[itemID] }, { startsQ, rev.src[itemID] } }) do + local have = {} + for _, qid in ipairs(def[1]) do have[qid] = true end + for _, qid in ipairs(def[2] or {}) do + if not have[qid] then + have[qid] = true + def[1][#def[1] + 1] = qid + end + end + end + end + for _, def in ipairs({ { rewardOf, L.CODEX_SEC_REWARDOF }, { itemFor, L.CODEX_SEC_QUESTITEM }, { startsQ, L.CODEX_SEC_STARTS } }) do + if #def[1] > 0 then + D:Add({ style = "heading", text = def[2] }) + for i, qid in ipairs(def[1]) do + if i > 30 then break end + QuestLink(qid, Codex.V().quests[qid]) + end + end + end + end + + function ShowDetail() + UpdateFavUI() + D:Reset() + if selected then + if kind == "quests" then ShowQuest(selected) + elseif kind == "items" then ShowItem(selected) + elseif kind == "xp" then ShowXP(selected) + elseif kind == "learn" then ShowLearn(selected) + elseif kind == "zones" then ShowZone(selected) + else ShowEntity(kind, selected) end + end + D:Finish() + detail:ScrollToTop() + end + + -- Neuzeichnen der Detailseite (Antworten des Servers auf Namensanfragen), Scrollstand bleibt erhalten + function Codex.RedrawDetail() + if not (f:IsShown() and selected) then return end + local sc = detail.scroll + local v = sc and sc.GetVerticalScroll and sc:GetVerticalScroll() or 0 + ShowDetail() + if v > 0 and sc and sc.SetVerticalScroll then sc:SetVerticalScroll(v) end + end + + ---------------- Liste ---------------- + local function FilterKey() + local parts = {} + for q in pairs(flt.q) do parts[#parts + 1] = "q" .. q end + table.sort(parts) + for _, k in ipairs({ "type", "sub", "slot", "src", "zone", "ilMin", "ilMax", "rlMin", "rlMax", "pMin", "pMax", "aMin", "aMax", "stat", "statMin", "statMax" }) do + if flt[k] ~= nil then parts[#parts + 1] = k .. "=" .. tostring(flt[k]) end + end + for i = 1, MAX_STAT_ROWS do + local r = flt.stats and flt.stats[i] + if r and r.key then + parts[#parts + 1] = string.format("s%d=%s:%s:%s:%s", i, r.key, tostring(r.min), tostring(r.max), + flt.ops and flt.ops[i] or "and") + end + end + return table.concat(parts, ",") + end + + -- Sortierwerte erst berechnen, wenn danach sortiert wird; fehlende Werte bleiben nil und stehen am Ende + local function Enrich(entries, mode) + local V = Codex.V() + if kind == "units" or kind == "objects" then + for _, e in ipairs(entries) do + local u = V[kind][e.id] + if mode == "ahkill" and kind == "units" then + local value = u and Codex.KillValue(u, true) + e.ahkill = value and value >= 0 and value or nil + elseif mode == "ttk" or mode == "gpm" or mode == "gpmah" or mode == "xpm" then + local ttk = kind == "units" and UnitTTK(u) or nil + e.ttk = ttk + if ttk then + if mode == "gpm" or mode == "gpmah" then + local value = Codex.KillValue(u, mode == "gpmah") + e[mode] = value and value >= 0 and (value / ttk * 60) or nil + elseif mode == "xpm" then + local xp = UnitXPAvg(u) + e.xpm = xp and (xp / ttk * 60) or nil + end + end + elseif mode == "data" then + e.data = u and ((u.k or 0) + (u.tt and 1 or 0)) or 0 + elseif mode == "lvl" then + local lv = u and u.l1 + if not lv and SeedOK() then + local ent = Codex.Seed.Entity(kind, e.id) + lv = ent and ent.l1 + end + e.lvl = lv + end + end + elseif kind == "quests" then + for _, e in ipairs(entries) do + local q = V.quests[e.id] + if mode == "lvl" then + e.lvl = q and q.lvl or nil + elseif mode == "xp" then + e.xp = q and q.xp or nil + elseif mode == "money" then + e.money = q and q.money or nil + elseif mode == "qtime" then + e.qtime = q and q.tm and q.tm.n and q.tm.n > 0 and (q.tm.sum / q.tm.n / 10) or nil + end + end + elseif kind == "items" then + if mode == "buy" then + local lowest = LowestBuyPrices() + for _, e in ipairs(entries) do e.buy = lowest[e.id] end + elseif mode == "flip" then + -- Gewinn je Stueck: Auktion (netto nach Gebuehr) minus Einkauf beim Haendler + local lowest = LowestBuyPrices() + for _, e in ipairs(entries) do + local info = Codex.AuctionInfo and Codex.AuctionInfo(e.id) + local buy = lowest[e.id] + e.flip = info and info.net and buy and (info.net - buy) or nil + end + elseif mode == "ah" then + for _, e in ipairs(entries) do + local v = Codex.AuctionProvider and Codex.AuctionPrice(e.id) + e.ah = v and v > 0 and v or nil + end + elseif mode == "gph" then + local best = {} + for _, u in pairs(V.units) do + local k = u.k or 0 + local ttk = k > 0 and UnitTTK(u) or nil + if ttk then + for id, d in pairs(u.d or {}) do + local p = ItemValueOf(id) + if p and p > 0 then + local g = (d.q or d.n or 0) / k * p / ttk * 3600 + if g > (best[id] or 0) then best[id] = g end + end + end + end + end + for _, e in ipairs(entries) do e.gph = best[e.id] end + end + end + -- Sortierwert in der Zeile anzeigen + local fmt = SORT_FORMAT[mode] + local metric = SORT_METRIC[mode] + for _, e in ipairs(entries) do + e.baseSub = e.baseSub or e.sub + local v = metric and e[metric] + if fmt and v and v >= 0 and not (mode == "gold" or mode == "price") then + local text + if fmt == "money" then text = FormatMoney(v) + elseif fmt == "secs" then text = string.format("%.1f s", v) + else text = string.format("%.0f", v) end + e.sub = (e.baseSub ~= "" and (e.baseSub .. " | ") or "") .. (L["CODEX_SORTBY_" .. mode] or mode) .. ": " .. text + else + e.sub = e.baseSub + end + end + end + + local function Missing(v) + return v == nil or v < 0 or v >= 1e9 + end + + local function SortedBase() + local mode = CurrentSort() + local seed = SeedOn() + local role = roleSel[kind] + local reverse = sortRev[kind] == true + -- unveraendert (zum Beispiel beim Anklicken einer Zeile): die gemerkte Liste wiederverwenden + local key = table.concat({ kind, search, mode, tostring(reverse), tostring(farmOn and kind == "units"), tostring(seed), tostring(role), tostring(chainSel), tostring(statusSel), tostring(zoneSel), tostring(learnSel), tostring(favOnly[kind]), FilterKey(), dataVersion }, "\1") + -- Quest-Status aendert sich im Spiel laufend: mit Statusfilter immer neu aufbauen + if memo.key == key and mode ~= "dist" and not statusSel then + return memo.list + end + local entries = BuildEntries(kind, search, flt, { seed = seed, role = role, chain = chainSel, status = statusSel, zoneSel = zoneSel, + class = kind == "learn" and EnsureLearnSel() or nil, fav = favOnly[kind] }) + local metric = SORT_METRIC[mode] + if mode == "dist" then + local Seed = Codex.Seed + local loc = Util.GetPlayerLocation() -- einmal lesen, nicht je Eintrag + for _, e in ipairs(entries) do + if kind == "quests" then + local q = Codex.V().quests[e.id] + local g = q and q.give + local d + if g and g.m and g.x and g.y and loc and loc.mapID == g.m and loc.x and loc.y then + d = math.sqrt((g.x - loc.x) ^ 2 + (g.y - loc.y) ^ 2) + end + e.dist = d or 1e9 + else + local live = Codex.V()[kind][e.id] + local d1 = live and live.cells and Seed.Distance(live.cells, loc) + local d2 = SeedOK() and Seed.Distance(Seed.Cells(kind, e.id), loc) + e.dist = math.min(d1 or 1e9, d2 or 1e9) + end + end + end + if farmOn and kind == "units" then + local loc = Util.GetPlayerLocation() + local zone = loc and loc.mapID and CachedMapName(loc.mapID) + zone = zone and zone:lower() or nil + local pl = UnitLevel and UnitLevel("player") or 1 + Enrich(entries, "gpm") + local kept = {} + for _, e in ipairs(entries) do + if e.gpm and e.l1 and (e.l2 or e.l1) >= pl - 5 and e.l1 <= pl + 3 and (not zone or e.zone == zone) then + kept[#kept + 1] = e + end + end + entries = kept + end + Enrich(entries, mode) + local asc = SORT_ASC[mode] == true + if reverse then asc = not asc end + table.sort(entries, function(a, b) + local va, vb + if mode == "zone" then + local za, zb = a.zone ~= "" and a.zone or "\255", b.zone ~= "" and b.zone or "\255" + if za ~= zb then + if asc then return za < zb end + return za > zb + end + if a.name ~= b.name then return a.name < b.name end + return a.id < b.id + end + if mode == "recent" then + va, vb = a.recent, b.recent + elseif mode == "dist" then + va, vb = a.dist, b.dist + local ma, mb = Missing(va), Missing(vb) + if ma ~= mb then return mb end + if ma then va, vb = 0, 0 end + elseif metric then + va, vb = a[metric], b[metric] + local ma, mb = Missing(va), Missing(vb) + if ma ~= mb then return mb end -- fehlende Werte immer ans Ende + if ma then va, vb = 0, 0 end + end + if va ~= nil and va ~= vb then + if asc then return va < vb end + return va > vb + end + if a.name ~= b.name then + if mode == "name" then + if asc then return a.name < b.name end + return a.name > b.name + end + return a.name < b.name + end + return a.id < b.id + end) + memo.key, memo.list = key, entries + return entries + end + + -- Sortierung nach Gebiet: Kopfzeilen mit Zaehlern, einklappbar. Zaehler immer frisch (Questlog aendert sich). + local function SortedEntries() + local entries = SortedBase() + if kind ~= "quests" or CurrentSort() ~= "zone" then return entries end + local L = FW.L + local out, i = {}, 1 + while i <= #entries do + local zone = entries[i].zone or "" + local j, open, active, done = i, 0, 0, 0 + while j <= #entries and (entries[j].zone or "") == zone do + local st = Codex.QuestStatus(entries[j].id) + if st == "done" then done = done + 1 elseif st == "active" then active = active + 1 else open = open + 1 end + j = j + 1 + end + local count = j - i + local name = entries[i].zoneName or L.CODEX_ZONE_UNKNOWN + local closed = collapsed[zone] == true + out[#out + 1] = { header = zone, id = "zone:" .. zone, title = string.format("%s (%d)", name, count), + sub = string.format(L.CODEX_GROUP_ROW, open, active, done), icon = closed and ICON.plus or ICON.minus, + name = "", zone = zone } + if not closed then + for k = i, j - 1 do out[#out + 1] = entries[k] end + end + i = j + end + return out + end + + -- Kreatur-Bilder in der Liste: 2D-Portrait aus der gespeicherten Display-ID. + -- Kreaturen ohne ID zeigen das Symbol; ein einziges unsichtbares Modell holt die IDs + -- der sichtbaren Zeilen nach und zwar eine nach der anderen. + local resolver = CreateFrame("PlayerModel", nil, f) + resolver:SetSize(8, 8) + resolver:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0) + resolver:SetAlpha(0) + local resolverBusy, resolverTries = false, {} + local UpdateRowIcons + + local function ReadDisplayID(model) + local ok, id = pcall(function() return model.GetDisplayInfo and model:GetDisplayInfo() end) + if ok and type(id) == "number" and id > 0 then return id end + return nil + end + + local function ResolveNext() + -- Ohne 2D-Portrait in der Liste (Octo) braucht niemand mehr die Display-IDs der Zeilen; + -- unbekannte Kreaturen ueber ein Modell zu laden waere ausserdem riskant (siehe SAFE_MODEL_TYPE). + if true then return end + if resolverBusy then return end + local sf = listScroll.scroll + local top = sf:GetVerticalScroll() or 0 + local bottom = top + (sf:GetHeight() or 0) + local pick + for i, row in ipairs(listRows) do + local npc = row.unitID + if npc and row:IsShown() and not Codex:GetDisplayID(npc) and not resolverTries[npc] then + local y = (i - 1) * (ROW_H + ROW_GAP) + if y + ROW_H >= top and y <= bottom then pick = npc break end + end + end + if not pick then return end + resolverTries[pick] = true + resolverBusy = true + local function Finish() + local d = ReadDisplayID(resolver) + if d then + Codex.dispStats.read = Codex.dispStats.read + 1 + if Codex:SetDisplayID(pick, d) then UpdateRowIcons() end + else + Codex.dispStats.fail = Codex.dispStats.fail + 1 + end + resolverBusy = false + C_Timer.After(0.05, ResolveNext) + end + Codex.EnsureCreature(pick, function() + local cd = Codex.CacheDisplayID(pick) + if cd then + Codex.dispStats.read = Codex.dispStats.read + 1 + if Codex:SetDisplayID(pick, cd) then UpdateRowIcons() end + resolverBusy = false + C_Timer.After(0.05, ResolveNext) + return + end + pcall(function() + resolver:ClearModel() + resolver:SetCreature(pick) + end) + C_Timer.After(0.35, Finish) + end) + end + + -- Octo hat kein SetPortraitTextureFromCreatureDisplayID und ein 2D-Bild geht nur fuer + -- Einheiten-Token. Mehrere 3D-Modelle in der Liste fuehrten zu Abstuerzen, daher bleibt + -- die Liste bei den Symbolen; das 3D-Modell gibt es nur im Detailfenster. + function UpdateRowIcons() + for _, row in ipairs(listRows) do + if row.fwModel then row.fwModel:Hide() end + row.icon:SetAlpha(1) + end + end + + local function UpdateRowModels() + UpdateRowIcons() + ResolveNext() + end + f.UpdateRowModels = UpdateRowModels + if listScroll.scroll.HookScript then + listScroll.scroll:HookScript("OnVerticalScroll", function() UpdateRowModels() end) + end + + function RefreshList() + if kind == "items" or kind == "units" or kind == "objects" then + local _, ids = ItemIndex() + Codex:LoadItemInfo(ids) + if kind == "items" then Codex:CaptureStats(ids) end + end + local entries = SortedEntries() + -- Namen der Katalog-Ziele beim Server nachfragen (je Aufruf wenige, jede ID nur einmal) + if (kind == "units" or kind == "objects") and Codex.Catalog and Codex.Catalog.Reverse then + local asked = 0 + for _, e in ipairs(entries) do + if asked >= 12 then break end + if e.title:sub(1, 1) == "#" and not srvAsked[(kind == "units" and "u" or "o") .. e.id] then + ServerInfo(kind, e.id, true) + asked = asked + 1 + end + end + if asked > 0 and _G.C_Timer then + _G.C_Timer.After(1.6, function() catEnt = {} dataVersion = dataVersion + 1 if f:IsShown() and RefreshList then RefreshList() end end) + end + end + local total = #entries + local headers = 0 + if kind == "quests" and CurrentSort() == "zone" then + for _, e in ipairs(entries) do + if e.header then headers = headers + 1 end + end + end + local shown = math.min(total, MaxRows()) + for i = 1, shown do + local e = entries[i] + local row = listRows[i] + if not row then + row = UI.CreatePanel(listScroll.child, "card", "bronze") + row:SetHeight(ROW_H) + row:EnableMouse(true) + row.icon = row:CreateTexture(nil, "ARTWORK") + row.icon:SetSize(30, 30) + row.icon:SetPoint("LEFT", row, "LEFT", 7, 0) + row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) + row.title = UI.CreateLabel(row, "", { size = 12 }) + row.title:SetPoint("TOPLEFT", row, "TOPLEFT", 46, -7) + row.title:SetPoint("TOPRIGHT", row, "TOPRIGHT", -8, -7) + row.title:SetWordWrap(false) + row.sub = UI.CreateLabel(row, "", { size = 10, color = "textDim" }) + row.sub:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 46, 7) + row.sub:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -8, 7) + row.sub:SetWordWrap(false) + -- Quest-Status rechts: Haken (erledigt) oder Sprint-Symbol (in Arbeit) + row.mark = row:CreateTexture(nil, "OVERLAY") + row.mark:SetSize(18, 18) + row.mark:SetPoint("RIGHT", row, "RIGHT", -8, 0) + row.mark:Hide() + row.fav = row:CreateTexture(nil, "OVERLAY") + row.fav:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcon_1") + row.fav:SetSize(14, 14) + row.fav:Hide() + row:SetScript("OnMouseUp", function(self) + if self.headerKey then + collapsed[self.headerKey] = not collapsed[self.headerKey] + RefreshList() + return + end + selected = self.entryID + RefreshList() + ShowDetail() + if nameCtl then nameCtl.Update() end + end) + row:SetScript("OnEnter", function(self) + UI.SetBorderColor(self, "gold") + if self.itemID and GameTooltip then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + local ok = pcall(GameTooltip.SetItemByID, GameTooltip, self.itemID) + if not ok then pcall(GameTooltip.SetHyperlink, GameTooltip, "item:" .. self.itemID) end + GameTooltip:Show() + end + end) + row:SetScript("OnLeave", function(self) + UI.SetBorderColor(self, (self.entryID == selected or self.headerKey) and "gold" or "bronze") + if GameTooltip then GameTooltip:Hide() end + end) + listRows[i] = row + end + row.entryID = e.id + row.headerKey = e.header + row.itemID = e.itemID + row.unitID = e.unitID + row.dispShown = nil + row:ClearAllPoints() + local y = (i - 1) * (ROW_H + ROW_GAP) + row:SetPoint("TOPLEFT", listScroll.child, "TOPLEFT", 0, -y) + row:SetPoint("TOPRIGHT", listScroll.child, "TOPRIGHT", 0, -y) + row.title:SetText(e.header and ("|cffffd100" .. e.title .. "|r") or e.title) + row.sub:SetText(e.sub or "") + local mark = (kind == "quests" and not e.header) and STATUS_MARK[Codex.QuestStatus(e.id) or ""] or nil + row.markState = mark + local isFav = (not e.header) and Codex.FavSupported(kind) and Codex.IsFav(kind, e.id) + row.fav:ClearAllPoints() + row.fav:SetPoint("RIGHT", row, "RIGHT", mark and -30 or -8, 0) + row.fav:SetShown(isFav and true or false) + local rightGap = (mark and 32 or 8) + (isFav and 18 or 0) + row.title:ClearAllPoints() + row.title:SetPoint("TOPLEFT", row, "TOPLEFT", 46, -7) + row.title:SetPoint("TOPRIGHT", row, "TOPRIGHT", -rightGap, -7) + row.sub:ClearAllPoints() + row.sub:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 46, 7) + row.sub:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -rightGap, 7) + if mark then + row.mark:SetTexture(mark) + row.mark:SetTexCoord(0.08, 0.92, 0.08, 0.92) + row.mark:Show() + else + row.mark:Hide() + end + row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) + if e.itemID then + row.icon:SetTexture(ICON.items) + local q = Codex.QualityOf(e.itemID) + if q then row.title:SetText(Colored(e.title, q)) end + Util.RequestItem(e.itemID, function(info) + if row.entryID == e.itemID and info then + Codex.RememberQuality(e.itemID, info.quality) + row.icon:SetTexture(info.icon) + row.title:SetText(Colored(info.name, info.quality)) + end + end) + else + row.icon:SetTexture(e.icon) + row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) + end + UI.SetBorderColor(row, (e.id == selected or e.header) and "gold" or "bronze") + if e.header then row.icon:SetTexCoord(0, 1, 0, 1) end + row:Show() + end + for i = shown + 1, #listRows do + listRows[i]:Hide() + end + listScroll:SetContentHeight(shown * (ROW_H + ROW_GAP)) + UpdateRowModels() + + local q, u, o = Codex:Counts() + if total == 0 then + listEmpty:SetText(kind == "learn" and #Codex.LearnClasses() == 0 and L.CODEX_LEARN_EMPTY + or (q + u + o) == 0 and L.CODEX_EMPTY or L.CODEX_NO_MATCH) + listEmpty:Show() + countLabel:SetText("") + else + listEmpty:Hide() + local text = total > shown and string.format(L.CODEX_COUNT_MORE, total - headers, shown - headers) or string.format(L.CODEX_COUNT, total - headers) + local pending = Codex.runtime.pendingInfo or 0 + if pending > 0 and kind == "items" then + text = text .. " | " .. string.format(L.CODEX_LOADING_ITEMS, pending) + end + countLabel:SetText(text) + end + end + + function Refresh() + LayoutKinds() + for id, b in pairs(kindButtons) do + b:SetStyle(id == kind and "primary" or "default") + end + if #history > 0 then backButton:Show() else backButton:Hide() end + sortDD:SetValue(CurrentSort()) + local asc = SORT_ASC[CurrentSort()] == true + if sortRev[kind] then asc = not asc end + dirButton.arrow:SetTexCoord(0, 1, asc and 0 or 1, asc and 1 or 0) + Layout() + UpdateFilterUI() + RefreshList() + ShowDetail() + if nameCtl then nameCtl.Update() end + end + + function Go(newKind, id) + if selected ~= nil and (kind ~= newKind or selected ~= id) then + history[#history + 1] = { kind = kind, id = selected } + if #history > 30 then table.remove(history, 1) end + end + kind, selected = newKind, id + edit:SetText("") + edit:ClearFocus() + Refresh() + end + + f.Refresh = function() + dirty = true + dataVersion = dataVersion + 1 + Refresh() + end + f.Go = Go + -- fuer Tests + f.Entries = SortedEntries + f.SetFilter = function(t) + flt = t or {} + flt.q = flt.q or {} + Refresh() + end + f.SetSort = function(mode, reverse) + sortBy[kind] = mode + sortRev[kind] = reverse == true + Refresh() + end + f.ToggleZone = function(zone) collapsed[zone] = not collapsed[zone]; Refresh() end + f.ToggleRoute = function() routeOpen = not routeOpen; RouteSync(); Layout(); return routeOpen end + f.RouteLevels = function() return routeLvl, routeOpen end + f.SetRouteRange = function(on) + if on then routeLvl.below, routeLvl.above = 3, 3 else routeLvl.below, routeLvl.above = nil, nil end + RouteSync() + end + f.SetFarm = function(on) + farmOn = on and true or false + if farmOn then roleSel.units, sortBy.units, sortRev.units = "combat", "gpm", false end + Refresh() + end + f.Back = function() + local prev = table.remove(history) + if prev then + kind, selected = prev.kind, prev.id + Refresh() + end + return prev ~= nil + end + f.HistoryCount = function() return #history end + f.SetLearnClass = function(token) learnSel = token; selected = nil; dataVersion = dataVersion + 1; Refresh() end + f.SetFavOnly = function(on) favOnly[kind] = on and true or false; dataVersion = dataVersion + 1; Refresh() end + f.Kind = function() return kind end + f.SetRole = function(role) + roleSel[kind] = role + Refresh() + end + f.FilterText = function() return StatPreview(flt) end + f.SetStatus = function(status) + statusSel = status + Refresh() + end + f.SetChain = function(chain) + chainSel = chain + Refresh() + end + f.SetSearch = function(text) + search = text or "" + Refresh() + end + -- Text der angezeigten Detail-Zeilen (links | rechts), fuer Tests + f.DetailText = function() + local t = {} + for i = 1, D.used do + t[#t + 1] = (detailRows[i].left:GetText() or "") .. "|" .. (detailRows[i].right:GetText() or "") + end + return table.concat(t, "\n") + end + + FW:On("CODEX_CHANGED", function() + dirty = true + dataVersion = dataVersion + 1 + if f:IsShown() then + RefreshList() + end + end, f) + FW:On("CODEX_ITEMS_LOADED", function() + dataVersion = dataVersion + 1 + if f:IsShown() and (kind == "items" or kind == "units" or kind == "objects") then + RefreshList() + if (kind == "units" or kind == "objects") and selected and detailMissing then + ShowDetail() + end + end + end, f) + + return f +end + +local built +UI:RegisterTab("codex", { + label = function() + return FW.L.CODEX_TAB + end, + order = 30, + build = function(content) + built = Build(content) + Codex.ui = built + return built + end, + onShow = function(f) + f.Refresh() + end, +}) + +------------------------------------------------------------------------ +-- /fwcodex near : naechste Haendler, Flugmeister ... auf dieser Karte (Vorlage) +------------------------------------------------------------------------ + +local NEAR_WORDS = { + { "vendor", "haendler", "händler", "vendor", "shop" }, { "repair", "repair", "reparatur", "rep" }, + { "flight", "flug", "flight", "fm" }, { "innkeeper", "gast", "inn", "wirt" }, + { "stablemaster", "stall", "stable" }, { "banker", "bank" }, { "auctioneer", "auktion", "auction", "ah" }, + { "mailbox", "post", "mail", "brief" }, { "spirithealer", "geist", "spirit", "heiler" }, +} + +function Codex.Near(word) + local L = FW.L + word = (word or ""):lower() + local role + for _, def in ipairs(NEAR_WORDS) do + for i = 2, #def do + if word == def[i] then role = def[1] end + end + end + if not role then + FW:Print(L.CODEX_NEAR_HELP) + return + end + local list = Codex.Seed.Available() and Codex.Seed.Nearest(role, 5) or {} + if #list == 0 then + FW:Print(L.CODEX_NEAR_NONE) + return + end + FW:Print(string.format(L.CODEX_NEAR_HEAD, L["CODEX_ROLE_" .. role] or role)) + local points = {} + for _, e in ipairs(list) do + local name = (Codex.NameOf(Codex.V()[e.kind][e.id])) or Codex.Seed.Name(e.kind, e.id) or ("#" .. e.id) + FW:Print(string.format(L.CODEX_NEAR_ROW, name, e.x * 100, e.y * 100)) + points[#points + 1] = { m = e.m, x = e.x, y = e.y, n = 4, pin = true, name = name } + end + if Codex.Map and Codex.Map.Show then + Codex.Map:Show(points, L["CODEX_ROLE_" .. role] or role) + end +end + +------------------------------------------------------------------------ +-- Befehl +------------------------------------------------------------------------ + +SLASH_FREEWOODCODEX1 = "/fwcodex" +SlashCmdList["FREEWOODCODEX"] = function(msg) + msg = (msg or ""):lower():match("^%s*(.-)%s*$") + if msg == "test" then + Codex:RunTest() + elseif msg == "share log" then + if Codex.Sync then Codex.Sync:SetLog(not Codex.Sync.state.log) end + elseif msg == "share on" or msg == "share off" then + if Codex.Sync then + Codex.Sync:SetEnabled(msg == "share on") + Codex.Sync:Debug() + end + elseif msg == "enc" then + if Codex.Sync then Codex.Sync:EncTest() end + elseif msg == "share" then + if Codex.Sync then Codex.Sync:Debug() end + elseif msg == "time" then + if Codex.Time then Codex.Time:Debug() end + elseif msg == "icons" then + local st = Codex.dispStats + local n = 0 + for _ in pairs(Codex.db.disp or {}) do n = n + 1 end + FW:Print(string.format("Kreatur-Bilder: %d Display-IDs gespeichert, gelesen %d, nicht lesbar %d, in der Liste gesetzt %d", n, st.read, st.fail, st.shown)) + elseif msg == "seed" then + if Codex.Seed and Codex.Seed.Available() then + FW:Print(string.format(FW.L.CODEX_SEED_STATUS, Codex.Seed.Count())) + else + FW:Print(FW.L.CODEX_SEED_MISSING) + end + elseif msg == "roles" then + Codex.Roles:Debug() + elseif msg == "trainers" then + -- Diagnose Lernplan: alle erfassten Lehrer mit Titel, Klasse und Anzahl Zauber + local n = 0 + for id, u in pairs(Codex.V().units) do + if u.ro and ((u.ro.classtrainer or 0) > 0 or (u.ro.proftrainer or 0) > 0) then + n = n + 1 + local cnt = 0 + for _ in pairs(u.tr or {}) do cnt = cnt + 1 end + FW:Print(string.format("#%d %s | Titel: %s | Klasse: %s (Titel: %s, Spieler: %s) | Zauber: %d | Rolle: %s", id, tostring(u.n), tostring(u.ti), + tostring(Codex.ClassOfTrainer(u)), tostring(Codex.ClassOfTitle(u.ti)), tostring(u.trc), cnt, (u.ro.classtrainer or 0) > 0 and "Klasse" or "Beruf")) + end + end + FW:Print(n .. " Lehrer erfasst.") + elseif msg:find("^weapon") then + local id = tonumber(msg:match("item:(%d+)")) or tonumber(msg:match("(%d+)")) + if id then Codex.WeaponDebug(id) else FW:Print("/fwcodex weapon ") end + elseif msg:find("^itemload") then + if msg:find("stop") then Codex.ItemLoadStop() + elseif msg:find("status") then Codex.ItemLoadStatus() + else Codex.ItemLoadStart(Codex.AllItemIds()) end + elseif msg:find("^tipscan") then + if msg:find("stop") then Codex.TipScanStop() else local _, ids = ItemIndex() Codex.TipScan(ids) end + elseif msg:find("^near") then + Codex.Near(msg:match("^near%s*(.-)$")) + elseif msg == "names" then + if Codex.Names then Codex.Names:Debug() end + elseif msg == "map" then + Codex.Map:Debug() + elseif msg == "map test" then + Codex.Map:Test() + elseif msg == "map square" then + Codex.Map:ToggleSquare() + else + UI:Toggle("codex") + end +end + +------------------------------------------------------------------------ +-- Einstellungen: Anzahl der Listenzeilen in der Datenbank +------------------------------------------------------------------------ + +if UI.RegisterSettingsSection then + UI:RegisterSettingsSection("codex-list", { + order = 104, + height = 110, + build = function(parent) + local L = FW.L + local f, stack = UI.CreateSection(parent, L.CODEX_LISTMAX_HEADER) + stack:Add(UI.CreateLabel(f, L.CODEX_LISTMAX_NOTE, { size = 11, color = "textDim", justifyV = "TOP" }), { fit = true, gap = 8 }) + local val = UI.CreateLabel(f, "", { size = 12 }) + stack:Add(val, { fit = true, gap = 6 }) + local slider = UI.CreateSlider(f, 240, { + min = 100, max = 6000, step = 100, + get = function() return MaxRows() end, + set = function(v) + Codex.db.settings.listMax = v + val:SetText(string.format(L.CODEX_LISTMAX_VALUE, v)) + end, + }) + slider.onText = function(v) val:SetText(string.format(L.CODEX_LISTMAX_VALUE, v)) end + stack:Add(slider, { height = 20, gap = 4 }) + stack:Layout() + f.slider = slider + return f + end, + refresh = function(frame) frame.slider:Refresh() end, + }) +end diff --git a/CodexWdbChain.lua b/CodexWdbChain.lua new file mode 100644 index 0000000..212228a --- /dev/null +++ b/CodexWdbChain.lua @@ -0,0 +1,1406 @@ +-- Erzeugt aus WDB\questcache.wdb (4205 Quests). Nicht von Hand aendern. +local ADDON, NS = ... +local Codex = NS and NS.Codex +if not Codex then return end +Codex.WdbNext = { +[5]=93, [10]=110, [12]=13, [13]=14, [15]=21, [20]=19, [26]=29, [27]=28, +[28]=30, [29]=272, [30]=31, [35]=37, [36]=38, [37]=45, [39]=59, [40]=35, +[45]=71, [48]=49, [49]=50, [50]=51, [51]=53, [56]=57, [57]=58, [60]=61, +[62]=76, [63]=100, [65]=132, [66]=67, [67]=68, [68]=69, [69]=70, [70]=72, +[71]=39, [72]=74, [74]=75, [75]=78, [76]=60154, [78]=79, [79]=80, [80]=97, +[84]=87, [85]=86, [86]=84, [93]=240, [94]=248, [95]=230, [97]=98, [100]=96, +[106]=111, [107]=112, [110]=113, [111]=107, [118]=119, [120]=121, [124]=126, [125]=89, +[129]=130, [130]=131, [132]=135, [133]=134, [134]=160, [135]=141, [136]=138, [138]=139, +[139]=140, [141]=142, [143]=144, [145]=146, [148]=149, [149]=154, [154]=157, [155]=166, +[156]=159, [157]=158, [158]=156, [159]=133, [160]=251, [161]=274, [173]=221, [174]=175, +[175]=177, [177]=181, [182]=218, [185]=186, [186]=187, [187]=188, [190]=191, [191]=192, +[192]=193, [194]=195, [195]=196, [196]=197, [199]=161, [200]=328, [207]=205, [210]=627, +[215]=200, [218]=282, [221]=222, [222]=223, [225]=227, [227]=228, [228]=229, [229]=231, +[230]=262, [232]=238, [233]=234, [238]=243, [239]=11, [243]=379, [244]=246, [250]=199, +[257]=258, [261]=1052, [262]=265, [265]=266, [266]=453, [268]=323, [269]=270, [270]=321, +[271]=531, [272]=5061, [273]=454, [274]=278, [276]=277, [277]=275, [278]=280, [279]=281, +[280]=283, [281]=284, [282]=420, [284]=285, [285]=286, [287]=291, [288]=289, [289]=290, +[290]=292, [292]=293, [294]=295, [295]=296, [298]=301, [301]=302, [302]=273, [305]=306, +[310]=311, [317]=318, [318]=319, [319]=320, [321]=324, [322]=325, [323]=269, [324]=322, +[325]=55, [328]=329, [329]=330, [330]=331, [335]=336, [337]=538, [343]=344, [344]=345, +[345]=347, [347]=346, [350]=2745, [351]=648, [355]=408, [357]=366, [359]=360, [365]=407, +[366]=409, [367]=368, [368]=369, [369]=492, [370]=371, [371]=372, [373]=389, [380]=381, +[381]=382, [382]=383, [389]=391, [391]=392, [392]=393, [393]=350, [394]=395, [395]=396, +[401]=252, [405]=357, [409]=411, [413]=414, [415]=413, [419]=417, [421]=422, [422]=423, +[423]=424, [424]=99, [427]=370, [428]=429, [429]=430, [434]=394, [435]=449, [436]=297, +[437]=438, [438]=439, [439]=443, [440]=441, [441]=530, [443]=444, [446]=448, [447]=450, +[448]=442, [449]=3221, [450]=451, [453]=268, [458]=459, [460]=461, [461]=491, [463]=276, +[464]=465, [465]=474, [467]=466, [468]=455, [473]=464, [475]=476, [476]=483, [477]=478, +[478]=481, [479]=480, [481]=482, [482]=479, [483]=486, [484]=471, [485]=836, [495]=518, +[496]=499, [500]=504, [501]=502, [503]=506, [506]=507, [507]=508, [509]=513, [510]=512, +[511]=514, [513]=515, [514]=525, [515]=517, [517]=524, [518]=519, [519]=520, [520]=521, +[522]=523, [525]=537, [526]=322, [527]=528, [528]=529, [529]=532, [532]=539, [533]=503, +[536]=559, [538]=540, [539]=541, [540]=542, [541]=550, [544]=545, [551]=554, [552]=553, +[558]=171, [559]=560, [560]=561, [561]=562, [562]=563, [568]=569, [570]=572, [571]=573, +[572]=571, [574]=202, [577]=628, [578]=601, [581]=582, [588]=589, [589]=591, [594]=630, +[595]=597, [597]=599, [599]=604, [601]=602, [603]=610, [604]=608, [605]=600, [606]=607, +[607]=609, [610]=611, [615]=618, [616]=578, [624]=625, [625]=626, [627]=622, [631]=632, +[632]=633, [633]=634, [638]=639, [639]=640, [641]=643, [642]=651, [643]=644, [644]=645, +[645]=646, [649]=650, [650]=77, [651]=652, [653]=687, [654]=864, [655]=672, [658]=657, +[659]=658, [660]=661, [665]=666, [666]=668, [668]=669, [669]=670, [672]=674, [674]=675, +[675]=701, [676]=677, [677]=678, [678]=679, [686]=689, [687]=692, [688]=687, [694]=695, +[695]=696, [696]=697, [698]=699, [699]=1422, [701]=702, [707]=738, [710]=711, [711]=712, +[713]=714, [718]=733, [720]=721, [721]=722, [722]=723, [723]=724, [725]=726, [726]=762, +[727]=735, [728]=736, [730]=729, [731]=741, [732]=717, [734]=777, [735]=737, [736]=737, +[738]=739, [739]=704, [741]=942, [749]=751, [750]=780, [752]=753, [753]=755, [755]=757, +[757]=763, [809]=924, [819]=821, [821]=822, [828]=827, [829]=809, [830]=831, [834]=835, +[838]=964, [840]=842, [843]=846, [844]=845, [845]=903, [846]=849, [851]=852, [860]=844, +[867]=875, [869]=3281, [870]=877, [874]=873, [875]=876, [877]=880, [879]=906, [881]=905, +[882]=907, [886]=870, [887]=890, [890]=892, [892]=888, [894]=900, [900]=901, [901]=902, +[903]=881, [905]=3261, [907]=913, [913]=874, [915]=925, [916]=917, [918]=922, [920]=921, +[921]=928, [922]=923, [923]=2498, [925]=5502, [928]=929, [929]=933, [933]=7383, [936]=3761, +[939]=4441, [940]=952, [942]=943, [944]=949, [947]=948, [948]=944, [949]=950, [954]=955, +[955]=956, [956]=957, [964]=5514, [965]=966, [966]=967, [967]=970, [969]=975, [973]=1140, +[974]=980, [977]=5163, [978]=979, [980]=4842, [983]=1001, [984]=985, [991]=1023, [992]=82, +[994]=990, [995]=990, [1000]=1123, [1001]=1002, [1002]=1003, [1004]=1123, [1015]=6761, [1016]=1017, +[1018]=1123, [1019]=6761, [1021]=1031, [1022]=1037, [1024]=1026, [1026]=1027, [1027]=1028, [1028]=1055, +[1029]=1030, [1030]=1045, [1036]=4621, [1037]=1038, [1038]=1039, [1039]=1040, [1040]=1041, [1041]=1042, +[1042]=1043, [1043]=1044, [1045]=1046, [1047]=6761, [1055]=1029, [1056]=1057, [1057]=1059, [1061]=1062, +[1064]=1065, [1065]=1066, [1070]=1085, [1072]=1073, [1073]=1074, [1075]=1076, [1076]=1077, [1082]=1081, +[1085]=1071, [1087]=1088, [1088]=1089, [1090]=1092, [1093]=1094, [1094]=1095, [1095]=1096, [1097]=353, +[1100]=1101, [1106]=1108, [1109]=1113, [1111]=1112, [1115]=1116, [1116]=1117, [1123]=1124, [1124]=1125, +[1125]=1126, [1126]=6844, [1130]=1131, [1132]=1133, [1140]=1167, [1143]=981, [1145]=1146, [1146]=1147, +[1148]=1184, [1149]=1150, [1150]=1151, [1151]=1152, [1152]=1154, [1154]=6627, [1159]=1160, [1160]=6628, +[1167]=1143, [1170]=1171, [1171]=1172, [1176]=1178, [1178]=1180, [1180]=1181, [1181]=1182, [1182]=1183, +[1183]=1186, [1186]=1187, [1187]=1188, [1188]=1189, [1190]=1194, [1195]=1196, [1196]=1197, [1198]=1200, +[1201]=1202, [1204]=1258, [1206]=1203, [1218]=1206, [1219]=1220, [1239]=1240, [1241]=1242, [1242]=1243, +[1243]=1244, [1244]=1245, [1245]=1246, [1246]=1447, [1247]=1248, [1248]=1249, [1250]=1264, [1251]=1321, +[1252]=1259, [1253]=1319, [1259]=1285, [1260]=1204, [1261]=1262, [1264]=1265, [1265]=1266, [1266]=1324, +[1274]=1241, [1285]=1286, [1286]=1287, [1288]=1289, [1289]=1390, [1301]=1302, [1319]=1320, [1321]=1322, +[1322]=1323, [1339]=1338, [1359]=1358, [1361]=1362, [1363]=1364, [1367]=1369, [1368]=1370, [1369]=1371, +[1370]=1373, [1372]=1383, [1373]=1374, [1374]=1380, [1375]=1381, [1382]=1384, [1383]=1388, [1384]=1370, +[1385]=1386, [1386]=1369, [1388]=1391, [1396]=1421, [1398]=1425, [1418]=1420, [1421]=1398, [1422]=1426, +[1424]=1429, [1426]=1427, [1427]=1428, [1429]=1444, [1431]=1432, [1433]=1435, [1437]=1465, [1438]=1439, +[1444]=1445, [1447]=1247, [1448]=1449, [1449]=1450, [1450]=1451, [1451]=1452, [1454]=1455, [1455]=1456, +[1456]=1457, [1458]=1459, [1459]=1466, [1465]=1438, [1466]=1467, [1469]=1475, [1472]=1476, [1473]=1471, +[1476]=1474, [1477]=1395, [1478]=1473, [1480]=1481, [1481]=1482, [1483]=1093, [1485]=1499, [1489]=1490, +[1490]=914, [1498]=1502, [1499]=794, [1501]=1504, [1502]=1503, [1505]=1498, [1506]=1501, [1507]=1508, +[1508]=1509, [1509]=1510, [1510]=1511, [1511]=1515, [1512]=1513, [1515]=1512, [1516]=1517, [1517]=1518, +[1519]=1520, [1520]=1521, [1522]=1524, [1523]=1524, [1524]=1525, [1525]=1526, [1526]=1527, [1528]=1530, +[1529]=1530, [1530]=1535, [1534]=220, [1535]=1536, [1536]=1534, [1579]=1580, [1638]=1639, [1639]=1640, +[1640]=1665, [1642]=1643, [1643]=1644, [1644]=1780, [1646]=1647, [1647]=1648, [1648]=1778, [1649]=1650, +[1651]=1652, [1652]=1653, [1653]=1654, [1654]=1806, [1666]=1667, [1678]=1680, [1679]=1678, [1680]=1681, +[1681]=1682, [1684]=1683, [1685]=1688, [1686]=1692, [1688]=1689, [1690]=1691, [1698]=1699, [1700]=1705, +[1702]=1701, [1703]=1710, [1704]=1708, [1712]=1713, [1716]=1738, [1717]=1716, [1718]=1719, [1738]=1739, +[1758]=1802, [1778]=1779, [1779]=1783, [1780]=1781, [1781]=1786, [1783]=1784, [1784]=1785, [1786]=1787, +[1787]=1788, [1791]=1712, [1796]=4781, [1798]=1758, [1799]=4961, [1801]=1803, [1802]=1804, [1803]=1805, +[1804]=1795, [1805]=1795, [1818]=1819, [1819]=1820, [1820]=1821, [1823]=1824, [1824]=1825, [1825]=1838, +[1839]=1842, [1840]=1844, [1841]=1846, [1859]=1963, [1860]=1861, [1879]=1880, [1881]=1882, [1883]=1884, +[1885]=1886, [1886]=1898, [1898]=1899, [1899]=1978, [1918]=824, [1919]=1920, [1920]=1921, [1938]=1940, +[1939]=1938, [1943]=1944, [1944]=1945, [1949]=1950, [1950]=1951, [1953]=1954, [1954]=1955, [1955]=1956, +[1956]=1957, [1959]=1960, [1960]=1961, [1963]=1858, [1998]=1999, [2039]=2038, [2041]=2040, [2098]=2078, +[2118]=2138, [2198]=2199, [2199]=2200, [2200]=2201, [2201]=2204, [2218]=2238, [2238]=2239, [2258]=2202, +[2259]=2260, [2279]=2439, [2281]=2282, [2283]=2284, [2284]=2318, [2299]=2298, [2300]=2281, [2318]=2338, +[2340]=2341, [2359]=2607, [2360]=2359, [2378]=2379, [2379]=2382, [2380]=2379, [2382]=2381, [2398]=2240, +[2438]=2459, [2460]=2458, [2478]=2479, [2479]=2480, [2498]=2499, [2518]=2520, [2519]=2518, [2541]=2561, +[2605]=2606, [2606]=2641, [2621]=2622, [2622]=2623, [2661]=2662, [2681]=2702, [2702]=2701, [2721]=2743, +[2742]=2782, [2743]=2744, [2744]=3141, [2745]=2746, [2757]=2760, [2758]=2759, [2759]=2760, [2766]=2767, +[2769]=2770, [2783]=2801, [2784]=2621, [2801]=2681, [2842]=2843, [2844]=2845, [2861]=2846, [2862]=2863, +[2863]=2902, [2864]=2865, [2866]=2867, [2869]=2870, [2870]=2871, [2872]=2873, [2873]=2874, [2879]=2942, +[2902]=2903, [2923]=2922, [2925]=2924, [2926]=2962, [2927]=2926, [2931]=2930, [2933]=2934, [2934]=2935, +[2935]=2936, [2936]=2937, [2940]=2941, [2941]=2944, [2944]=2943, [2947]=2948, [2949]=2950, [2963]=2946, +[2965]=2966, [2967]=2968, [2970]=2972, [2972]=3841, [2973]=2974, [2974]=2976, [2975]=2980, [2977]=2964, +[2978]=2979, [2979]=3002, [2981]=2975, [2983]=1524, [2984]=1524, [2985]=1530, [2986]=1530, [2988]=2989, +[2989]=2990, [2990]=2991, [2991]=2992, [2992]=2993, [2993]=2994, [2997]=1645, [2998]=1641, [2999]=1645, +[3000]=1645, [3121]=3122, [3123]=3124, [3124]=3125, [3125]=3126, [3126]=3127, [3130]=2869, [3141]=3508, +[3181]=3182, [3221]=1359, [3367]=3368, [3368]=3371, [3371]=3372, [3377]=3378, [3379]=3385, [3380]=3444, +[3385]=3402, [3442]=3443, [3443]=3452, [3445]=3444, [3448]=3449, [3449]=3461, [3450]=3451, [3452]=3453, +[3453]=3454, [3462]=3463, [3501]=3502, [3504]=3505, [3505]=3506, [3506]=3507, [3508]=3509, [3509]=3510, +[3510]=3511, [3511]=3602, [3513]=3514, [3518]=3562, [3519]=3521, [3520]=3527, [3521]=3522, [3523]=3525, +[3524]=4681, [3527]=4787, [3541]=3563, [3542]=3564, [3561]=3565, [3578]=3579, [3579]=3580, [3580]=3581, +[3621]=3625, [3625]=3626, [3626]=3627, [3627]=3628, [3631]=4490, [3638]=3639, [3640]=3641, [3642]=3643, +[3681]=1641, [3701]=4341, [3702]=3701, [3762]=3761, [3763]=3764, [3765]=1275, [3781]=3785, [3782]=3786, +[3783]=977, [3784]=3761, [3787]=3791, [3788]=3791, [3789]=3764, [3790]=3764, [3801]=3802, [3821]=3822, +[3823]=3824, [3824]=3825, [3841]=3842, [3842]=3843, [3843]=4297, [3844]=3845, [3845]=3908, [3903]=3904, +[3904]=3905, [3906]=3907, [3909]=3912, [3912]=3913, [3913]=3914, [3914]=3941, [3921]=3922, [3923]=3924, +[3941]=3942, [3942]=4084, [3961]=3962, [3981]=3982, [3982]=4001, [4001]=4002, [4002]=4003, [4003]=4004, +[4005]=3961, [4022]=4024, [4023]=4024, [4061]=4062, [4062]=4063, [4084]=4005, [4124]=4125, [4125]=4127, +[4127]=4129, [4128]=4126, [4129]=4130, [4130]=4131, [4131]=4135, [4133]=4134, [4135]=4265, [4141]=4142, +[4142]=4143, [4145]=4147, [4147]=4146, [4182]=4183, [4183]=4184, [4184]=4185, [4185]=4186, [4186]=4223, +[4223]=4224, [4224]=4241, [4241]=4242, [4243]=4244, [4262]=4263, [4264]=4282, [4265]=4266, [4266]=4267, +[4290]=4291, [4291]=4292, [4297]=4298, [4322]=6402, [4324]=4136, [4341]=4342, [4342]=4361, [4361]=4362, +[4362]=4363, [4449]=4450, [4487]=4490, [4488]=4490, [4489]=4490, [4493]=4496, [4494]=4496, [4495]=3519, +[4508]=4510, [4509]=4511, [4521]=4741, [4542]=4841, [4641]=788, [4726]=4808, [4734]=4735, [4736]=1796, +[4737]=1796, [4738]=1796, [4739]=1796, [4741]=4721, [4742]=4743, [4761]=4762, [4764]=4765, [4766]=4764, +[4769]=4768, [4781]=4782, [4782]=4783, [4783]=4784, [4784]=4786, [4787]=3528, [4808]=4809, [4809]=4810, +[4811]=4812, [4812]=4813, [4822]=558, [4841]=5064, [4861]=4863, [4863]=4864, [4865]=5062, [4881]=4966, +[4882]=4883, [4903]=4941, [4907]=4734, [4941]=4974, [4961]=4976, [4965]=1799, [4967]=1799, [4968]=1799, +[4969]=1799, [4981]=4982, [4982]=4983, [4984]=4985, [5001]=5002, [5002]=5081, [5022]=5048, [5023]=5049, +[5048]=5050, [5049]=5050, [5050]=5051, [5054]=5055, [5055]=5056, [5065]=4788, [5066]=5092, [5083]=5084, +[5084]=5085, [5085]=5086, [5086]=5087, [5087]=5121, [5089]=5102, [5090]=5092, [5091]=5092, [5093]=5096, +[5094]=5096, [5095]=5096, [5103]=5124, [5142]=5149, [5152]=5153, [5153]=5154, [5155]=5157, [5157]=5158, +[5159]=5165, [5160]=5161, [5161]=5162, [5162]=5164, [5203]=5204, [5204]=5385, [5206]=5941, [5210]=5181, +[5212]=5213, [5215]=5216, [5216]=5217, [5217]=5219, [5219]=5220, [5220]=5222, [5222]=5223, [5223]=5225, +[5225]=5226, [5228]=5229, [5229]=5230, [5230]=5231, [5231]=5232, [5232]=5233, [5233]=5234, [5234]=5235, +[5235]=5236, [5241]=5211, [5244]=5245, [5245]=5246, [5246]=5247, [5248]=5252, [5249]=5244, [5250]=5244, +[5252]=5253, [5261]=33, [5262]=5263, [5264]=5265, [5281]=5282, [5341]=5342, [5343]=5344, [5381]=5581, +[5382]=5515, [5441]=6394, [5461]=5462, [5462]=5463, [5463]=5464, [5464]=5465, [5465]=5466, [5481]=5482, +[5514]=5802, [5515]=5384, [5522]=5531, [5527]=5526, [5531]=4771, [5533]=5537, [5537]=5538, [5538]=5801, +[5542]=5742, [5543]=5742, [5544]=5742, [5601]=5149, [5622]=5621, [5623]=5624, [5626]=5625, [5649]=5648, +[5651]=5650, [5721]=5942, [5722]=5724, [5727]=5728, [5728]=5729, [5729]=5730, [5741]=6027, [5742]=5781, +[5781]=5845, [5801]=5803, [5802]=5804, [5845]=5846, [5846]=5848, [5848]=5861, [5861]=5862, [5901]=5902, +[5902]=6390, [5903]=5904, [5904]=6389, [5921]=5929, [5922]=5930, [5923]=5921, [5924]=5921, [5925]=5921, +[5926]=5922, [5927]=5922, [5928]=5922, [5929]=5931, [5930]=5932, [5931]=6001, [5932]=6002, [5941]=5721, +[6004]=6023, [6023]=6025, [6026]=6041, [6061]=6087, [6062]=6083, [6063]=6101, [6064]=6084, [6082]=6081, +[6083]=6082, [6084]=6085, [6085]=6086, [6087]=6088, [6088]=6089, [6101]=6102, [6102]=6103, [6121]=6122, +[6122]=6123, [6123]=6124, [6124]=6125, [6126]=6127, [6127]=6128, [6128]=6129, [6129]=6130, [6141]=261, +[6144]=6145, [6145]=6146, [6146]=6147, [6147]=6148, [6181]=6281, [6182]=6183, [6183]=6184, [6184]=6185, +[6185]=6186, [6186]=6187, [6261]=6285, [6281]=6261, [6282]=6283, [6321]=6323, [6322]=6324, [6323]=6322, +[6341]=6342, [6342]=6343, [6344]=6341, [6361]=6362, [6362]=6363, [6363]=6364, [6365]=6384, [6384]=6385, +[6385]=6386, [6387]=6391, [6388]=6392, [6391]=6388, [6403]=6501, [6501]=6502, [6522]=6521, [6523]=6401, +[6541]=6543, [6542]=6543, [6548]=6629, [6562]=6563, [6564]=6565, [6566]=6567, [6567]=6568, [6568]=6569, +[6569]=6570, [6585]=6601, [6601]=6602, [6603]=5082, [6604]=4861, [6605]=4505, [6606]=969, [6611]=6610, +[6612]=6610, [6623]=6622, [6625]=6624, [6627]=1159, [6628]=1394, [6761]=6762, [6762]=1124, [6821]=6822, +[6822]=6823, [6823]=6824, [6963]=6983, [6964]=7061, [6983]=6984, [7042]=7043, [7043]=7045, [7062]=7063, +[7383]=935, [7490]=7491, [7492]=7489, [7494]=7488, [7495]=7496, [7507]=7508, [7508]=7509, [7562]=7563, +[7563]=7564, [7601]=7602, [7602]=7603, [7621]=7622, [7623]=7624, [7624]=7625, [7637]=7639, [7639]=7640, +[7641]=7642, [7643]=7644, [7644]=7646, [7646]=7647, [7667]=8258, [7781]=7782, [7783]=7784, [7785]=7786, +[7841]=7842, [7842]=7843, [7845]=7846, [7846]=7847, [8151]=8153, [8153]=8231, [8231]=8232, [8233]=8234, +[8234]=8235, [8235]=8236, [8251]=8252, [8252]=8253, [8254]=8255, [8255]=8256, [8256]=8257, [8275]=8280, +[8276]=8280, [8279]=8287, [8280]=8281, [8284]=8285, [8285]=8279, [8288]=8301, [8303]=8305, [8304]=8306, +[8305]=8519, [8307]=8313, [8313]=8317, [8314]=8315, [8320]=8321, [8322]=8409, [8331]=8332, [8332]=8349, +[8341]=8351, [8343]=8341, [8349]=8348, [8351]=8352, [8410]=8412, [8411]=8412, [8415]=8414, [8416]=8418, +[8417]=8423, [8419]=8421, [8420]=8421, [8421]=8422, [8423]=8424, [8424]=8425, [8446]=8447, [8553]=8554, +[8577]=8578, [8584]=8585, [8585]=8586, [8586]=8587, [8597]=8598, [8598]=8606, [8606]=8620, [8728]=8729, +[8733]=8734, [8734]=8735, [8801]=8802, [8867]=8883, [8870]=8867, [8871]=8867, [8872]=8867, [8873]=8867, +[8874]=8867, [8875]=8867, [8903]=9024, [8904]=8979, [8921]=8924, [8922]=8921, [8923]=8921, [8924]=8925, +[8925]=8928, [8926]=8929, [8927]=8930, [8929]=8945, [8930]=8945, [8931]=8929, [8932]=8929, [8933]=8929, +[8934]=8929, [8935]=8929, [8936]=8929, [8937]=8929, [8938]=8930, [8939]=8930, [8940]=8930, [8941]=8930, +[8942]=8930, [8943]=8930, [8944]=8930, [8945]=8946, [8946]=8947, [8947]=8948, [8948]=8949, [8949]=8950, +[8951]=8960, [8952]=8960, [8953]=8960, [8954]=8960, [8955]=8960, [8956]=8960, [8957]=9032, [8958]=8960, +[8959]=8960, [8960]=8961, [8962]=8966, [8963]=8967, [8964]=8968, [8965]=8969, [8966]=8970, [8967]=8970, +[8968]=8970, [8969]=8970, [8979]=8980, [8980]=8982, [8982]=8983, [8983]=8984, [8985]=8990, [8986]=8989, +[8987]=8991, [8988]=8992, [8989]=8994, [8990]=8994, [8991]=8994, [8992]=8994, [8994]=8995, [8995]=8996, +[9016]=9032, [9017]=9032, [9018]=9032, [9019]=9032, [9020]=9032, [9021]=9032, [9022]=9032, [9024]=9025, +[9025]=9026, [9026]=9027, [9027]=9028, [9032]=8961, [9051]=9053, [9052]=9051, [9063]=9052, [9229]=9230, +[9250]=9251, [9362]=9364, [9415]=9419, [9416]=9422, [50003]=50004, +} +Codex.WdbZone = { +[2]=331, [5]=10, [6]=9, [7]=9, [8]=154, [9]=40, [10]=440, [11]=12, +[12]=40, [13]=40, [14]=40, [15]=9, [16]=12, [17]=1517, [18]=9, [19]=44, +[20]=44, [21]=9, [22]=40, [23]=331, [24]=331, [25]=331, [26]=-263, [27]=-263, +[28]=-263, [29]=-263, [30]=-263, [31]=-263, [32]=440, [33]=9, [34]=44, [35]=12, +[36]=40, [37]=12, [38]=40, [39]=12, [40]=12, [45]=12, [46]=12, [47]=12, +[48]=40, [49]=40, [50]=40, [51]=40, [52]=12, [53]=40, [54]=9, [55]=10, +[56]=10, [57]=10, [58]=10, [59]=12, [60]=12, [61]=12, [62]=12, [63]=-82, +[64]=40, [65]=40, [66]=10, [67]=10, [68]=10, [69]=10, [70]=10, [71]=12, +[72]=10, [74]=10, [75]=10, [76]=12, [77]=47, [78]=10, [79]=10, [80]=10, +[81]=1637, [82]=440, [83]=12, [84]=12, [85]=12, [86]=12, [87]=12, [88]=12, +[89]=44, [90]=10, [91]=44, [92]=44, [93]=10, [94]=44, [95]=10, [96]=-82, +[97]=10, [98]=10, [99]=130, [100]=-82, [101]=10, [102]=40, [103]=40, [104]=40, +[105]=28, [106]=12, [107]=12, [109]=12, [110]=440, [111]=12, [112]=12, [113]=440, +[114]=12, [115]=44, [116]=44, [117]=40, [118]=44, [119]=44, [120]=44, [121]=44, +[122]=44, [123]=12, [124]=44, [125]=44, [126]=44, [127]=44, [128]=44, [129]=44, +[130]=44, [131]=44, [132]=40, [133]=10, [134]=10, [135]=40, [136]=40, [138]=40, +[139]=40, [140]=40, [141]=40, [142]=40, [143]=44, [144]=44, [145]=44, [146]=44, +[147]=12, [148]=10, [149]=10, [150]=44, [151]=40, [152]=40, [153]=40, [154]=10, +[155]=40, [156]=10, [157]=10, [158]=10, [159]=10, [160]=10, [161]=38, [162]=440, +[163]=10, [164]=10, [165]=10, [166]=1581, [167]=1581, [168]=1581, [169]=44, [170]=132, +[171]=-284, [172]=-284, [173]=10, [174]=10, [175]=10, [176]=12, [177]=10, [178]=44, +[179]=132, [180]=44, [181]=10, [182]=132, [183]=132, [184]=40, [185]=33, [186]=33, +[187]=33, [188]=33, [189]=33, [190]=33, [191]=33, [192]=33, [193]=33, [194]=33, +[195]=33, [196]=33, [197]=33, [198]=33, [199]=38, [200]=33, [201]=33, [202]=33, +[203]=33, [204]=33, [205]=33, [206]=33, [207]=33, [208]=33, [209]=33, [210]=33, +[211]=28, [212]=1519, [213]=33, [214]=1581, [215]=33, [216]=331, [217]=38, [218]=132, +[219]=44, [220]=-82, [221]=10, [222]=10, [223]=10, [224]=38, [225]=10, [226]=10, +[227]=10, [228]=10, [229]=10, [230]=10, [231]=10, [232]=1497, [233]=132, [234]=132, +[235]=1637, [236]=10, [237]=38, [238]=1497, [239]=12, [240]=10, [243]=440, [244]=44, +[245]=10, [246]=44, [247]=331, [248]=44, [249]=44, [250]=38, [251]=10, [252]=10, +[253]=10, [254]=10, [255]=38, [256]=38, [257]=38, [258]=38, [261]=405, [262]=10, +[263]=38, [264]=1638, [265]=10, [266]=10, [267]=38, [268]=10, [269]=10, [270]=10, +[271]=38, [272]=-263, [273]=38, [274]=38, [275]=11, [276]=11, [277]=11, [278]=38, +[279]=11, [280]=38, [281]=11, [282]=132, [283]=38, [284]=11, [285]=11, [286]=11, +[287]=1, [288]=11, [289]=11, [290]=11, [291]=1, [292]=11, [293]=11, [294]=11, +[295]=11, [296]=11, [297]=38, [298]=38, [299]=11, [301]=38, [302]=38, [303]=11, +[304]=11, [305]=11, [306]=11, [307]=38, [308]=1, [309]=38, [310]=1, [311]=1, +[312]=1, [313]=1, [314]=1, [315]=1, [317]=1, [318]=1, [319]=1, [320]=1, +[321]=10, [322]=10, [323]=10, [324]=10, [325]=10, [328]=33, [329]=33, [330]=33, +[331]=33, [332]=1519, [333]=1519, [334]=1519, [335]=1519, [336]=1519, [337]=10, [338]=33, +[339]=33, [340]=33, [341]=33, [342]=33, [343]=1519, [344]=1519, [345]=1519, [346]=1519, +[347]=1519, [348]=33, [349]=33, [350]=1519, [351]=440, [353]=1519, [354]=85, [355]=85, +[356]=85, [357]=1497, [358]=85, [359]=85, [360]=85, [361]=85, [362]=85, [363]=154, +[364]=154, [365]=85, [366]=85, [367]=85, [368]=85, [369]=85, [370]=85, [371]=85, +[372]=85, [373]=1519, [374]=85, [375]=85, [376]=154, [377]=717, [378]=717, [379]=440, +[380]=154, [381]=154, [382]=154, [383]=154, [384]=-304, [385]=38, [386]=717, [387]=717, +[388]=717, [389]=1519, [391]=717, [392]=1519, [393]=1519, [394]=1519, [395]=1519, [396]=1519, +[397]=1519, [398]=85, [399]=1519, [400]=1, [401]=10, [403]=1, [404]=85, [405]=85, +[407]=85, [408]=85, [409]=85, [410]=85, [411]=85, [412]=1, [413]=1, [414]=1, +[415]=1, [416]=38, [417]=1, [418]=38, [419]=1, [420]=132, [421]=130, [422]=130, +[423]=130, [424]=130, [425]=130, [426]=85, [427]=85, [428]=130, [429]=130, [430]=130, +[431]=85, [432]=1, [433]=1, [434]=1519, [435]=130, [436]=38, [437]=130, [438]=130, +[439]=130, [440]=130, [441]=130, [442]=130, [443]=130, [444]=130, [445]=85, [446]=130, +[447]=130, [448]=130, [449]=130, [450]=130, [451]=130, [452]=130, [453]=10, [454]=38, +[455]=11, [456]=188, [457]=188, [458]=188, [459]=188, [460]=130, [461]=130, [463]=11, +[464]=11, [465]=11, [466]=1, [467]=1, [468]=11, [469]=11, [470]=11, [471]=11, +[472]=11, [473]=11, [474]=11, [475]=141, [476]=141, [477]=130, [478]=130, [479]=130, +[480]=130, [481]=130, [482]=130, [483]=141, [484]=11, [485]=47, [486]=141, [487]=141, +[488]=141, [489]=141, [491]=130, [492]=85, [493]=130, [494]=267, [495]=1497, [496]=267, +[498]=267, [499]=267, [500]=36, [501]=267, [502]=267, [503]=267, [504]=36, [505]=36, +[506]=267, [507]=267, [508]=267, [509]=267, [510]=36, [511]=36, [512]=36, [513]=267, +[514]=36, [515]=267, [516]=130, [517]=267, [518]=267, [519]=267, [520]=267, [521]=267, +[522]=36, [523]=36, [524]=267, [525]=36, [526]=10, [527]=267, [528]=267, [529]=267, +[530]=130, [531]=38, [532]=267, [533]=267, [535]=36, [536]=267, [537]=36, [538]=1519, +[539]=267, [540]=1519, [541]=267, [542]=1519, [543]=1519, [544]=267, [545]=267, [546]=267, +[547]=267, [549]=267, [550]=267, [551]=36, [552]=267, [553]=267, [554]=36, [555]=267, +[556]=267, [557]=267, [558]=-284, [559]=267, [560]=267, [561]=267, [562]=267, [563]=267, +[564]=267, [565]=267, [566]=267, [567]=267, [568]=33, [569]=33, [570]=33, [571]=33, +[572]=33, [573]=33, [574]=33, [575]=33, [576]=33, [577]=33, [578]=33, [579]=1519, +[580]=33, [581]=33, [582]=33, [583]=33, [584]=33, [585]=33, [586]=33, [587]=33, +[588]=33, [589]=33, [590]=154, [591]=33, [592]=33, [593]=33, [594]=33, [595]=33, +[596]=33, [597]=33, [598]=33, [599]=33, [600]=33, [601]=33, [602]=33, [603]=33, +[604]=33, [605]=33, [606]=33, [607]=33, [608]=33, [609]=33, [610]=33, [611]=33, +[613]=33, [614]=33, [615]=33, [616]=33, [617]=33, [618]=33, [619]=33, [621]=33, +[622]=33, [623]=33, [624]=33, [625]=33, [626]=33, [627]=33, [628]=33, [629]=33, +[630]=33, [631]=11, [632]=11, [633]=11, [634]=11, [635]=45, [636]=45, [637]=1537, +[638]=33, [639]=45, [640]=45, [641]=45, [642]=45, [643]=45, [644]=45, [645]=45, +[646]=45, [647]=11, [648]=440, [649]=1637, [650]=1637, [651]=45, [652]=45, [653]=45, +[654]=440, [655]=45, [656]=45, [657]=267, [658]=267, [659]=267, [660]=267, [661]=267, +[662]=45, [663]=45, [664]=45, [665]=45, [666]=45, [667]=45, [668]=45, [669]=45, +[670]=45, [671]=45, [672]=45, [673]=45, [674]=45, [675]=45, [676]=267, [677]=45, +[678]=45, [679]=45, [680]=45, [681]=45, [682]=45, [683]=1537, [684]=45, [685]=45, +[686]=1537, [687]=45, [688]=45, [689]=1537, [690]=1519, [691]=45, [692]=3, [693]=45, +[694]=45, [695]=45, [696]=45, [697]=45, [698]=8, [699]=8, [700]=1537, [701]=45, +[702]=45, [703]=3, [704]=1517, [705]=3, [706]=3, [707]=1537, [708]=3, [709]=1517, +[710]=3, [711]=3, [712]=3, [713]=3, [714]=3, [715]=3, [716]=3, [717]=3, +[718]=3, [719]=3, [720]=3, [721]=1517, [722]=1517, [723]=3, [724]=3, [725]=3, +[726]=3, [727]=3, [728]=3, [729]=148, [730]=1657, [731]=148, [732]=3, [733]=3, +[734]=3, [735]=3, [736]=1497, [737]=3, [738]=3, [739]=3, [741]=148, [742]=1638, +[743]=215, [744]=1638, [745]=215, [746]=215, [747]=220, [748]=215, [749]=215, [750]=220, +[751]=215, [752]=220, [753]=220, [754]=215, [755]=220, [756]=215, [757]=220, [758]=215, +[759]=215, [760]=215, [804]=363, [805]=363, [806]=14, [807]=14, [808]=14, [809]=14, +[810]=14, [811]=14, [812]=14, [813]=14, [814]=14, [815]=14, [816]=14, [817]=14, +[818]=14, [819]=17, [820]=14, [821]=17, [822]=17, [823]=14, [824]=331, [825]=14, +[826]=14, [827]=14, [828]=14, [829]=14, [830]=14, [831]=14, [832]=14, [833]=215, +[834]=14, [835]=14, [836]=47, [837]=14, [838]=28, [840]=14, [841]=440, [842]=14, +[843]=17, [844]=17, [845]=17, [846]=17, [847]=45, [848]=17, [849]=17, [850]=17, +[851]=17, [852]=17, [853]=17, [854]=215, [855]=17, [857]=17, [858]=17, [860]=17, +[861]=215, [862]=-304, [863]=17, [864]=1497, [865]=17, [866]=-24, [867]=17, [868]=17, +[869]=17, [870]=17, [871]=17, [872]=17, [873]=17, [874]=17, [875]=17, [876]=17, +[877]=17, [878]=17, [879]=17, [880]=17, [881]=17, [882]=17, [883]=17, [884]=17, +[885]=17, [886]=17, [887]=17, [888]=17, [889]=17, [890]=17, [891]=17, [892]=17, +[893]=17, [894]=17, [895]=17, [896]=17, [897]=17, [898]=17, [899]=17, [900]=17, +[901]=17, [902]=17, [903]=17, [905]=17, [906]=17, [907]=17, [908]=331, [909]=331, +[910]=-284, [911]=-284, [913]=17, [914]=718, [915]=-284, [916]=188, [917]=188, [918]=141, +[919]=141, [920]=188, [921]=188, [922]=141, [923]=141, [924]=14, [925]=-284, [926]=14, +[927]=141, [928]=188, [929]=141, [930]=141, [931]=141, [932]=141, [933]=141, [934]=141, +[935]=141, [936]=1637, [937]=141, [938]=141, [939]=361, [940]=141, [941]=141, [942]=148, +[943]=148, [944]=148, [945]=148, [947]=148, [948]=148, [949]=148, [950]=148, [951]=148, +[952]=1657, [953]=148, [954]=148, [955]=148, [956]=148, [957]=148, [958]=148, [959]=718, +[960]=148, [961]=148, [962]=718, [963]=148, [964]=28, [965]=148, [966]=148, [967]=148, +[968]=148, [969]=618, [970]=148, [971]=719, [972]=-82, [973]=148, [974]=490, [975]=618, +[976]=331, [977]=618, [978]=702, [979]=702, [980]=490, [981]=148, [982]=148, [983]=148, +[984]=148, [985]=148, [986]=148, [990]=331, [991]=331, [992]=440, [993]=148, [994]=148, +[995]=148, [996]=361, [997]=141, [998]=361, [1000]=1638, [1001]=148, [1002]=148, [1003]=148, +[1004]=1497, [1007]=331, [1008]=331, [1009]=331, [1010]=331, [1011]=331, [1012]=331, [1013]=209, +[1014]=209, [1015]=1519, [1016]=331, [1017]=331, [1018]=1637, [1019]=1537, [1020]=331, [1021]=331, +[1022]=331, [1023]=331, [1024]=331, [1025]=331, [1026]=331, [1027]=331, [1028]=331, [1029]=331, +[1030]=331, [1031]=331, [1032]=331, [1033]=331, [1034]=331, [1035]=331, [1036]=33, [1037]=331, +[1038]=331, [1039]=331, [1040]=331, [1041]=331, [1042]=331, [1043]=331, [1044]=331, [1045]=331, +[1046]=331, [1047]=1657, [1048]=796, [1049]=796, [1050]=796, [1051]=796, [1052]=405, [1053]=796, +[1054]=331, [1055]=331, [1056]=331, [1057]=406, [1058]=406, [1059]=406, [1060]=17, [1061]=406, +[1062]=406, [1063]=406, [1064]=1638, [1065]=1638, [1066]=1638, [1067]=1638, [1068]=406, [1069]=17, +[1070]=331, [1071]=406, [1072]=406, [1073]=406, [1074]=406, [1075]=406, [1076]=40, [1077]=406, +[1078]=406, [1079]=406, [1080]=406, [1081]=406, [1082]=406, [1083]=406, [1084]=406, [1085]=331, +[1086]=1638, [1087]=406, [1088]=406, [1089]=406, [1090]=406, [1091]=406, [1092]=406, [1093]=406, +[1094]=406, [1095]=406, [1096]=406, [1097]=1519, [1098]=209, [1100]=400, [1101]=1717, [1102]=1717, +[1103]=-82, [1104]=400, [1105]=400, [1106]=400, [1107]=400, [1108]=400, [1109]=1717, [1110]=400, +[1111]=400, [1112]=400, [1113]=796, [1114]=400, [1115]=400, [1116]=400, [1117]=400, [1118]=400, +[1119]=400, [1120]=400, [1121]=400, [1122]=400, [1123]=1638, [1124]=493, [1125]=1377, [1126]=1377, +[1127]=33, [1130]=1638, [1131]=1638, [1132]=11, [1133]=15, [1134]=331, [1135]=15, [1136]=1638, +[1137]=400, [1138]=148, [1139]=1517, [1140]=148, [1141]=148, [1142]=1717, [1143]=148, [1144]=1717, +[1145]=17, [1146]=1637, [1147]=400, [1148]=400, [1149]=400, [1150]=400, [1151]=400, [1152]=400, +[1153]=17, [1154]=400, [1157]=440, [1158]=440, [1159]=400, [1160]=796, [1164]=1497, [1166]=15, +[1167]=148, [1168]=15, [1169]=15, [1170]=15, [1171]=15, [1172]=15, [1173]=15, [1175]=400, +[1176]=400, [1177]=15, [1178]=400, [1179]=400, [1180]=400, [1181]=400, [1182]=400, [1183]=400, +[1184]=400, [1185]=493, [1186]=400, [1187]=400, [1188]=400, [1189]=400, [1190]=400, [1191]=400, +[1192]=400, [1193]=2557, [1194]=400, [1195]=1638, [1196]=1638, [1197]=1638, [1198]=719, [1199]=719, +[1200]=719, [1201]=15, [1202]=15, [1203]=15, [1204]=15, [1205]=15, [1206]=15, [1218]=15, +[1219]=15, [1220]=15, [1221]=1717, [1222]=15, [1238]=15, [1239]=15, [1240]=15, [1241]=1519, +[1242]=1519, [1243]=1519, [1244]=1519, [1245]=1519, [1246]=1519, [1247]=1519, [1248]=1519, [1249]=1519, +[1250]=1519, [1251]=15, [1252]=15, [1253]=15, [1258]=15, [1259]=15, [1260]=15, [1261]=15, +[1262]=15, [1264]=1519, [1265]=1519, [1266]=1519, [1267]=1519, [1268]=15, [1269]=15, [1270]=15, +[1271]=15, [1273]=15, [1274]=1519, [1275]=719, [1276]=15, [1282]=15, [1284]=15, [1285]=15, +[1286]=15, [1287]=15, [1288]=15, [1289]=15, [1301]=1519, [1302]=11, [1318]=2557, [1319]=15, +[1320]=15, [1321]=15, [1322]=15, [1323]=15, [1324]=1519, [1338]=38, [1339]=38, [1358]=1497, +[1359]=1497, [1360]=1517, [1361]=405, [1362]=405, [1363]=1519, [1364]=1519, [1365]=405, [1366]=405, +[1367]=405, [1368]=405, [1369]=405, [1370]=405, [1371]=405, [1372]=10, [1373]=405, [1374]=405, +[1375]=405, [1380]=405, [1381]=405, [1382]=405, [1383]=10, [1384]=405, [1385]=405, [1386]=405, +[1387]=405, [1388]=10, [1389]=8, [1390]=15, [1391]=10, [1392]=8, [1393]=8, [1394]=400, +[1395]=10, [1396]=8, [1398]=8, [1418]=8, [1419]=3, [1420]=3, [1421]=8, [1422]=8, +[1423]=8, [1424]=8, [1425]=8, [1426]=8, [1427]=8, [1428]=8, [1429]=8, [1430]=8, +[1431]=1637, [1432]=1637, [1433]=1637, [1434]=1637, [1435]=1637, [1436]=1637, [1437]=405, [1438]=405, +[1439]=405, [1440]=405, [1442]=-141, [1444]=47, [1445]=1417, [1446]=1417, [1447]=1519, [1448]=1519, +[1449]=1519, [1450]=47, [1451]=47, [1452]=47, [1453]=1537, [1454]=405, [1455]=405, [1456]=405, +[1457]=405, [1458]=405, [1459]=405, [1462]=-82, [1463]=-82, [1464]=-82, [1465]=405, [1466]=405, +[1467]=405, [1468]=-284, [1469]=47, [1470]=-61, [1471]=-61, [1472]=-61, [1473]=-61, [1474]=-61, +[1475]=1417, [1476]=-61, [1477]=1519, [1478]=-61, [1479]=-284, [1480]=405, [1481]=405, [1482]=405, +[1483]=17, [1484]=405, [1485]=-61, [1486]=718, [1487]=718, [1488]=405, [1489]=718, [1490]=718, +[1491]=718, [1492]=17, [1498]=-81, [1499]=-61, [1501]=-61, [1502]=-81, [1503]=-81, [1504]=-61, +[1505]=-81, [1506]=-61, [1507]=-61, [1508]=-61, [1509]=-61, [1510]=-61, [1511]=-61, [1512]=-61, +[1513]=-61, [1514]=361, [1515]=-61, [1516]=-82, [1517]=-82, [1518]=-82, [1519]=-82, [1520]=-82, +[1521]=-82, [1522]=-82, [1523]=-82, [1524]=-82, [1525]=-82, [1526]=-82, [1527]=-82, [1528]=-82, +[1529]=-82, [1530]=-82, [1531]=-82, [1532]=-82, [1534]=-82, [1535]=-82, [1536]=-82, [1558]=-284, +[1559]=-201, [1560]=440, [1578]=-121, [1579]=-101, [1580]=-101, [1581]=-181, [1582]=-182, [1638]=-81, +[1639]=-81, [1640]=-81, [1641]=-141, [1642]=-141, [1643]=-141, [1644]=-141, [1645]=-141, [1646]=-141, +[1647]=-141, [1648]=-141, [1649]=-141, [1650]=-141, [1651]=-141, [1652]=-141, [1653]=-141, [1654]=-141, +[1655]=-141, [1656]=220, [1657]=-22, [1658]=-22, [1661]=-141, [1665]=-81, [1666]=-81, [1667]=-81, +[1678]=-81, [1679]=-81, [1680]=-81, [1681]=-81, [1682]=-81, [1683]=-81, [1684]=-81, [1685]=-61, +[1686]=-81, [1687]=-284, [1688]=-61, [1689]=-61, [1690]=440, [1691]=440, [1692]=-81, [1693]=-81, +[1698]=-81, [1699]=-81, [1700]=-81, [1701]=-81, [1702]=-81, [1703]=-81, [1704]=-81, [1705]=-81, +[1706]=-81, [1707]=440, [1708]=-81, [1709]=-81, [1710]=-81, [1711]=-81, [1712]=-81, [1713]=-81, +[1714]=-81, [1715]=-61, [1716]=-61, [1717]=-61, [1718]=-81, [1719]=-81, [1738]=-61, [1739]=-61, +[1740]=-61, [1758]=-61, [1778]=-141, [1779]=-141, [1780]=-141, [1781]=-141, [1783]=-141, [1784]=-141, +[1785]=-141, [1786]=-141, [1787]=-141, [1788]=-141, [1789]=-141, [1790]=-141, [1791]=-81, [1792]=-81, +[1793]=-141, [1794]=-141, [1795]=-61, [1796]=-61, [1798]=-61, [1799]=-61, [1800]=-284, [1801]=-61, +[1802]=-61, [1803]=-61, [1804]=-61, [1805]=-61, [1806]=-141, [1818]=-81, [1819]=-81, [1820]=-81, +[1821]=-81, [1822]=-81, [1823]=-81, [1824]=-81, [1825]=-81, [1838]=-81, [1839]=-81, [1840]=-81, +[1841]=-81, [1842]=-81, [1843]=-81, [1844]=-81, [1845]=-81, [1846]=-81, [1847]=-81, [1848]=-81, +[1858]=-162, [1859]=-162, [1860]=-161, [1861]=-161, [1878]=440, [1879]=-161, [1880]=-161, [1881]=-161, +[1882]=-161, [1883]=-161, [1884]=-161, [1885]=-162, [1886]=-162, [1898]=-162, [1899]=-162, [1918]=331, +[1919]=-161, [1920]=-161, [1921]=-161, [1938]=-161, [1939]=-161, [1940]=-161, [1941]=-161, [1942]=-161, +[1943]=-161, [1944]=-161, [1945]=-161, [1946]=-161, [1947]=-161, [1948]=-161, [1949]=-161, [1950]=-161, +[1951]=-161, [1952]=-161, [1953]=-161, [1954]=-161, [1955]=-161, [1956]=-161, [1957]=-161, [1958]=-161, +[1959]=-161, [1960]=-161, [1961]=-161, [1962]=-161, [1963]=-162, [1978]=-162, [1998]=-162, [1999]=-162, +[2038]=38, [2039]=1537, [2040]=1581, [2041]=1537, [2078]=148, [2098]=148, [2118]=148, [2138]=148, +[2139]=148, [2158]=12, [2159]=141, [2160]=1, [2161]=14, [2178]=-304, [2198]=1517, [2199]=1517, +[2200]=1517, [2201]=1517, [2202]=1517, [2203]=3, [2204]=1517, [2205]=-162, [2206]=-162, [2218]=-162, +[2238]=-162, [2239]=-162, [2240]=1517, [2241]=-162, [2242]=-162, [2258]=3, [2259]=-162, [2260]=-162, +[2278]=1517, [2279]=1517, [2280]=1517, [2281]=-162, [2282]=-162, [2283]=1517, [2284]=1517, [2298]=-162, +[2299]=-162, [2300]=-162, [2318]=1517, [2338]=1517, [2339]=1517, [2340]=1517, [2341]=1517, [2342]=1517, +[2358]=-162, [2359]=-162, [2360]=-162, [2361]=1517, [2378]=-162, [2379]=-162, [2380]=-162, [2381]=-162, +[2382]=-162, [2383]=-81, [2398]=1517, [2399]=141, [2418]=1517, [2438]=141, [2439]=1537, [2440]=1638, +[2458]=-162, [2459]=141, [2460]=-162, [2478]=-162, [2479]=-162, [2480]=-162, [2498]=141, [2499]=141, +[2500]=38, [2501]=38, [2518]=1657, [2519]=1657, [2520]=1657, [2521]=4, [2522]=4, [2523]=361, +[2541]=141, [2561]=141, [2581]=4, [2582]=4, [2583]=4, [2584]=4, [2585]=4, [2586]=4, +[2601]=4, [2602]=4, [2603]=4, [2604]=4, [2605]=440, [2606]=440, [2607]=-162, [2608]=-162, +[2609]=-162, [2621]=4, [2622]=8, [2623]=8, [2641]=440, [2661]=440, [2662]=440, [2681]=4, +[2701]=4, [2702]=4, [2721]=4, [2741]=440, [2742]=47, [2743]=4, [2744]=4, [2745]=1519, +[2746]=1519, [2747]=440, [2748]=440, [2749]=440, [2750]=440, [2751]=-121, [2752]=-121, [2753]=-121, +[2754]=-121, [2755]=-121, [2756]=-121, [2757]=-121, [2758]=-121, [2759]=-121, [2760]=-121, [2761]=-121, +[2762]=-121, [2763]=-121, [2764]=-121, [2765]=-121, [2766]=357, [2767]=357, [2768]=978, [2769]=400, +[2770]=978, [2771]=-121, [2772]=-121, [2773]=-121, [2781]=440, [2782]=47, [2783]=4, [2784]=4, +[2801]=4, [2821]=357, [2822]=357, [2841]=133, [2842]=133, [2843]=133, [2844]=357, [2845]=357, +[2846]=978, [2847]=-182, [2848]=-182, [2849]=-182, [2850]=-182, [2851]=-182, [2852]=-182, [2853]=-182, +[2854]=-182, [2855]=-182, [2856]=-182, [2857]=-182, [2858]=-182, [2859]=-182, [2860]=-182, [2861]=978, +[2862]=357, [2863]=357, [2864]=978, [2865]=978, [2866]=357, [2867]=357, [2869]=357, [2870]=357, +[2871]=357, [2872]=440, [2873]=440, [2874]=440, [2875]=440, [2876]=440, [2877]=47, [2878]=357, +[2879]=357, [2880]=47, [2881]=47, [2882]=-221, [2902]=357, [2903]=357, [2904]=133, [2922]=133, +[2923]=133, [2924]=133, [2925]=133, [2926]=133, [2927]=133, [2928]=133, [2929]=133, [2930]=133, +[2931]=133, [2932]=47, [2933]=47, [2934]=47, [2935]=47, [2936]=978, [2937]=47, [2938]=47, +[2939]=357, [2940]=357, [2941]=357, [2942]=357, [2943]=357, [2944]=357, [2945]=133, [2946]=1537, +[2947]=133, [2948]=1537, [2949]=133, [2950]=1637, [2951]=133, [2952]=133, [2953]=133, [2954]=440, +[2962]=133, [2963]=1537, [2964]=1537, [2965]=1638, [2966]=1638, [2967]=1638, [2968]=1638, [2969]=357, +[2970]=357, [2972]=357, [2973]=357, [2974]=357, [2975]=357, [2976]=357, [2977]=1537, [2978]=357, +[2979]=357, [2980]=357, [2981]=1637, [2982]=357, [2983]=-82, [2984]=-82, [2985]=-82, [2986]=-82, +[2987]=357, [2988]=47, [2989]=47, [2990]=47, [2991]=978, [2992]=47, [2993]=47, [2994]=47, +[2995]=1497, [2996]=-61, [2997]=-141, [2998]=-141, [2999]=-141, [3000]=-141, [3001]=-61, [3002]=357, +[3022]=440, [3042]=978, [3062]=357, [3063]=357, [3065]=-81, [3082]=-261, [3083]=-162, [3084]=-82, +[3085]=-262, [3086]=-161, [3087]=-261, [3088]=-162, [3089]=-82, [3090]=-61, [3091]=-81, [3092]=-261, +[3093]=-82, [3094]=-263, [3095]=-81, [3096]=-162, [3097]=-262, [3098]=-161, [3099]=-61, [3100]=-81, +[3101]=-141, [3102]=-162, [3103]=-262, [3104]=-161, [3105]=-61, [3106]=-81, [3107]=-141, [3108]=-261, +[3109]=-162, [3110]=-262, [3111]=-161, [3112]=-81, [3113]=-162, [3114]=-161, [3115]=-61, [3116]=-81, +[3117]=-261, [3118]=-162, [3119]=-262, [3120]=-263, [3121]=357, [3122]=357, [3123]=357, [3124]=357, +[3125]=357, [3126]=357, [3127]=357, [3128]=357, [3129]=357, [3130]=357, [3141]=16, [3161]=440, +[3181]=51, [3182]=38, [3201]=1537, [3221]=130, [3281]=17, [3301]=17, [3321]=-121, [3341]=722, +[3361]=132, [3362]=440, [3363]=361, [3364]=132, [3365]=132, [3366]=718, [3367]=51, [3368]=51, +[3369]=17, [3370]=17, [3371]=1537, [3372]=51, [3373]=1417, [3374]=8, [3375]=1517, [3376]=220, +[3377]=51, [3378]=51, [3379]=-264, [3380]=1417, [3381]=16, [3382]=16, [3385]=-264, [3402]=-264, +[3421]=16, [3441]=51, [3442]=51, [3443]=51, [3444]=440, [3445]=357, [3446]=1417, [3447]=1417, +[3448]=1537, [3449]=1537, [3450]=1537, [3451]=1537, [3452]=51, [3453]=51, [3454]=51, [3461]=1537, +[3462]=51, [3463]=51, [3481]=51, [3483]=1537, [3501]=4, [3502]=4, [3503]=16, [3504]=1637, +[3505]=1637, [3506]=1637, [3507]=1637, [3508]=16, [3509]=16, [3510]=16, [3511]=16, [3512]=8, +[3513]=17, [3514]=17, [3517]=16, [3518]=16, [3519]=188, [3520]=440, [3521]=188, [3522]=188, +[3523]=722, [3524]=148, [3525]=722, [3526]=-201, [3527]=978, [3528]=1417, [3541]=16, [3542]=16, +[3561]=16, [3562]=16, [3563]=16, [3564]=16, [3565]=16, [3566]=51, [3567]=357, [3568]=1497, +[3569]=1497, [3570]=1497, [3578]=222, [3579]=222, [3580]=222, [3581]=222, [3601]=16, [3602]=16, +[3621]=16, [3625]=33, [3626]=33, [3627]=4, [3628]=4, [3629]=-201, [3630]=-201, [3631]=-61, +[3632]=-201, [3633]=-201, [3634]=-201, [3635]=-201, [3636]=722, [3637]=-201, [3638]=-201, [3639]=-201, +[3640]=-201, [3641]=-201, [3642]=-201, [3643]=-201, [3644]=-201, [3645]=-201, [3646]=-201, [3647]=-201, +[3661]=702, [3681]=-141, [3701]=1537, [3702]=1537, [3721]=35, [3741]=44, [3761]=1638, [3762]=1638, +[3763]=1657, [3764]=1657, [3765]=1519, [3781]=1657, [3782]=1638, [3783]=618, [3784]=1497, [3785]=1657, +[3786]=1638, [3787]=1519, [3788]=1116, [3789]=1519, [3790]=1537, [3791]=1116, [3792]=1116, [3801]=1584, +[3802]=1584, [3803]=1657, [3804]=1638, [3821]=3, [3822]=46, [3823]=46, [3824]=46, [3825]=46, +[3841]=357, [3842]=357, [3843]=357, [3844]=490, [3845]=490, [3861]=-284, [3881]=490, [3882]=490, +[3883]=490, [3884]=490, [3901]=154, [3902]=154, [3903]=9, [3904]=9, [3905]=9, [3906]=25, +[3907]=1584, [3908]=490, [3909]=490, [3912]=490, [3913]=490, [3914]=490, [3921]=17, [3922]=17, +[3923]=17, [3924]=17, [3941]=490, [3942]=490, [3961]=490, [3962]=490, [3981]=1584, [3982]=1584, +[4001]=1584, [4002]=1584, [4003]=1584, [4004]=1584, [4005]=490, [4021]=17, [4022]=46, [4023]=46, +[4024]=1584, [4041]=357, [4061]=46, [4062]=3, [4063]=1584, [4081]=1584, [4082]=1584, [4083]=1584, +[4084]=490, [4101]=361, [4102]=361, [4103]=361, [4104]=361, [4105]=361, [4106]=361, [4107]=361, +[4108]=361, [4109]=361, [4110]=361, [4111]=361, [4112]=361, [4113]=361, [4114]=361, [4115]=361, +[4116]=361, [4117]=361, [4118]=361, [4119]=361, [4120]=357, [4121]=1584, [4122]=1584, [4123]=1584, +[4124]=357, [4125]=357, [4126]=1584, [4127]=357, [4128]=1584, [4129]=357, [4130]=357, [4131]=357, +[4132]=1584, [4133]=1584, [4134]=1584, [4135]=357, [4136]=1584, [4141]=490, [4142]=490, [4143]=1477, +[4144]=490, [4145]=490, [4146]=490, [4147]=490, [4148]=490, [4161]=-304, [4181]=-201, [4182]=46, +[4183]=46, [4184]=46, [4185]=46, [4186]=46, [4201]=1584, [4221]=361, [4222]=361, [4223]=46, +[4224]=46, [4241]=1584, [4242]=1584, [4243]=490, [4244]=490, [4245]=490, [4261]=361, [4262]=25, +[4263]=1584, [4264]=1584, [4265]=357, [4266]=357, [4267]=357, [4281]=357, [4282]=1584, [4283]=46, +[4284]=490, [4285]=490, [4286]=1584, [4287]=490, [4288]=490, [4289]=490, [4290]=490, [4291]=490, +[4292]=490, [4293]=1497, [4294]=1497, [4295]=1584, [4296]=46, [4297]=357, [4298]=357, [4300]=1637, +[4301]=490, [4321]=490, [4322]=1584, [4324]=1584, [4341]=1584, [4342]=1584, [4343]=361, [4361]=1584, +[4362]=1584, [4363]=1584, [4381]=490, [4382]=490, [4383]=490, [4384]=490, [4385]=490, [4386]=490, +[4401]=361, [4402]=363, [4403]=361, [4421]=361, [4441]=361, [4442]=361, [4443]=361, [4444]=361, +[4445]=361, [4446]=361, [4447]=361, [4448]=361, [4449]=51, [4450]=51, [4451]=51, [4461]=361, +[4462]=361, [4463]=46, [4464]=361, [4465]=361, [4466]=361, [4467]=361, [4481]=46, [4482]=46, +[4483]=46, [4484]=46, [4485]=-141, [4486]=-141, [4487]=-61, [4488]=-61, [4489]=-61, [4490]=-61, +[4491]=490, [4492]=490, [4493]=1657, [4494]=1637, [4495]=188, [4496]=440, [4501]=490, [4502]=490, +[4503]=490, [4504]=440, [4505]=361, [4506]=361, [4507]=440, [4508]=440, [4509]=440, [4510]=1657, +[4511]=1637, [4512]=1537, [4513]=1537, [4521]=361, [4542]=400, [4561]=1497, [4581]=331, [4601]=133, +[4602]=133, [4603]=133, [4604]=133, [4605]=133, [4606]=133, [4621]=33, [4641]=363, [4642]=1497, +[4661]=1497, [4681]=148, [4701]=1583, [4721]=361, [4722]=148, [4723]=148, [4724]=1583, [4725]=148, +[4726]=46, [4727]=148, [4728]=148, [4729]=1583, [4730]=148, [4731]=148, [4732]=148, [4733]=148, +[4734]=1583, [4735]=1583, [4736]=-61, [4737]=-61, [4738]=-61, [4739]=-61, [4740]=148, [4741]=361, +[4742]=1583, [4743]=1583, [4761]=148, [4762]=148, [4763]=148, [4764]=1583, [4765]=1583, [4766]=1583, +[4767]=400, [4768]=1583, [4769]=1583, [4770]=400, [4771]=2057, [4781]=-61, [4782]=-61, [4783]=-61, +[4784]=-61, [4785]=-61, [4786]=-61, [4787]=47, [4788]=1583, [4801]=618, [4802]=618, [4803]=618, +[4804]=618, [4805]=618, [4806]=618, [4807]=618, [4808]=46, [4809]=618, [4810]=618, [4811]=148, +[4812]=148, [4813]=148, [4821]=400, [4822]=-284, [4841]=400, [4842]=618, [4861]=618, [4862]=1583, +[4863]=618, [4864]=618, [4865]=400, [4866]=1583, [4867]=1583, [4881]=400, [4882]=618, [4883]=618, +[4901]=618, [4902]=618, [4903]=1583, [4904]=400, [4906]=361, [4907]=1583, [4921]=17, [4941]=1637, +[4961]=-61, [4962]=-61, [4963]=-61, [4964]=-61, [4965]=-61, [4966]=400, [4967]=-61, [4968]=-61, +[4969]=-61, [4970]=618, [4971]=28, [4972]=28, [4973]=28, [4974]=1583, [4975]=-61, [4976]=-61, +[4981]=1583, [4982]=1583, [4983]=1583, [4984]=28, [4985]=28, [4986]=28, [4987]=28, [5001]=1583, +[5002]=1583, [5021]=28, [5022]=28, [5023]=28, [5041]=17, [5042]=17, [5043]=17, [5044]=17, +[5045]=17, [5046]=17, [5047]=1583, [5048]=1519, [5049]=1497, [5050]=28, [5051]=28, [5052]=17, +[5054]=618, [5055]=618, [5056]=618, [5057]=618, [5058]=28, [5059]=28, [5060]=28, [5061]=-263, +[5062]=400, [5063]=618, [5064]=400, [5065]=139, [5066]=1519, [5067]=618, [5068]=618, [5081]=1583, +[5082]=618, [5083]=618, [5084]=618, [5085]=618, [5086]=618, [5087]=618, [5088]=400, [5089]=1583, +[5090]=1537, [5091]=1657, [5092]=28, [5093]=28, [5094]=28, [5095]=28, [5096]=28, [5097]=28, +[5098]=28, [5102]=1583, [5103]=-121, [5121]=618, [5122]=2017, [5123]=618, [5124]=618, [5125]=2017, +[5126]=618, [5127]=1583, [5128]=618, [5141]=-182, [5142]=139, [5143]=-182, [5144]=-182, [5145]=-182, +[5146]=-182, [5147]=400, [5148]=-182, [5149]=139, [5150]=490, [5151]=400, [5152]=139, [5153]=139, +[5154]=28, [5155]=361, [5156]=361, [5157]=361, [5158]=361, [5159]=361, [5160]=1583, [5161]=618, +[5162]=28, [5163]=618, [5164]=28, [5165]=361, [5166]=28, [5167]=28, [5168]=139, [5181]=139, +[5201]=618, [5202]=361, [5203]=361, [5204]=361, [5206]=139, [5210]=139, [5211]=139, [5212]=2017, +[5213]=2017, [5214]=2017, [5215]=28, [5216]=28, [5217]=28, [5218]=28, [5219]=28, [5220]=28, +[5221]=28, [5222]=28, [5223]=28, [5224]=28, [5225]=28, [5226]=28, [5227]=28, [5228]=28, +[5229]=28, [5230]=28, [5231]=28, [5232]=28, [5233]=28, [5234]=28, [5235]=28, [5236]=28, +[5237]=28, [5238]=28, [5241]=139, [5242]=361, [5243]=2017, [5244]=618, [5245]=618, [5246]=139, +[5247]=139, [5248]=139, [5249]=361, [5250]=702, [5251]=2017, [5252]=618, [5253]=618, [5261]=9, +[5262]=2017, [5263]=2017, [5264]=139, [5265]=139, [5281]=139, [5282]=2017, [5283]=-121, [5284]=-121, +[5301]=-121, [5302]=-121, [5305]=-121, [5306]=-121, [5307]=-121, [5321]=148, [5341]=2057, [5342]=28, +[5343]=2057, [5344]=28, [5361]=400, [5381]=405, [5382]=2057, [5384]=2057, [5385]=361, [5386]=405, +[5401]=28, [5402]=28, [5403]=28, [5404]=28, [5405]=28, [5406]=28, [5407]=28, [5408]=28, +[5421]=405, [5441]=363, [5461]=28, [5462]=28, [5463]=2017, [5464]=139, [5465]=28, [5466]=2057, +[5481]=85, [5482]=85, [5501]=405, [5502]=-284, [5503]=139, [5504]=28, [5505]=28, [5507]=28, +[5508]=139, [5509]=139, [5510]=139, [5511]=28, [5513]=139, [5514]=28, [5515]=2057, [5517]=139, +[5518]=2557, [5519]=2557, [5521]=28, [5522]=46, [5524]=28, [5525]=2557, [5526]=493, [5527]=493, +[5528]=2557, [5529]=2057, [5531]=2057, [5533]=28, [5534]=16, [5535]=16, [5536]=16, [5537]=28, +[5538]=28, [5541]=1, [5542]=139, [5543]=139, [5544]=139, [5545]=12, [5561]=405, [5581]=405, +[5582]=2057, [5601]=139, [5621]=-262, [5622]=-262, [5623]=-262, [5624]=-262, [5625]=-262, [5626]=-262, +[5627]=-262, [5628]=-262, [5629]=-262, [5630]=-262, [5631]=-262, [5632]=-262, [5633]=-262, [5634]=-262, +[5635]=-262, [5636]=-262, [5637]=-262, [5638]=-262, [5639]=-262, [5640]=-262, [5641]=-262, [5642]=-262, +[5643]=-262, [5644]=-262, [5645]=-262, [5646]=-262, [5647]=-262, [5648]=-262, [5649]=-262, [5650]=-262, +[5651]=-262, [5652]=-262, [5654]=-262, [5655]=-262, [5656]=-262, [5657]=-262, [5658]=-262, [5659]=-262, +[5660]=-262, [5661]=-262, [5662]=-262, [5663]=-262, [5672]=-262, [5673]=-262, [5674]=-262, [5675]=-262, +[5676]=-262, [5677]=-262, [5678]=-262, [5679]=-262, [5680]=-262, [5713]=148, [5721]=139, [5722]=2437, +[5723]=2437, [5724]=2437, [5725]=2437, [5726]=1637, [5727]=1637, [5728]=2437, [5729]=1637, [5730]=1637, +[5741]=405, [5742]=139, [5761]=2437, [5762]=400, [5763]=405, [5781]=139, [5801]=440, [5802]=440, +[5803]=28, [5804]=28, [5821]=405, [5845]=139, [5846]=139, [5848]=2017, [5861]=28, [5862]=28, +[5863]=440, [5881]=406, [5882]=361, [5883]=361, [5884]=361, [5885]=361, [5886]=361, [5887]=361, +[5888]=361, [5889]=361, [5890]=361, [5891]=361, [5892]=2597, [5893]=2597, [5901]=85, [5902]=85, +[5903]=28, [5904]=28, [5921]=-263, [5922]=-263, [5923]=-263, [5924]=-263, [5925]=-263, [5926]=-263, +[5927]=-263, [5928]=-263, [5929]=-263, [5930]=-263, [5931]=-263, [5932]=-263, [5941]=139, [5942]=139, +[5943]=405, [5944]=28, [5961]=1497, [5981]=618, [6000]=-61, [6001]=-263, [6002]=-263, [6004]=28, +[6021]=139, [6022]=139, [6023]=28, [6024]=139, [6025]=28, [6026]=139, [6027]=405, [6028]=618, +[6029]=618, [6030]=618, [6031]=1216, [6032]=1216, [6041]=139, [6042]=139, [6061]=-261, [6062]=-261, +[6063]=-261, [6064]=-261, [6065]=-261, [6066]=-261, [6067]=-261, [6068]=-261, [6069]=-261, [6070]=-261, +[6071]=-261, [6072]=-261, [6073]=-261, [6074]=-261, [6075]=-261, [6076]=-261, [6081]=-261, [6082]=-261, +[6083]=-261, [6084]=-261, [6085]=-261, [6086]=-261, [6087]=-261, [6088]=-261, [6089]=-261, [6101]=-261, +[6102]=-261, [6103]=-261, [6121]=-263, [6122]=-263, [6123]=-263, [6124]=-263, [6125]=-263, [6126]=-263, +[6127]=-263, [6128]=-263, [6129]=-263, [6130]=-263, [6131]=361, [6132]=405, [6133]=139, [6134]=405, +[6135]=139, [6136]=139, [6141]=405, [6142]=405, [6143]=405, [6144]=139, [6145]=139, [6146]=139, +[6147]=139, [6148]=139, [6161]=405, [6162]=361, [6163]=2017, [6164]=139, [6165]=28, [6181]=40, +[6182]=1519, [6183]=1519, [6184]=28, [6185]=139, [6186]=1519, [6187]=139, [6221]=1769, [6241]=1769, +[6261]=40, [6281]=40, [6282]=406, [6283]=406, [6284]=406, [6285]=40, [6301]=406, [6321]=130, +[6322]=130, [6323]=130, [6324]=130, [6341]=148, [6342]=148, [6343]=148, [6344]=1657, [6361]=17, +[6362]=17, [6363]=17, [6364]=17, [6365]=17, [6381]=406, [6382]=17, [6383]=331, [6384]=17, +[6385]=17, [6386]=17, [6387]=38, [6388]=38, [6389]=28, [6390]=28, [6391]=38, [6392]=38, +[6393]=406, [6394]=363, [6395]=154, [6401]=406, [6402]=1519, [6403]=1519, [6421]=406, [6441]=331, +[6442]=331, [6461]=406, [6462]=331, [6481]=406, [6482]=331, [6501]=1519, [6502]=1583, [6503]=331, +[6504]=331, [6521]=722, [6522]=722, [6523]=406, [6541]=17, [6542]=406, [6543]=17, [6544]=331, +[6545]=331, [6546]=331, [6547]=331, [6548]=406, [6561]=719, [6562]=719, [6563]=719, [6564]=719, +[6565]=719, [6566]=1637, [6567]=1637, [6568]=405, [6569]=1583, [6570]=15, [6571]=331, [6581]=331, +[6582]=15, [6583]=15, [6584]=15, [6585]=15, [6601]=15, [6602]=1583, [6603]=618, [6604]=618, +[6605]=618, [6606]=618, [6607]=-101, [6608]=-101, [6609]=-101, [6610]=-304, [6611]=-304, [6612]=-304, +[6621]=331, [6622]=-324, [6623]=-324, [6624]=-324, [6625]=-324, [6626]=722, [6627]=400, [6628]=400, +[6629]=406, [6641]=331, [6642]=2717, [6643]=2717, [6644]=2717, [6645]=2717, [6646]=2717, [6661]=2257, +[6662]=2257, [6681]=-162, [6701]=-162, [6721]=1537, [6722]=131, [6741]=2597, [6761]=1657, [6762]=1657, +[6781]=2597, [6801]=2597, [6804]=16, [6805]=16, [6821]=16, [6822]=16, [6823]=16, [6824]=16, +[6825]=2597, [6826]=2597, [6827]=2597, [6881]=2597, [6901]=2597, [6921]=719, [6922]=331, [6941]=2597, +[6942]=2597, [6943]=2597, [6961]=-22, [6962]=-22, [6963]=-22, [6964]=-22, [6981]=718, [6982]=2597, +[6983]=-22, [6984]=-22, [6985]=2597, [7001]=2597, [7002]=2597, [7003]=357, [7021]=-22, [7022]=-22, +[7023]=-22, [7024]=-22, [7025]=-22, [7026]=2597, [7027]=2597, [7028]=2100, [7029]=2100, [7041]=2100, +[7042]=-22, [7043]=-22, [7044]=2100, [7045]=-22, [7046]=2100, [7061]=-22, [7062]=-22, [7063]=-22, +[7064]=2100, [7065]=2100, [7066]=2100, [7067]=2100, [7068]=2100, [7070]=2100, [7081]=2597, [7082]=2597, +[7101]=2597, [7102]=2597, [7121]=2597, [7122]=2597, [7123]=2597, [7124]=2597, [7141]=2597, [7142]=2597, +[7161]=2597, [7162]=2597, [7163]=2597, [7164]=2597, [7165]=2597, [7166]=2597, [7167]=2597, [7168]=2597, +[7169]=2597, [7170]=2597, [7171]=2597, [7172]=2597, [7181]=2597, [7201]=1584, [7202]=2597, [7223]=2597, +[7224]=2597, [7241]=2597, [7261]=2597, [7281]=2597, [7282]=2597, [7301]=2597, [7302]=2597, [7321]=-304, +[7341]=1637, [7342]=1537, [7361]=2597, [7362]=2597, [7363]=2597, [7364]=2597, [7365]=2597, [7366]=2597, +[7367]=2597, [7368]=2597, [7381]=2597, [7382]=2597, [7383]=141, [7385]=2597, [7386]=2597, [7401]=2597, +[7402]=2597, [7421]=2597, [7422]=2597, [7423]=2597, [7424]=2597, [7425]=2597, [7426]=2597, [7427]=2597, +[7428]=2597, [7429]=2557, [7441]=2557, [7461]=2557, [7462]=2557, [7463]=2557, [7478]=2557, [7479]=2557, +[7480]=2557, [7481]=2557, [7482]=2557, [7483]=2557, [7484]=2557, [7485]=2557, [7486]=16, [7487]=2717, +[7488]=2557, [7489]=2557, [7490]=1637, [7491]=1637, [7492]=2557, [7493]=1637, [7494]=2557, [7495]=1519, +[7496]=1519, [7497]=1519, [7498]=2557, [7499]=2557, [7500]=2557, [7501]=2557, [7502]=2557, [7503]=2557, +[7504]=2557, [7505]=2557, [7506]=2557, [7507]=2557, [7508]=2557, [7509]=2159, [7521]=-344, [7541]=15, +[7562]=-61, [7563]=-61, [7564]=-61, [7581]=-61, [7582]=-61, [7583]=-61, [7601]=-61, [7602]=-61, +[7603]=-61, [7604]=1584, [7621]=-262, [7622]=-262, [7623]=-61, [7624]=-61, [7625]=-61, [7626]=-61, +[7627]=-61, [7628]=-61, [7629]=-61, [7630]=-61, [7631]=-61, [7632]=-261, [7633]=-261, [7634]=-261, +[7635]=-261, [7636]=-261, [7637]=-141, [7638]=-141, [7639]=-141, [7640]=-141, [7641]=-141, [7642]=-141, +[7643]=-141, [7644]=-141, [7645]=-141, [7646]=-141, [7647]=-141, [7648]=-141, [7649]=-121, [7650]=-121, +[7651]=-121, [7652]=-121, [7653]=-121, [7654]=-121, [7655]=-121, [7656]=-121, [7657]=-121, [7658]=-121, +[7659]=-121, [7666]=-141, [7667]=-82, [7668]=-82, [7701]=51, [7703]=2557, [7721]=357, [7722]=51, +[7723]=51, [7724]=51, [7725]=357, [7726]=357, [7727]=51, [7728]=51, [7729]=51, [7730]=357, +[7731]=357, [7732]=357, [7733]=357, [7734]=357, [7735]=357, [7736]=51, [7737]=51, [7738]=357, +[7761]=1583, [7781]=1519, [7782]=1519, [7783]=1637, [7784]=1637, [7785]=-344, [7786]=-344, [7787]=-344, +[7788]=3277, [7789]=3277, [7791]=1519, [7792]=1657, [7793]=1519, [7794]=1519, [7795]=1519, [7796]=1519, +[7798]=1657, [7799]=1657, [7800]=1657, [7801]=1657, [7802]=1537, [7803]=1537, [7804]=1537, [7805]=1537, +[7806]=1537, [7807]=1537, [7808]=1537, [7809]=1537, [7810]=33, [7811]=1537, [7812]=1537, [7813]=1497, +[7814]=1497, [7815]=47, [7816]=47, [7817]=1497, [7818]=1497, [7819]=1497, [7820]=1638, [7821]=1638, +[7822]=1638, [7823]=1638, [7824]=1637, [7825]=1638, [7826]=1637, [7827]=1637, [7828]=47, [7829]=47, +[7830]=47, [7831]=1637, [7832]=1637, [7833]=1637, [7834]=1637, [7835]=1637, [7836]=1637, [7837]=1637, +[7839]=47, [7840]=47, [7841]=47, [7842]=47, [7843]=47, [7844]=47, [7845]=47, [7846]=47, +[7847]=47, [7848]=2717, [7849]=47, [7850]=47, [7861]=47, [7862]=47, [7863]=3277, [7864]=3277, +[7865]=3277, [7866]=3277, [7867]=3277, [7868]=3277, [7871]=3277, [7872]=3277, [7873]=3277, [7874]=3277, +[7875]=3277, [7876]=3277, [7877]=2557, [7881]=-364, [7882]=-364, [7883]=-364, [7884]=-364, [7885]=-364, +[7886]=3277, [7887]=3277, [7888]=3277, [7889]=-364, [7890]=-364, [7891]=-364, [7892]=-364, [7893]=-364, +[7894]=-364, [7895]=-364, [7896]=-364, [7897]=-364, [7898]=-364, [7899]=-364, [7900]=-364, [7901]=-364, +[7902]=-364, [7903]=-364, [7905]=1537, [7907]=-364, [7921]=3277, [7922]=3277, [7923]=3277, [7924]=3277, +[7925]=3277, [7926]=1637, [7927]=-364, [7928]=-364, [7929]=-364, [7930]=-364, [7931]=-364, [7932]=-364, +[7933]=-364, [7934]=-364, [7935]=-364, [7936]=-364, [7937]=-364, [7938]=-364, [7939]=-364, [7940]=-364, +[7941]=-364, [7942]=-364, [7943]=-364, [7944]=-364, [7945]=-364, [7946]=-364, [7981]=-364, [8001]=3277, +[8041]=1977, [8042]=1977, [8043]=1977, [8044]=1977, [8045]=1977, [8046]=1977, [8047]=1977, [8048]=1977, +[8049]=1977, [8050]=1977, [8051]=1977, [8052]=1977, [8053]=19, [8054]=19, [8055]=19, [8056]=19, +[8057]=19, [8058]=19, [8059]=19, [8060]=19, [8061]=19, [8062]=19, [8063]=19, [8064]=19, +[8065]=19, [8066]=19, [8067]=19, [8068]=19, [8069]=19, [8070]=19, [8071]=19, [8072]=19, +[8073]=19, [8074]=19, [8075]=19, [8076]=19, [8077]=19, [8078]=19, [8079]=19, [8080]=3358, +[8081]=3358, [8101]=1977, [8102]=1977, [8103]=1977, [8104]=1977, [8105]=3358, [8106]=1977, [8107]=1977, +[8108]=1977, [8109]=1977, [8110]=1977, [8111]=1977, [8112]=1977, [8113]=1977, [8114]=3358, [8115]=3358, +[8116]=1977, [8117]=1977, [8118]=1977, [8119]=1977, [8120]=3358, [8121]=3358, [8122]=3358, [8123]=3358, +[8124]=3358, [8141]=1977, [8142]=1977, [8143]=1977, [8144]=1977, [8145]=1977, [8146]=1977, [8147]=1977, +[8148]=1977, [8149]=-22, [8150]=-22, [8151]=-261, [8153]=-261, [8154]=3358, [8155]=3358, [8156]=3358, +[8157]=3358, [8158]=3358, [8159]=3358, [8160]=3358, [8161]=3358, [8162]=3358, [8163]=3358, [8164]=3358, +[8165]=3358, [8166]=3358, [8167]=3358, [8168]=3358, [8169]=3358, [8170]=3358, [8171]=3358, [8181]=19, +[8182]=440, [8183]=33, [8184]=1977, [8185]=1977, [8186]=1977, [8187]=1977, [8188]=1977, [8189]=1977, +[8190]=1977, [8191]=1977, [8192]=1977, [8193]=-101, [8194]=-101, [8195]=19, [8196]=19, [8201]=19, +[8221]=-101, [8222]=-364, [8223]=-364, [8224]=-101, [8225]=-101, [8227]=19, [8228]=-101, [8229]=-101, +[8231]=-261, [8232]=-261, [8233]=-162, [8234]=-162, [8235]=-162, [8236]=-162, [8238]=19, [8239]=19, +[8240]=19, [8241]=51, [8242]=51, [8243]=19, [8246]=19, [8249]=-162, [8250]=-161, [8251]=-161, +[8252]=-161, [8253]=-161, [8254]=-262, [8255]=-262, [8256]=-262, [8257]=-262, [8258]=-82, [8260]=3358, +[8261]=3358, [8262]=3358, [8263]=3358, [8264]=3358, [8265]=3358, [8266]=3277, [8267]=3277, [8268]=3277, +[8269]=3277, [8271]=2597, [8272]=2597, [8273]=47, [8275]=1537, [8276]=1637, [8277]=1377, [8278]=1377, +[8279]=1377, [8280]=1377, [8281]=1377, [8282]=1377, [8283]=1377, [8284]=1377, [8285]=1377, [8286]=1377, +[8287]=1377, [8288]=2677, [8289]=3277, [8290]=3277, [8291]=3277, [8292]=3277, [8293]=3277, [8294]=3277, +[8295]=3277, [8296]=3277, [8297]=3358, [8298]=3358, [8299]=3358, [8300]=3358, [8301]=1377, [8302]=1377, +[8303]=1377, [8304]=1377, [8305]=1377, [8306]=1377, [8307]=-304, [8308]=1377, [8309]=1377, [8310]=1377, +[8311]=-22, [8312]=-22, [8313]=-304, [8314]=1377, [8315]=1377, [8316]=1377, [8317]=-304, [8318]=1377, +[8319]=1377, [8320]=1377, [8321]=1377, [8322]=-22, [8323]=1377, [8324]=1377, [8331]=1377, [8332]=1377, +[8333]=1377, [8341]=1377, [8342]=1377, [8343]=1377, [8348]=1377, [8349]=1377, [8351]=1377, [8352]=1377, +[8353]=-22, [8354]=-22, [8355]=-22, [8356]=-22, [8357]=-22, [8358]=-22, [8359]=-22, [8360]=-22, +[8361]=1377, [8362]=1377, [8363]=1377, [8364]=1377, [8365]=440, [8366]=440, [8367]=-25, [8368]=3277, +[8369]=2597, [8370]=3358, [8371]=-25, [8372]=3277, [8373]=-22, [8374]=3358, [8375]=2839, [8376]=1377, +[8377]=1377, [8378]=1377, [8379]=1377, [8380]=1377, [8381]=1377, [8382]=1377, [8383]=2839, [8384]=3358, +[8385]=-25, [8386]=3277, [8387]=2839, [8388]=1637, [8389]=3277, [8390]=3358, [8391]=3358, [8392]=3358, +[8393]=3358, [8394]=3358, [8395]=3358, [8396]=3358, [8397]=3358, [8398]=3358, [8399]=3277, [8400]=3277, +[8401]=3277, [8402]=3277, [8403]=3277, [8404]=3277, [8405]=3277, [8406]=3277, [8407]=3277, [8408]=3277, +[8409]=-22, [8410]=-82, [8411]=-82, [8412]=-82, [8413]=-82, [8414]=-141, [8415]=-141, [8416]=-141, +[8417]=-81, [8418]=-141, [8419]=-61, [8420]=-61, [8421]=-61, [8422]=-61, [8423]=-81, [8424]=-81, +[8425]=-81, [8426]=3277, [8427]=3277, [8428]=3277, [8429]=3277, [8430]=3277, [8431]=3277, [8432]=3277, +[8433]=3277, [8434]=3277, [8435]=3277, [8436]=3358, [8437]=3358, [8438]=3358, [8439]=3358, [8440]=3358, +[8441]=3358, [8442]=3358, [8443]=3358, [8446]=-1, [8447]=493, [8460]=361, [8461]=1769, [8462]=361, +[8464]=1769, [8465]=361, [8466]=361, [8467]=361, [8469]=361, [8470]=361, [8471]=618, [8481]=1769, +[8484]=1769, [8485]=1769, [8492]=-365, [8493]=-365, [8494]=-365, [8495]=-365, [8496]=1377, [8497]=1377, +[8498]=1377, [8499]=-365, [8500]=-365, [8501]=1377, [8502]=1377, [8503]=-365, [8504]=-365, [8505]=-365, +[8506]=-365, [8507]=1377, [8508]=1377, [8509]=-365, [8510]=-365, [8511]=-365, [8512]=-365, [8513]=-365, +[8514]=-365, [8515]=-365, [8516]=-365, [8517]=-365, [8518]=-365, [8519]=1377, [8520]=-365, [8521]=-365, +[8522]=-365, [8523]=-365, [8524]=-365, [8525]=-365, [8526]=-365, [8527]=-365, [8528]=-365, [8529]=-365, +[8532]=-365, [8533]=-365, [8534]=1377, [8535]=1377, [8536]=1377, [8537]=1377, [8538]=1377, [8539]=1377, +[8540]=1377, [8541]=1377, [8542]=-365, [8543]=-365, [8544]=3428, [8545]=-365, [8546]=-365, [8548]=1377, +[8549]=-365, [8550]=-365, [8551]=33, [8552]=33, [8553]=33, [8554]=33, [8555]=440, [8556]=3428, +[8557]=3428, [8558]=3428, [8559]=3428, [8560]=3428, [8561]=3428, [8562]=3428, [8572]=1377, [8573]=1377, +[8574]=1377, [8575]=16, [8576]=440, [8577]=440, [8578]=2717, [8579]=3428, [8580]=-365, [8581]=-365, +[8582]=-365, [8583]=-365, [8584]=440, [8585]=440, [8586]=440, [8587]=440, [8588]=-365, [8589]=-365, +[8590]=-365, [8591]=-365, [8592]=3428, [8593]=3428, [8594]=3428, [8595]=3428, [8596]=3428, [8597]=440, +[8598]=440, [8599]=440, [8600]=-365, [8601]=-365, [8602]=3428, [8603]=3428, [8604]=-365, [8605]=-365, +[8606]=440, [8607]=-365, [8608]=-365, [8609]=-365, [8610]=-365, [8611]=-365, [8612]=-365, [8613]=-365, +[8614]=-365, [8615]=-365, [8616]=-365, [8619]=-366, [8620]=440, [8621]=3428, [8622]=3428, [8623]=3428, +[8624]=3428, [8625]=3428, [8626]=3428, [8627]=3428, [8628]=3428, [8629]=3428, [8630]=3428, [8631]=3428, +[8632]=3428, [8633]=3428, [8634]=3428, [8635]=-366, [8636]=-366, [8637]=3428, [8638]=3428, [8639]=3428, +[8640]=3428, [8641]=3428, [8642]=-366, [8643]=-366, [8644]=-366, [8645]=-366, [8646]=-366, [8647]=-366, +[8648]=-366, [8649]=-366, [8650]=-366, [8651]=-366, [8652]=-366, [8653]=-366, [8654]=-366, [8655]=3428, +[8656]=3428, [8657]=3428, [8658]=3428, [8659]=3428, [8660]=3428, [8661]=3428, [8662]=3428, [8663]=3428, +[8664]=3428, [8665]=3428, [8666]=3428, [8667]=3428, [8668]=3428, [8669]=3428, [8670]=-366, [8671]=-366, +[8672]=-366, [8673]=-366, [8674]=-366, [8675]=-366, [8676]=-366, [8677]=-366, [8678]=-366, [8679]=-366, +[8680]=-366, [8681]=-366, [8682]=-366, [8683]=-366, [8684]=-366, [8685]=-366, [8686]=-366, [8687]=1377, +[8688]=-366, [8689]=3428, [8690]=3428, [8691]=3428, [8692]=3428, [8693]=3428, [8694]=3428, [8695]=3428, +[8696]=3428, [8697]=3428, [8698]=3428, [8699]=3428, [8700]=3428, [8701]=3428, [8702]=3428, [8703]=3428, +[8704]=3428, [8705]=3428, [8706]=3428, [8707]=3428, [8708]=3428, [8709]=3428, [8710]=3428, [8711]=3428, +[8712]=3428, [8713]=-366, [8714]=-366, [8715]=-366, [8716]=-366, [8717]=-366, [8718]=-366, [8719]=-366, +[8720]=-366, [8721]=-366, [8722]=-366, [8723]=-366, [8724]=-366, [8725]=-366, [8726]=-366, [8727]=-366, +[8728]=440, [8729]=16, [8730]=2677, [8731]=1377, [8732]=1377, [8733]=1417, [8734]=141, [8735]=493, +[8736]=493, [8737]=1377, [8738]=1377, [8739]=1377, [8740]=1377, [8741]=493, [8742]=440, [8743]=1377, +[8744]=-22, [8745]=1377, [8746]=-22, [8747]=440, [8748]=440, [8749]=440, [8750]=440, [8751]=440, +[8752]=440, [8753]=440, [8754]=440, [8755]=440, [8756]=440, [8757]=440, [8758]=440, [8759]=440, +[8760]=440, [8761]=440, [8762]=-22, [8763]=-22, [8764]=440, [8765]=440, [8766]=440, [8767]=-22, +[8768]=-22, [8769]=-22, [8770]=1377, [8771]=1377, [8772]=1377, [8773]=1377, [8774]=1377, [8775]=1377, +[8776]=1377, [8777]=1377, [8778]=1377, [8779]=1377, [8780]=1377, [8781]=1377, [8782]=1377, [8783]=1377, +[8784]=3428, [8785]=1377, [8786]=1377, [8787]=1377, [8788]=-22, [8789]=3428, [8790]=3428, [8791]=3429, +[8792]=-365, [8793]=-365, [8794]=-365, [8795]=-365, [8796]=-365, [8797]=-365, [8798]=618, [8799]=-22, +[8800]=1377, [8801]=3428, [8802]=3428, [8803]=-22, [8804]=1377, [8805]=1377, [8806]=1377, [8807]=1377, +[8808]=1377, [8809]=1377, [8810]=1377, [8811]=-367, [8812]=-367, [8813]=-367, [8814]=-367, [8815]=-367, +[8816]=-367, [8817]=-367, [8818]=-367, [8819]=-367, [8820]=-367, [8821]=-367, [8822]=-367, [8823]=-367, +[8824]=-367, [8825]=-367, [8826]=-367, [8827]=-22, [8828]=-22, [8829]=1377, [8830]=-367, [8831]=-367, +[8832]=-367, [8833]=-367, [8834]=-367, [8835]=-367, [8836]=-367, [8837]=-367, [8838]=-367, [8839]=-367, +[8840]=-367, [8841]=-367, [8842]=-367, [8843]=-367, [8844]=-367, [8845]=-367, [8846]=-365, [8847]=-365, +[8848]=-365, [8849]=-365, [8850]=-365, [8851]=-365, [8852]=-365, [8853]=-365, [8854]=-365, [8855]=-365, +[8857]=1377, [8858]=1377, [8859]=1377, [8860]=-22, [8861]=-22, [8862]=-366, [8863]=-366, [8864]=-366, +[8865]=-366, [8866]=-366, [8867]=-366, [8868]=-241, [8870]=-366, [8871]=-366, [8872]=-366, [8873]=-366, +[8874]=-366, [8875]=-366, [8876]=-366, [8877]=-366, [8878]=-366, [8879]=-366, [8880]=-366, [8881]=-366, +[8882]=-366, [8883]=-366, [8893]=440, [8897]=-22, [8898]=-22, [8899]=-22, [8900]=-22, [8901]=-22, +[8902]=-22, [8903]=-22, [8904]=-22, [8905]=1537, [8906]=1537, [8907]=1537, [8908]=1537, [8909]=1537, +[8910]=1537, [8911]=1537, [8912]=1537, [8913]=1637, [8914]=1637, [8915]=1637, [8916]=1637, [8917]=1637, +[8918]=1637, [8919]=1637, [8920]=1637, [8921]=440, [8922]=440, [8923]=440, [8924]=440, [8925]=440, +[8926]=1537, [8927]=1637, [8928]=440, [8929]=139, [8930]=139, [8931]=1537, [8932]=1537, [8933]=1537, +[8934]=1537, [8935]=1537, [8936]=1537, [8937]=1537, [8938]=1637, [8939]=1637, [8940]=1637, [8941]=1637, +[8942]=1637, [8943]=1637, [8944]=1637, [8945]=2017, [8946]=139, [8947]=139, [8948]=2557, [8949]=2557, +[8950]=2557, [8951]=1537, [8952]=1537, [8953]=1537, [8954]=1537, [8955]=1537, [8956]=1537, [8957]=1637, +[8958]=1537, [8959]=1537, [8960]=25, [8961]=25, [8962]=25, [8963]=25, [8964]=25, [8965]=25, +[8966]=1583, [8967]=2557, [8968]=2017, [8969]=2057, [8970]=2079, [8977]=1537, [8978]=1637, [8979]=-22, +[8980]=-22, [8981]=-22, [8982]=-22, [8983]=-22, [8984]=-22, [8985]=25, [8986]=25, [8987]=25, +[8988]=25, [8989]=1583, [8990]=2557, [8991]=2017, [8992]=2057, [8993]=-22, [8994]=25, [8995]=1583, +[8996]=25, [8997]=1537, [8998]=1637, [8999]=1537, [9000]=1537, [9001]=1537, [9002]=1537, [9003]=1537, +[9004]=1537, [9005]=1537, [9006]=1537, [9007]=1637, [9008]=1637, [9009]=1637, [9010]=1637, [9011]=1637, +[9012]=1637, [9013]=1637, [9014]=1637, [9015]=1584, [9016]=1637, [9017]=1637, [9018]=1637, [9019]=1637, +[9020]=1637, [9021]=1637, [9022]=1637, [9023]=1377, [9024]=-22, [9025]=-22, [9026]=-22, [9027]=-22, +[9028]=-22, [9029]=-22, [9032]=1637, [9033]=3456, [9034]=3456, [9036]=3456, [9037]=3456, [9038]=3456, +[9039]=3456, [9040]=3456, [9041]=3456, [9042]=3456, [9043]=3456, [9044]=3456, [9045]=3456, [9046]=3456, +[9047]=3456, [9048]=3456, [9049]=3456, [9050]=3456, [9051]=-263, [9052]=-263, [9053]=-263, [9054]=3456, +[9055]=3456, [9056]=3456, [9057]=3456, [9058]=3456, [9059]=3456, [9060]=3456, [9061]=3456, [9063]=-263, +[9068]=3456, [9069]=3456, [9070]=3456, [9071]=3456, [9072]=3456, [9073]=3456, [9074]=3456, [9075]=3456, +[9077]=3456, [9078]=3456, [9079]=3456, [9080]=3456, [9081]=3456, [9082]=3456, [9083]=3456, [9084]=3456, +[9085]=-368, [9086]=3456, [9087]=3456, [9088]=3456, [9089]=3456, [9090]=3456, [9091]=3456, [9092]=3456, +[9093]=3456, [9094]=-368, [9095]=3456, [9096]=3456, [9097]=3456, [9098]=3456, [9099]=3456, [9100]=3456, +[9101]=3456, [9102]=3456, [9103]=3456, [9104]=3456, [9105]=3456, [9106]=3456, [9107]=3456, [9108]=3456, +[9109]=3456, [9110]=3456, [9111]=3456, [9112]=3456, [9113]=3456, [9114]=3456, [9115]=3456, [9116]=3456, +[9117]=3456, [9118]=3456, [9120]=3456, [9121]=139, [9122]=139, [9123]=139, [9124]=139, [9125]=139, +[9126]=139, [9127]=139, [9128]=139, [9129]=139, [9131]=139, [9132]=139, [9136]=139, [9137]=139, +[9141]=139, [9142]=139, [9153]=-368, [9154]=-368, [9165]=139, [9178]=139, [9179]=139, [9181]=139, +[9182]=139, [9183]=139, [9184]=139, [9185]=139, [9186]=139, [9187]=139, [9188]=139, [9190]=139, +[9191]=139, [9194]=139, [9195]=139, [9196]=139, [9197]=139, [9198]=139, [9200]=139, [9201]=139, +[9202]=139, [9203]=139, [9204]=139, [9205]=139, [9206]=139, [9208]=1977, [9209]=1977, [9210]=1977, +[9211]=139, [9213]=139, [9221]=139, [9222]=139, [9223]=139, [9224]=139, [9225]=139, [9226]=139, +[9227]=139, [9228]=139, [9229]=3456, [9230]=3456, [9232]=3456, [9233]=3456, [9234]=3456, [9235]=3456, +[9236]=3456, [9237]=3456, [9238]=3456, [9239]=3456, [9240]=3456, [9241]=3456, [9242]=3456, [9243]=3456, +[9244]=3456, [9245]=3456, [9246]=3456, [9247]=-368, [9248]=1377, [9250]=-344, [9251]=-344, [9257]=-344, +[9259]=33, [9260]=-368, [9261]=-368, [9262]=-368, [9263]=-368, [9264]=-368, [9265]=-368, [9266]=618, +[9267]=17, [9268]=440, [9269]=-344, [9270]=-344, [9271]=-344, [9272]=33, [9292]=-368, [9295]=-368, +[9299]=-368, [9300]=-368, [9301]=-368, [9302]=-368, [9304]=-368, [9310]=-368, [9317]=-368, [9318]=-368, +[9319]=-369, [9320]=-368, [9321]=-368, [9322]=-369, [9323]=-369, [9324]=-369, [9325]=-369, [9326]=-369, +[9330]=-369, [9331]=-369, [9332]=-369, [9338]=1377, [9339]=-369, [9341]=-368, [9362]=-161, [9364]=-161, +[9365]=-369, [9367]=-369, [9368]=-369, [9378]=139, [9386]=-369, [9388]=-369, [9389]=-369, [9415]=1377, +[9416]=1377, [9419]=1377, [9422]=1377, [9664]=139, [9665]=139, [41747]=12, [41895]=12, [50003]=-162, +[60050]=12, +} +Codex.WdbRep = { +[1036]={87,3000}, [1367]={93,3000}, [1368]={92,3000}, [1369]={93,3000}, [1370]={92,3000}, [1371]={93,3000}, [1373]={92,3000}, [1374]={92,3000}, +[1375]={93,3000}, [1380]={92,3000}, [1381]={93,3000}, [1382]={92,3000}, [1384]={92,3000}, [1385]={93,3000}, [1386]={93,3000}, [4621]={87,3000}, +[5504]={529,21000}, [5507]={529,21000}, [5513]={529,21000}, [5517]={529,42000}, [5521]={529,42000}, [5524]={529,42000}, [6823]={749,9000}, [8053]={270,3000}, +[8054]={270,9000}, [8055]={270,21000}, [8056]={270,3000}, [8057]={270,3000}, [8058]={270,3000}, [8059]={270,3000}, [8060]={270,3000}, [8061]={270,3000}, +[8062]={270,3000}, [8063]={270,3000}, [8064]={270,9000}, [8065]={270,21000}, [8066]={270,9000}, [8067]={270,21000}, [8068]={270,9000}, [8069]={270,21000}, +[8070]={270,9000}, [8071]={270,21000}, [8072]={270,9000}, [8073]={270,21000}, [8074]={270,9000}, [8075]={270,21000}, [8076]={270,9000}, [8077]={270,21000}, +[8078]={270,9000}, [8079]={270,21000}, [8196]={270,9000}, [8243]={270,21000}, [8246]={270,42000}, [8481]={576,42000}, [8484]={576,42000}, [8485]={576,42000}, +[8548]={609,3000}, [8556]={609,9000}, [8557]={609,21000}, [8558]={609,42000}, [8560]={910,3000}, [8561]={910,3000}, [8562]={910,9000}, [8572]={609,9000}, +[8573]={609,42000}, [8574]={609,21000}, [8592]={910,3000}, [8593]={910,3000}, [8603]={910,9000}, [8622]={910,9000}, [8623]={910,3000}, [8624]={910,3000}, +[8627]={910,9000}, [8628]={910,3000}, [8629]={910,3000}, [8631]={910,3000}, [8632]={910,3000}, [8633]={910,9000}, [8638]={910,9000}, [8639]={910,3000}, +[8640]={910,3000}, [8656]={910,9000}, [8657]={910,3000}, [8658]={910,3000}, [8661]={910,9000}, [8662]={910,3000}, [8663]={910,3000}, [8666]={910,9000}, +[8667]={910,3000}, [8668]={910,3000}, [8689]={609,21000}, [8690]={609,21000}, [8691]={609,21000}, [8692]={609,21000}, [8693]={609,21000}, [8694]={609,21000}, +[8695]={609,21000}, [8696]={609,21000}, [8697]={609,9000}, [8698]={609,9000}, [8699]={609,9000}, [8700]={609,9000}, [8701]={609,9000}, [8702]={609,9000}, +[8703]={609,9000}, [8704]={609,9000}, [8705]={609,42000}, [8706]={609,42000}, [8707]={609,42000}, [8708]={609,42000}, [8709]={609,42000}, [8710]={609,42000}, +[8711]={609,42000}, [8712]={609,42000}, [9121]={529,9000}, [9122]={529,21000}, [9123]={529,42000}, [9236]={529,42000}, [9237]={529,42000}, [9240]={529,42000}, +[9243]={529,42000}, [9246]={529,42000}, [9248]={609,9000}, [9378]={529,42000}, +} +Codex.WdbInfo = { +[17]=81, [19]=1, [55]=1, [99]=1, [105]=1, [115]=1, [166]=81, [167]=81, +[168]=81, [169]=1, [176]=1, [193]=1, [197]=1, [202]=1, [206]=1, [208]=1, +[211]=1, [214]=81, [228]=1, [248]=1, [249]=1, [253]=1, [255]=1, [256]=1, +[271]=1, [278]=1, [303]=1, [304]=1, [314]=1, [377]=81, [378]=81, [386]=81, +[387]=81, [388]=81, [391]=81, [442]=1, [450]=1, [452]=1, [474]=1, [504]=1, +[517]=1, [518]=1, [519]=1, [520]=1, [531]=1, [540]=1, [541]=1, [543]=1, +[547]=1, [591]=1, [611]=1, [613]=1, [614]=1, [618]=1, [628]=1, [629]=1, +[630]=1, [631]=1, [639]=1, [640]=1, [643]=1, [644]=1, [645]=1, [646]=1, +[652]=1, [656]=1, [673]=1, [679]=1, [680]=1, [682]=1, [684]=1, [685]=1, +[694]=1, [695]=1, [696]=1, [697]=1, [704]=81, [705]=1, [706]=1, [709]=81, +[717]=1, [721]=81, [722]=81, [735]=1, [736]=1, [908]=1, [909]=1, [914]=81, +[959]=81, [962]=81, [969]=1, [971]=81, [1013]=81, [1014]=81, [1048]=81, [1049]=81, +[1050]=81, [1051]=1, [1053]=81, [1089]=1, [1098]=81, [1100]=1, [1101]=81, [1102]=81, +[1107]=1, [1109]=81, [1113]=81, [1139]=81, [1142]=81, [1144]=81, [1151]=1, [1160]=81, +[1166]=1, [1168]=1, [1172]=1, [1173]=1, [1193]=81, [1198]=81, [1199]=81, [1200]=81, +[1221]=81, [1275]=81, [1318]=81, [1360]=81, [1380]=1, [1381]=1, [1383]=1, [1424]=1, +[1442]=81, [1445]=81, [1446]=81, [1448]=1, [1475]=81, [1486]=81, [1487]=81, [1488]=1, +[1489]=81, [1490]=81, [1491]=81, [1653]=81, [1654]=81, [1655]=1, [1657]=41, [1658]=41, +[1701]=1, [1713]=1, [1740]=81, [1951]=81, [1955]=1, [1956]=81, [2040]=81, [2078]=1, +[2198]=81, [2199]=81, [2200]=81, [2201]=81, [2202]=81, [2203]=1, [2204]=81, [2240]=81, +[2278]=81, [2280]=81, [2283]=81, [2284]=81, [2318]=81, [2338]=81, [2339]=81, [2340]=81, +[2341]=81, [2342]=81, [2359]=1, [2361]=81, [2398]=81, [2418]=81, [2478]=1, [2499]=1, +[2501]=1, [2721]=1, [2768]=81, [2769]=81, [2770]=81, [2841]=81, [2842]=81, [2843]=81, +[2846]=81, [2861]=81, [2864]=81, [2865]=81, [2904]=81, [2922]=81, [2923]=81, [2924]=81, +[2925]=81, [2926]=81, [2927]=81, [2928]=81, [2929]=81, [2930]=81, [2931]=81, [2935]=1, +[2936]=81, [2937]=1, [2944]=1, [2945]=81, [2946]=1, [2947]=81, [2949]=81, [2951]=81, +[2952]=81, [2953]=81, [2954]=1, [2962]=81, [2966]=1, [2967]=1, [2977]=1, [2991]=81, +[2993]=1, [2994]=1, [3042]=81, [3062]=1, [3126]=1, [3127]=1, [3128]=1, [3181]=1, +[3182]=1, [3201]=1, [3341]=81, [3372]=1, [3373]=81, [3380]=81, [3385]=1, [3446]=81, +[3447]=81, [3452]=1, [3463]=1, [3510]=1, [3514]=1, [3523]=81, [3525]=81, [3527]=81, +[3528]=81, [3566]=1, [3602]=1, [3627]=1, [3628]=1, [3636]=81, [3801]=81, [3802]=81, +[3906]=81, [3907]=81, [3962]=1, [3981]=81, [3982]=81, [4001]=81, [4002]=81, [4003]=81, +[4004]=81, [4021]=1, [4023]=1, [4024]=81, [4063]=81, [4081]=81, [4082]=81, [4083]=81, +[4121]=81, [4122]=81, [4123]=81, [4126]=81, [4128]=81, [4132]=81, [4133]=81, [4134]=81, +[4136]=81, [4143]=81, [4146]=1, [4148]=81, [4182]=1, [4201]=81, [4241]=81, [4242]=81, +[4262]=81, [4263]=81, [4264]=81, [4282]=81, [4286]=81, [4295]=81, [4322]=81, [4324]=81, +[4341]=81, [4342]=81, [4361]=81, [4362]=81, [4363]=81, [4601]=81, [4602]=81, [4603]=81, +[4604]=81, [4605]=81, [4606]=81, [4701]=81, [4724]=81, [4729]=81, [4734]=62, [4735]=62, +[4742]=81, [4743]=81, [4764]=62, [4766]=62, [4768]=62, [4769]=62, [4771]=81, [4787]=1, +[4788]=81, [4862]=81, [4866]=81, [4867]=81, [4903]=81, [4907]=62, [4961]=1, [4974]=62, +[4981]=81, [4982]=81, [4983]=81, [5001]=81, [5002]=81, [5047]=81, [5054]=1, [5055]=1, +[5056]=1, [5063]=1, [5065]=1, [5067]=1, [5068]=1, [5081]=81, [5088]=1, [5089]=81, +[5098]=1, [5102]=62, [5103]=81, [5121]=1, [5122]=81, [5124]=1, [5125]=81, [5127]=81, +[5151]=1, [5153]=1, [5156]=1, [5160]=81, [5162]=1, [5164]=1, [5166]=1, [5167]=1, +[5168]=1, [5212]=81, [5213]=81, [5214]=81, [5243]=81, [5247]=1, [5251]=81, [5262]=81, +[5263]=81, [5264]=1, [5265]=1, [5281]=81, [5282]=81, [5305]=81, [5306]=81, [5307]=81, +[5341]=81, [5342]=41, [5343]=81, [5344]=41, [5382]=81, [5384]=81, [5461]=1, [5462]=1, +[5463]=81, [5464]=1, [5465]=1, [5466]=81, [5515]=81, [5518]=81, [5519]=81, [5522]=81, +[5525]=81, [5526]=81, [5528]=81, [5529]=81, [5531]=81, [5582]=81, [5721]=62, [5722]=81, +[5723]=81, [5724]=81, [5725]=81, [5728]=81, [5761]=81, [5803]=1, [5804]=1, [5848]=81, +[5862]=1, [5944]=1, [5981]=1, [6025]=1, [6041]=1, [6135]=1, [6136]=1, [6145]=1, +[6146]=1, [6147]=1, [6148]=1, [6163]=81, [6182]=1, [6183]=1, [6184]=1, [6185]=1, +[6186]=1, [6187]=62, [6283]=1, [6284]=1, [6402]=62, [6403]=62, [6481]=1, [6501]=62, +[6502]=62, [6521]=81, [6522]=81, [6561]=81, [6562]=81, [6563]=81, [6564]=81, [6565]=81, +[6569]=62, [6570]=1, [6582]=62, [6583]=62, [6584]=62, [6585]=62, [6602]=62, [6626]=81, +[6642]=81, [6643]=81, [6644]=81, [6645]=81, [6646]=81, [6781]=41, [6801]=41, [6821]=62, +[6822]=62, [6824]=62, [6825]=41, [6826]=41, [6827]=41, [6881]=41, [6901]=41, [6921]=81, +[6922]=81, [6941]=41, [6942]=41, [6943]=41, [6983]=1, [7001]=41, [7002]=41, [7026]=41, +[7027]=41, [7028]=81, [7029]=81, [7041]=81, [7043]=1, [7044]=81, [7046]=81, [7064]=81, +[7065]=81, [7066]=81, [7067]=81, [7068]=81, [7070]=81, [7081]=41, [7082]=41, [7101]=41, +[7102]=41, [7121]=41, [7122]=41, [7123]=41, [7124]=41, [7141]=41, [7142]=41, [7181]=62, +[7201]=81, [7202]=62, [7223]=41, [7224]=41, [7241]=41, [7261]=41, [7281]=62, [7282]=62, +[7301]=41, [7302]=41, [7361]=41, [7362]=41, [7363]=41, [7364]=41, [7365]=41, [7366]=41, +[7367]=62, [7368]=62, [7381]=62, [7382]=62, [7385]=41, [7386]=41, [7401]=41, [7402]=41, +[7421]=41, [7422]=41, [7423]=41, [7424]=41, [7425]=41, [7426]=41, [7427]=41, [7428]=41, +[7429]=81, [7441]=81, [7461]=81, [7462]=81, [7463]=81, [7478]=81, [7479]=81, [7480]=81, +[7481]=81, [7482]=81, [7483]=81, [7484]=81, [7485]=81, [7487]=81, [7488]=81, [7489]=81, +[7492]=81, [7494]=81, [7498]=81, [7499]=81, [7500]=81, [7501]=81, [7502]=81, [7503]=81, +[7504]=81, [7505]=81, [7506]=81, [7507]=81, [7508]=81, [7509]=62, [7521]=62, [7581]=81, +[7582]=1, [7583]=1, [7603]=1, [7604]=81, [7629]=81, [7631]=81, [7634]=62, [7635]=62, +[7636]=1, [7642]=81, [7643]=81, [7647]=81, [7649]=81, [7650]=81, [7651]=81, [7666]=81, +[7668]=81, [7701]=1, [7703]=81, [7737]=81, [7761]=81, [7786]=62, [7788]=41, [7789]=41, +[7810]=41, [7816]=1, [7841]=41, [7842]=41, [7843]=41, [7845]=1, [7846]=1, [7847]=1, +[7848]=81, [7849]=1, [7850]=1, [7861]=1, [7862]=1, [7863]=41, [7864]=41, [7865]=41, +[7866]=41, [7867]=41, [7868]=41, [7871]=41, [7872]=41, [7873]=41, [7874]=41, [7875]=41, +[7876]=41, [7877]=81, [7886]=41, [7887]=41, [7888]=41, [7921]=41, [7922]=41, [7923]=41, +[7924]=41, [7925]=41, [8001]=41, [8041]=62, [8042]=62, [8043]=62, [8044]=62, [8045]=62, +[8046]=62, [8047]=62, [8048]=62, [8049]=62, [8050]=62, [8051]=62, [8052]=62, [8053]=62, +[8054]=62, [8055]=62, [8056]=62, [8057]=62, [8058]=62, [8059]=62, [8060]=62, [8061]=62, +[8062]=62, [8063]=62, [8064]=62, [8065]=62, [8066]=62, [8067]=62, [8068]=62, [8069]=62, +[8070]=62, [8071]=62, [8072]=62, [8073]=62, [8074]=62, [8075]=62, [8076]=62, [8077]=62, +[8078]=62, [8079]=62, [8080]=41, [8081]=41, [8101]=62, [8102]=62, [8103]=62, [8104]=62, +[8105]=41, [8106]=62, [8107]=62, [8108]=62, [8109]=62, [8110]=62, [8111]=62, [8112]=62, +[8113]=62, [8114]=41, [8115]=41, [8116]=62, [8117]=62, [8118]=62, [8119]=62, [8120]=41, +[8121]=41, [8122]=41, [8123]=41, [8124]=41, [8141]=62, [8142]=62, [8143]=62, [8144]=62, +[8145]=62, [8146]=62, [8147]=62, [8148]=62, [8154]=41, [8155]=41, [8156]=41, [8157]=41, +[8158]=41, [8159]=41, [8160]=41, [8161]=41, [8162]=41, [8163]=41, [8164]=41, [8165]=41, +[8166]=41, [8167]=41, [8168]=41, [8169]=41, [8170]=41, [8171]=41, [8181]=62, [8182]=62, +[8184]=62, [8185]=62, [8186]=62, [8187]=62, [8188]=62, [8189]=62, [8190]=62, [8191]=62, +[8192]=62, [8201]=62, [8227]=62, [8232]=81, [8236]=81, [8253]=81, [8257]=81, [8258]=81, +[8260]=41, [8261]=41, [8262]=41, [8263]=41, [8264]=41, [8265]=41, [8271]=62, [8272]=62, +[8283]=1, [8288]=62, [8289]=41, [8290]=41, [8291]=41, [8292]=41, [8293]=41, [8294]=41, +[8295]=41, [8296]=41, [8297]=41, [8298]=41, [8299]=41, [8300]=41, [8301]=1, [8302]=1, +[8304]=1, [8306]=1, [8308]=1, [8309]=1, [8310]=1, [8314]=1, [8315]=62, [8316]=62, +[8322]=41, [8331]=1, [8332]=1, [8341]=1, [8348]=1, [8349]=1, [8351]=62, [8352]=62, +[8361]=1, [8362]=1, [8363]=1, [8364]=62, [8367]=41, [8368]=41, [8369]=41, [8370]=41, +[8371]=41, [8372]=41, [8373]=41, [8374]=41, [8375]=41, [8376]=62, [8377]=62, [8378]=62, +[8379]=62, [8380]=62, [8381]=62, [8382]=62, [8383]=41, [8384]=41, [8385]=41, [8386]=41, +[8387]=41, [8388]=41, [8389]=41, [8390]=41, [8391]=41, [8392]=41, [8393]=41, [8394]=41, +[8395]=41, [8396]=41, [8397]=41, [8398]=41, [8399]=41, [8400]=41, [8401]=41, [8402]=41, +[8403]=41, [8404]=41, [8405]=41, [8406]=41, [8407]=41, [8408]=41, [8409]=41, [8413]=81, +[8418]=81, [8422]=81, [8425]=81, [8426]=41, [8427]=41, [8428]=41, [8429]=41, [8430]=41, +[8431]=41, [8432]=41, [8433]=41, [8434]=41, [8435]=41, [8436]=41, [8437]=41, [8438]=41, +[8439]=41, [8440]=41, [8441]=41, [8442]=41, [8443]=41, [8481]=1, [8493]=41, [8495]=41, +[8498]=1, [8500]=41, [8501]=1, [8502]=1, [8504]=41, [8506]=41, [8507]=1, [8510]=41, +[8512]=41, [8514]=41, [8516]=41, [8518]=41, [8521]=41, [8523]=41, [8525]=41, [8527]=41, +[8529]=41, [8533]=41, [8534]=1, [8535]=1, [8536]=1, [8537]=1, [8538]=1, [8539]=1, +[8543]=41, [8544]=62, [8546]=41, [8550]=41, [8551]=1, [8554]=1, [8556]=62, [8557]=62, +[8558]=62, [8559]=62, [8560]=62, [8561]=62, [8562]=62, [8578]=62, [8579]=62, [8581]=41, +[8583]=41, [8585]=62, [8589]=41, [8591]=41, [8592]=62, [8593]=62, [8594]=62, [8595]=62, +[8596]=62, [8601]=41, [8602]=62, [8603]=62, [8605]=41, [8606]=1, [8608]=41, [8610]=41, +[8612]=41, [8614]=41, [8616]=41, [8620]=62, [8621]=62, [8622]=62, [8623]=62, [8624]=62, +[8625]=62, [8626]=62, [8627]=62, [8628]=62, [8629]=62, [8630]=62, [8631]=62, [8632]=62, +[8633]=62, [8634]=62, [8637]=62, [8638]=62, [8639]=62, [8640]=62, [8641]=62, [8655]=62, +[8656]=62, [8657]=62, [8658]=62, [8659]=62, [8660]=62, [8661]=62, [8662]=62, [8663]=62, +[8664]=62, [8665]=62, [8666]=62, [8667]=62, [8668]=62, [8669]=62, [8687]=1, [8689]=62, +[8690]=62, [8691]=62, [8692]=62, [8693]=62, [8694]=62, [8695]=62, [8696]=62, [8697]=62, +[8698]=62, [8699]=62, [8700]=62, [8701]=62, [8702]=62, [8703]=62, [8704]=62, [8705]=62, +[8706]=62, [8707]=62, [8708]=62, [8709]=62, [8710]=62, [8711]=62, [8712]=62, [8729]=62, +[8730]=62, [8731]=1, [8735]=62, [8736]=62, [8737]=1, [8738]=1, [8739]=1, [8740]=1, +[8743]=82, [8770]=1, [8771]=1, [8772]=1, [8773]=1, [8774]=1, [8775]=1, [8776]=1, +[8777]=1, [8789]=62, [8790]=62, [8791]=62, [8829]=1, [8846]=41, [8847]=41, [8849]=41, +[8850]=41, [8851]=41, [8852]=41, [8854]=41, [8855]=41, [8868]=62, [8905]=81, [8906]=81, +[8907]=81, [8908]=81, [8909]=81, [8910]=81, [8911]=81, [8912]=81, [8913]=81, [8914]=81, +[8915]=81, [8916]=81, [8917]=81, [8918]=81, [8919]=81, [8920]=81, [8926]=81, [8927]=81, +[8928]=1, [8931]=81, [8932]=81, [8933]=81, [8934]=81, [8935]=81, [8936]=81, [8937]=81, +[8938]=81, [8939]=81, [8940]=81, [8941]=81, [8942]=81, [8943]=81, [8944]=81, [8945]=81, +[8948]=81, [8949]=81, [8950]=81, [8951]=81, [8952]=81, [8953]=81, [8954]=81, [8955]=81, +[8956]=81, [8957]=81, [8958]=81, [8959]=81, [8961]=62, [8962]=1, [8963]=1, [8964]=1, +[8965]=1, [8966]=81, [8967]=81, [8968]=81, [8969]=81, [8970]=1, [8985]=1, [8986]=1, +[8987]=1, [8988]=1, [8989]=81, [8990]=81, [8991]=81, [8992]=81, [8994]=62, [8995]=62, +[8999]=81, [9000]=81, [9001]=81, [9002]=81, [9003]=81, [9004]=81, [9005]=81, [9006]=81, +[9007]=81, [9008]=81, [9009]=81, [9010]=81, [9011]=81, [9012]=81, [9013]=81, [9014]=81, +[9015]=81, [9016]=81, [9017]=81, [9018]=81, [9019]=81, [9020]=81, [9021]=81, [9022]=81, +[9023]=62, [9033]=62, [9034]=62, [9036]=62, [9037]=62, [9038]=62, [9039]=62, [9040]=62, +[9041]=62, [9042]=62, [9043]=62, [9044]=62, [9045]=62, [9046]=62, [9047]=62, [9048]=62, +[9049]=62, [9050]=62, [9051]=1, [9053]=81, [9054]=62, [9055]=62, [9056]=62, [9057]=62, +[9058]=62, [9059]=62, [9060]=62, [9061]=62, [9068]=62, [9069]=62, [9070]=62, [9071]=62, +[9072]=62, [9073]=62, [9074]=62, [9075]=62, [9077]=62, [9078]=62, [9079]=62, [9080]=62, +[9081]=62, [9082]=62, [9083]=62, [9084]=62, [9085]=1, [9086]=62, [9087]=62, [9088]=62, +[9089]=62, [9090]=62, [9091]=62, [9092]=62, [9093]=62, [9095]=62, [9096]=62, [9097]=62, +[9098]=62, [9099]=62, [9100]=62, [9101]=62, [9102]=62, [9103]=62, [9104]=62, [9105]=62, +[9106]=62, [9107]=62, [9108]=62, [9109]=62, [9110]=62, [9111]=62, [9112]=62, [9113]=62, +[9114]=62, [9115]=62, [9116]=62, [9117]=62, [9118]=62, [9208]=62, [9209]=62, [9210]=62, +[9229]=62, [9230]=62, [9232]=62, [9233]=62, [9234]=62, [9235]=62, [9236]=62, [9237]=62, +[9238]=62, [9239]=62, [9240]=62, [9241]=62, [9242]=62, [9243]=62, [9244]=62, [9245]=62, +[9246]=62, [9250]=62, [9251]=62, [9257]=81, [9269]=81, [9270]=81, [9271]=81, [9419]=41, +[9422]=41, [9664]=41, [9665]=41, +} +Codex.WdbLevel = { +[2]=30, [5]=20, [6]=5, [7]=2, [8]=5, [9]=15, [10]=48, [11]=10, +[12]=12, [13]=14, [14]=17, [15]=3, [16]=1, [17]=42, [18]=4, [19]=25, +[20]=21, [21]=5, [22]=12, [23]=24, [24]=27, [25]=25, [26]=16, [27]=16, +[28]=16, [29]=16, [30]=16, [31]=16, [32]=48, [33]=2, [34]=24, [35]=10, +[36]=10, [37]=10, [38]=13, [39]=10, [40]=10, [45]=10, [46]=10, [47]=7, +[48]=44, [49]=44, [50]=44, [51]=44, [52]=10, [53]=44, [54]=5, [55]=32, +[56]=24, [57]=26, [58]=30, [59]=10, [60]=7, [61]=7, [62]=7, [63]=23, +[64]=12, [65]=18, [66]=28, [67]=28, [68]=28, [69]=28, [70]=28, [71]=10, +[72]=28, [74]=28, [75]=28, [76]=10, [77]=48, [78]=28, [79]=28, [80]=28, +[81]=48, [82]=47, [83]=9, [84]=6, [85]=6, [86]=6, [87]=8, [88]=9, +[89]=20, [90]=25, [91]=23, [92]=18, [93]=20, [94]=21, [95]=25, [96]=23, +[97]=28, [98]=35, [99]=15, [100]=23, [101]=25, [102]=14, [103]=16, [104]=20, +[105]=60, [106]=6, [107]=6, [109]=10, [110]=48, [111]=6, [112]=7, [113]=48, +[114]=7, [115]=23, [116]=15, [117]=15, [118]=18, [119]=18, [120]=14, [121]=14, +[122]=18, [123]=10, [124]=20, [125]=16, [126]=25, [127]=21, [128]=25, [129]=15, +[130]=15, [131]=15, [132]=18, [133]=27, [134]=30, [135]=18, [136]=16, [138]=16, +[139]=16, [140]=16, [141]=18, [142]=18, [143]=14, [144]=14, [145]=18, [146]=18, +[147]=10, [148]=24, [149]=24, [150]=20, [151]=14, [152]=19, [153]=15, [154]=24, +[155]=18, [156]=24, [157]=24, [158]=24, [159]=24, [160]=30, [161]=18, [162]=49, +[163]=20, [164]=23, [165]=25, [166]=22, [167]=20, [168]=18, [169]=26, [170]=2, +[171]=60, [172]=60, [173]=28, [174]=25, [175]=25, [176]=11, [177]=25, [178]=23, +[179]=1, [180]=26, [181]=30, [182]=4, [183]=3, [184]=9, [185]=31, [186]=33, +[187]=35, [188]=37, [189]=35, [190]=31, [191]=33, [192]=38, [193]=40, [194]=34, +[195]=36, [196]=41, [197]=43, [198]=32, [199]=18, [200]=35, [201]=32, [202]=40, +[203]=33, [204]=34, [205]=40, [206]=46, [207]=38, [208]=43, [209]=42, [210]=37, +[211]=60, [212]=40, [213]=36, [214]=17, [215]=33, [216]=24, [217]=17, [218]=5, +[219]=25, [220]=23, [221]=29, [222]=31, [223]=31, [224]=12, [225]=35, [226]=21, +[227]=35, [228]=35, [229]=35, [230]=25, [231]=35, [232]=45, [233]=3, [234]=4, +[235]=20, [236]=21, [237]=15, [238]=45, [239]=10, [240]=20, [243]=46, [244]=16, +[245]=21, [246]=17, [247]=30, [248]=22, [249]=27, [250]=18, [251]=30, [252]=30, +[253]=30, [254]=35, [255]=19, [256]=22, [257]=16, [258]=17, [261]=39, [262]=25, +[263]=15, [264]=15, [265]=25, [266]=25, [267]=12, [268]=25, [269]=29, [270]=29, +[271]=20, [272]=16, [273]=15, [274]=18, [275]=26, [276]=21, [277]=23, [278]=18, +[279]=22, [280]=18, [281]=25, [282]=5, [283]=20, [284]=25, [285]=25, [286]=25, +[287]=9, [288]=27, [289]=29, [290]=30, [291]=10, [292]=30, [293]=30, [294]=24, +[295]=27, [296]=29, [297]=18, [298]=15, [299]=28, [301]=15, [302]=15, [303]=30, +[304]=34, [305]=24, [306]=24, [307]=15, [308]=7, [309]=15, [310]=6, [311]=7, +[312]=12, [313]=7, [314]=12, [315]=9, [317]=6, [318]=7, [319]=8, [320]=8, +[321]=29, [322]=29, [323]=28, [324]=29, [325]=29, [328]=37, [329]=37, [330]=37, +[331]=37, [332]=2, [333]=2, [334]=2, [335]=30, [336]=30, [337]=25, [338]=40, +[339]=40, [340]=40, [341]=40, [342]=40, [343]=24, [344]=24, [345]=24, [346]=24, +[347]=24, [348]=45, [349]=35, [350]=31, [351]=48, [353]=15, [354]=11, [355]=10, +[356]=11, [357]=8, [358]=8, [359]=9, [360]=9, [361]=7, [362]=10, [363]=1, +[364]=2, [365]=7, [366]=8, [367]=6, [368]=9, [369]=11, [370]=9, [371]=10, +[372]=12, [373]=22, [374]=7, [375]=8, [376]=2, [377]=26, [378]=27, [379]=46, +[380]=4, [381]=4, [382]=5, [383]=5, [384]=7, [385]=15, [386]=25, [387]=26, +[388]=26, [389]=22, [391]=29, [392]=29, [393]=29, [394]=31, [395]=31, [396]=31, +[397]=30, [398]=10, [399]=15, [400]=5, [401]=30, [403]=1, [404]=6, [405]=8, +[407]=7, [408]=13, [409]=12, [410]=10, [411]=12, [412]=10, [413]=10, [414]=10, +[415]=10, [416]=11, [417]=11, [418]=11, [419]=10, [420]=5, [421]=10, [422]=11, +[423]=14, [424]=15, [425]=12, [426]=8, [427]=8, [428]=12, [429]=11, [430]=11, +[431]=10, [432]=9, [433]=11, [434]=31, [435]=11, [436]=18, [437]=14, [438]=16, +[439]=16, [440]=16, [441]=16, [442]=24, [443]=17, [444]=17, [445]=10, [446]=16, +[447]=12, [448]=16, [449]=11, [450]=15, [451]=18, [452]=15, [453]=25, [454]=15, +[455]=21, [456]=2, [457]=3, [458]=1, [459]=3, [460]=17, [461]=18, [463]=21, +[464]=28, [465]=31, [466]=22, [467]=23, [468]=21, [469]=21, [470]=24, [471]=26, +[472]=25, [473]=28, [474]=32, [475]=6, [476]=6, [477]=14, [478]=14, [479]=16, +[480]=22, [481]=14, [482]=14, [483]=9, [484]=22, [485]=48, [486]=12, [487]=8, +[488]=5, [489]=7, [491]=18, [492]=11, [493]=20, [494]=20, [495]=39, [496]=22, +[498]=22, [499]=22, [500]=36, [501]=24, [502]=24, [503]=36, [504]=40, [505]=33, +[506]=36, [507]=42, [508]=40, [509]=28, [510]=34, [511]=34, [512]=36, [513]=28, +[514]=34, [515]=30, [516]=21, [517]=30, [518]=39, [519]=41, [520]=43, [521]=43, +[522]=38, [523]=40, [524]=30, [525]=34, [526]=29, [527]=24, [528]=25, [529]=26, +[530]=20, [531]=20, [532]=26, [533]=34, [535]=34, [536]=30, [537]=40, [538]=38, +[539]=28, [540]=38, [541]=30, [542]=38, [543]=40, [544]=34, [545]=35, [546]=25, +[547]=30, [549]=22, [550]=32, [551]=40, [552]=33, [553]=33, [554]=40, [555]=31, +[556]=32, [557]=34, [558]=60, [559]=32, [560]=32, [561]=32, [562]=32, [563]=32, +[564]=34, [565]=34, [566]=40, [567]=28, [568]=36, [569]=37, [570]=38, [571]=41, +[572]=41, [573]=44, [574]=38, [575]=31, [576]=42, [577]=36, [578]=37, [579]=1, +[580]=50, [581]=34, [582]=37, [583]=30, [584]=41, [585]=40, [586]=46, [587]=41, +[588]=45, [589]=45, [590]=5, [591]=46, [592]=46, [593]=46, [594]=45, [595]=41, +[596]=37, [597]=41, [598]=42, [599]=41, [600]=41, [601]=37, [602]=37, [603]=37, +[604]=43, [605]=35, [606]=41, [607]=41, [608]=45, [609]=44, [610]=39, [611]=40, +[613]=44, [614]=47, [615]=50, [616]=37, [617]=43, [618]=50, [619]=52, [621]=44, +[622]=37, [623]=43, [624]=43, [625]=43, [626]=51, [627]=37, [628]=38, [629]=37, +[630]=51, [631]=31, [632]=31, [633]=31, [634]=31, [635]=35, [636]=35, [637]=30, +[638]=37, [639]=37, [640]=40, [641]=40, [642]=37, [643]=41, [644]=42, [645]=42, +[646]=42, [647]=30, [648]=48, [649]=48, [650]=48, [651]=38, [652]=42, [653]=40, +[654]=46, [655]=34, [656]=50, [657]=36, [658]=36, [659]=33, [660]=37, [661]=37, +[662]=40, [663]=35, [664]=40, [665]=40, [666]=40, [667]=44, [668]=40, [669]=40, +[670]=40, [671]=33, [672]=34, [673]=40, [674]=34, [675]=34, [676]=32, [677]=32, +[678]=38, [679]=40, [680]=40, [681]=31, [682]=37, [683]=30, [684]=39, [685]=40, +[686]=30, [687]=40, [688]=40, [689]=31, [690]=32, [691]=36, [692]=41, [693]=39, +[694]=39, [695]=39, [696]=39, [697]=39, [698]=40, [699]=42, [700]=31, [701]=37, +[702]=37, [703]=40, [704]=38, [705]=37, [706]=45, [707]=37, [708]=40, [709]=40, +[710]=37, [711]=39, [712]=42, [713]=37, [714]=37, [715]=37, [716]=42, [717]=50, +[718]=38, [719]=35, [720]=35, [721]=35, [722]=40, [723]=40, [724]=40, [725]=40, +[726]=40, [727]=40, [728]=40, [729]=20, [730]=14, [731]=20, [732]=43, [733]=40, +[734]=42, [735]=44, [736]=44, [737]=40, [738]=38, [739]=42, [741]=20, [742]=20, +[743]=8, [744]=11, [745]=6, [746]=8, [747]=2, [748]=5, [749]=8, [750]=3, +[751]=8, [752]=2, [753]=3, [754]=6, [755]=3, [756]=7, [757]=4, [758]=8, +[759]=10, [760]=10, [804]=5, [805]=5, [806]=12, [807]=10, [808]=9, [809]=13, +[810]=5, [811]=8, [812]=9, [813]=9, [814]=6, [815]=8, [816]=11, [817]=8, +[818]=7, [819]=15, [820]=10, [821]=15, [822]=24, [823]=7, [824]=27, [825]=8, +[826]=10, [827]=12, [828]=12, [829]=12, [830]=7, [831]=7, [832]=12, [833]=10, +[834]=9, [835]=11, [836]=48, [837]=10, [838]=55, [840]=12, [841]=46, [842]=12, +[843]=23, [844]=12, [845]=13, [846]=26, [847]=37, [848]=15, [849]=26, [850]=16, +[851]=18, [852]=19, [853]=15, [854]=12, [855]=14, [857]=30, [858]=18, [860]=10, +[861]=10, [862]=23, [863]=18, [864]=46, [865]=18, [866]=16, [867]=15, [868]=22, +[869]=13, [870]=13, [871]=12, [872]=15, [873]=27, [874]=27, [875]=16, [876]=20, +[877]=16, [878]=21, [879]=25, [880]=16, [881]=16, [882]=19, [883]=22, [884]=24, +[885]=25, [886]=10, [887]=14, [888]=16, [889]=20, [890]=14, [891]=20, [892]=14, +[893]=24, [894]=14, [895]=16, [896]=18, [897]=24, [898]=20, [899]=20, [900]=14, +[901]=14, [902]=16, [903]=15, [905]=17, [906]=25, [907]=18, [908]=27, [909]=30, +[910]=60, [911]=60, [913]=20, [914]=22, [915]=60, [916]=4, [917]=5, [918]=7, +[919]=7, [920]=5, [921]=5, [922]=7, [923]=9, [924]=14, [925]=60, [926]=14, +[927]=12, [928]=5, [929]=5, [930]=10, [931]=10, [932]=7, [933]=9, [934]=11, +[935]=11, [936]=50, [937]=11, [938]=12, [939]=54, [940]=11, [941]=12, [942]=20, +[943]=24, [944]=17, [945]=18, [947]=17, [948]=17, [949]=17, [950]=17, [951]=20, +[952]=11, [953]=12, [954]=12, [955]=12, [956]=13, [957]=13, [958]=12, [959]=18, +[960]=1, [961]=1, [962]=18, [963]=16, [964]=57, [965]=18, [966]=18, [967]=18, +[968]=20, [969]=60, [970]=21, [971]=23, [972]=20, [973]=24, [974]=55, [975]=60, +[976]=24, [977]=58, [978]=55, [979]=57, [980]=55, [981]=31, [982]=17, [983]=10, +[984]=14, [985]=14, [986]=20, [990]=19, [991]=19, [992]=46, [993]=20, [994]=22, +[995]=20, [996]=55, [997]=5, [998]=55, [1000]=55, [1001]=12, [1002]=14, [1003]=16, +[1004]=55, [1007]=20, [1008]=19, [1009]=25, [1010]=20, [1011]=29, [1012]=32, [1013]=26, +[1014]=27, [1015]=55, [1016]=24, [1017]=25, [1018]=55, [1019]=55, [1020]=20, [1021]=32, +[1022]=30, [1023]=21, [1024]=21, [1025]=24, [1026]=27, [1027]=28, [1028]=28, [1029]=28, +[1030]=28, [1031]=32, [1032]=32, [1033]=22, [1034]=23, [1035]=30, [1036]=60, [1037]=30, +[1038]=30, [1039]=30, [1040]=30, [1041]=30, [1042]=30, [1043]=30, [1044]=30, [1045]=30, +[1046]=30, [1047]=55, [1048]=42, [1049]=38, [1050]=38, [1051]=33, [1052]=40, [1053]=40, +[1054]=25, [1055]=28, [1056]=18, [1057]=27, [1058]=26, [1059]=27, [1060]=20, [1061]=17, +[1062]=19, [1063]=18, [1064]=18, [1065]=18, [1066]=23, [1067]=23, [1068]=23, [1069]=20, +[1070]=21, [1071]=21, [1072]=21, [1073]=21, [1074]=21, [1075]=21, [1076]=21, [1077]=21, +[1078]=26, [1079]=22, [1080]=22, [1081]=28, [1082]=22, [1083]=26, [1084]=28, [1085]=21, +[1086]=23, [1087]=25, [1088]=29, [1089]=29, [1090]=22, [1091]=22, [1092]=22, [1093]=21, +[1094]=21, [1095]=27, [1096]=27, [1097]=15, [1098]=25, [1100]=34, [1101]=34, [1102]=34, +[1103]=23, [1104]=30, [1105]=30, [1106]=35, [1107]=35, [1108]=39, [1109]=33, [1110]=31, +[1111]=36, [1112]=36, [1113]=33, [1114]=36, [1115]=36, [1116]=36, [1117]=36, [1118]=43, +[1119]=44, [1120]=44, [1121]=44, [1122]=44, [1123]=55, [1124]=55, [1125]=55, [1126]=57, +[1127]=44, [1130]=30, [1131]=30, [1132]=20, [1133]=20, [1134]=21, [1135]=30, [1136]=37, +[1137]=38, [1138]=17, [1139]=45, [1140]=28, [1141]=14, [1142]=30, [1143]=31, [1144]=30, +[1145]=33, [1146]=33, [1147]=35, [1148]=35, [1149]=26, [1150]=30, [1151]=30, [1152]=30, +[1153]=29, [1154]=30, [1157]=60, [1158]=60, [1159]=30, [1160]=36, [1164]=36, [1166]=43, +[1167]=28, [1168]=43, [1169]=43, [1170]=43, [1171]=43, [1172]=45, [1173]=45, [1175]=33, +[1176]=30, [1177]=36, [1178]=37, [1179]=30, [1180]=37, [1181]=37, [1182]=37, [1183]=37, +[1184]=35, [1185]=57, [1186]=37, [1187]=41, [1188]=41, [1189]=41, [1190]=41, [1191]=41, +[1192]=42, [1193]=60, [1194]=41, [1195]=25, [1196]=29, [1197]=29, [1198]=24, [1199]=25, +[1200]=27, [1201]=35, [1202]=35, [1203]=35, [1204]=38, [1205]=45, [1206]=35, [1218]=35, +[1219]=35, [1220]=35, [1221]=26, [1222]=37, [1238]=35, [1239]=35, [1240]=35, [1241]=28, +[1242]=28, [1243]=28, [1244]=30, [1245]=30, [1246]=31, [1247]=31, [1248]=33, [1249]=33, +[1250]=33, [1251]=35, [1252]=40, [1253]=35, [1258]=40, [1259]=40, [1260]=38, [1261]=40, +[1262]=40, [1264]=33, [1265]=35, [1266]=36, [1267]=38, [1268]=35, [1269]=37, [1270]=37, +[1271]=37, [1273]=37, [1274]=28, [1275]=24, [1276]=37, [1282]=35, [1284]=35, [1285]=38, +[1286]=38, [1287]=38, [1288]=38, [1289]=38, [1301]=35, [1302]=35, [1318]=60, [1319]=35, +[1320]=35, [1321]=35, [1322]=37, [1323]=37, [1324]=38, [1338]=14, [1339]=15, [1358]=15, +[1359]=15, [1360]=43, [1361]=32, [1362]=32, [1363]=41, [1364]=41, [1365]=35, [1366]=31, +[1367]=33, [1368]=33, [1369]=33, [1370]=35, [1371]=35, [1372]=42, [1373]=37, [1374]=37, +[1375]=37, [1380]=42, [1381]=42, [1382]=35, [1383]=42, [1384]=32, [1385]=35, [1386]=32, +[1387]=31, [1388]=42, [1389]=35, [1390]=60, [1391]=42, [1392]=39, [1393]=38, [1394]=36, +[1395]=45, [1396]=37, [1398]=42, [1418]=35, [1419]=40, [1420]=40, [1421]=35, [1422]=45, +[1423]=40, [1424]=43, [1425]=42, [1426]=43, [1427]=43, [1428]=45, [1429]=44, [1430]=44, +[1431]=30, [1432]=30, [1433]=33, [1434]=33, [1435]=33, [1436]=33, [1437]=33, [1438]=33, +[1439]=33, [1440]=33, [1442]=22, [1444]=44, [1445]=50, [1446]=53, [1447]=31, [1448]=43, +[1449]=43, [1450]=43, [1451]=43, [1452]=43, [1453]=33, [1454]=39, [1455]=39, [1456]=39, +[1457]=39, [1458]=33, [1459]=35, [1462]=4, [1463]=4, [1464]=13, [1465]=33, [1466]=40, +[1467]=40, [1468]=60, [1469]=43, [1470]=3, [1471]=10, [1472]=20, [1473]=10, [1474]=20, +[1475]=50, [1476]=20, [1477]=45, [1478]=10, [1479]=60, [1480]=33, [1481]=33, [1482]=35, +[1483]=21, [1484]=33, [1485]=4, [1486]=17, [1487]=21, [1488]=40, [1489]=16, [1490]=16, +[1491]=18, [1492]=11, [1498]=10, [1499]=4, [1501]=11, [1502]=10, [1503]=10, [1504]=11, +[1505]=10, [1506]=10, [1507]=20, [1508]=20, [1509]=20, [1510]=20, [1511]=20, [1512]=20, +[1513]=20, [1514]=55, [1515]=20, [1516]=4, [1517]=4, [1518]=4, [1519]=4, [1520]=4, +[1521]=4, [1522]=10, [1523]=10, [1524]=11, [1525]=12, [1526]=13, [1527]=13, [1528]=20, +[1529]=20, [1530]=22, [1531]=30, [1532]=30, [1534]=23, [1535]=22, [1536]=22, [1558]=60, +[1559]=37, [1560]=50, [1578]=12, [1579]=12, [1580]=12, [1581]=8, [1582]=18, [1638]=10, +[1639]=10, [1640]=10, [1641]=12, [1642]=12, [1643]=12, [1644]=13, [1645]=12, [1646]=12, +[1647]=12, [1648]=13, [1649]=20, [1650]=23, [1651]=25, [1652]=25, [1653]=21, [1654]=22, +[1655]=22, [1656]=5, [1657]=60, [1658]=60, [1661]=40, [1665]=10, [1666]=10, [1667]=10, +[1678]=11, [1679]=10, [1680]=11, [1681]=11, [1682]=10, [1683]=10, [1684]=10, [1685]=10, +[1686]=10, [1687]=60, [1688]=10, [1689]=10, [1690]=43, [1691]=44, [1692]=10, [1693]=10, +[1698]=20, [1699]=22, [1700]=28, [1701]=28, [1702]=22, [1703]=28, [1704]=28, [1705]=28, +[1706]=30, [1707]=44, [1708]=29, [1709]=30, [1710]=30, [1711]=30, [1712]=40, [1713]=40, +[1714]=37, [1715]=10, [1716]=20, [1717]=20, [1718]=30, [1719]=30, [1738]=20, [1739]=20, +[1740]=25, [1758]=30, [1778]=13, [1779]=13, [1780]=13, [1781]=13, [1782]=28, [1783]=13, +[1784]=13, [1785]=13, [1786]=13, [1787]=13, [1788]=13, [1789]=12, [1790]=12, [1791]=30, +[1792]=40, [1793]=20, [1794]=20, [1795]=30, [1796]=31, [1798]=30, [1799]=40, [1800]=60, +[1801]=30, [1802]=30, [1803]=30, [1804]=30, [1805]=30, [1806]=22, [1818]=10, [1819]=10, +[1820]=10, [1821]=11, [1822]=11, [1823]=20, [1824]=20, [1825]=20, [1838]=30, [1839]=30, +[1840]=30, [1841]=30, [1842]=30, [1843]=30, [1844]=30, [1845]=30, [1846]=30, [1847]=30, +[1848]=30, [1858]=13, [1859]=10, [1860]=10, [1861]=10, [1878]=44, [1879]=10, [1880]=10, +[1881]=10, [1882]=10, [1883]=10, [1884]=10, [1885]=10, [1886]=13, [1898]=13, [1899]=13, +[1918]=27, [1919]=15, [1920]=16, [1921]=15, [1938]=28, [1939]=26, [1940]=26, [1941]=15, +[1942]=26, [1943]=26, [1944]=26, [1945]=26, [1946]=26, [1947]=38, [1948]=40, [1949]=38, +[1950]=30, [1951]=40, [1952]=40, [1953]=40, [1954]=40, [1955]=40, [1956]=40, [1957]=40, +[1958]=40, [1959]=15, [1960]=16, [1961]=15, [1962]=15, [1963]=13, [1978]=13, [1998]=16, +[1999]=20, [2038]=15, [2039]=15, [2040]=20, [2041]=15, [2078]=20, [2098]=20, [2118]=14, +[2138]=16, [2139]=18, [2158]=5, [2159]=5, [2160]=5, [2161]=5, [2178]=12, [2198]=41, +[2199]=41, [2200]=42, [2201]=43, [2202]=42, [2203]=44, [2204]=44, [2205]=10, [2206]=10, +[2218]=10, [2238]=10, [2239]=10, [2240]=40, [2241]=10, [2242]=10, [2258]=39, [2259]=16, +[2260]=16, [2278]=47, [2279]=47, [2280]=47, [2281]=16, [2282]=20, [2283]=41, [2284]=41, +[2298]=16, [2299]=16, [2300]=16, [2318]=42, [2338]=42, [2339]=44, [2340]=44, [2341]=44, +[2342]=43, [2358]=22, [2359]=24, [2360]=20, [2361]=44, [2378]=16, [2379]=16, [2380]=16, +[2381]=18, [2382]=16, [2383]=1, [2398]=40, [2399]=10, [2418]=36, [2438]=6, [2439]=47, +[2440]=47, [2458]=20, [2459]=8, [2460]=20, [2478]=24, [2479]=26, [2480]=20, [2498]=9, +[2499]=9, [2500]=39, [2501]=44, [2518]=12, [2519]=10, [2520]=12, [2521]=55, [2522]=55, +[2523]=55, [2541]=8, [2561]=10, [2581]=50, [2582]=50, [2583]=50, [2584]=50, [2585]=50, +[2586]=50, [2601]=50, [2602]=50, [2603]=50, [2604]=50, [2605]=49, [2606]=49, [2607]=20, +[2608]=20, [2609]=20, [2621]=50, [2622]=50, [2623]=55, [2641]=49, [2661]=49, [2662]=49, +[2681]=57, [2701]=57, [2702]=57, [2721]=58, [2741]=47, [2742]=47, [2743]=60, [2744]=60, +[2745]=31, [2746]=31, [2747]=60, [2748]=60, [2749]=60, [2750]=60, [2751]=32, [2752]=32, +[2753]=36, [2754]=36, [2755]=36, [2756]=40, [2757]=40, [2758]=40, [2759]=40, [2760]=40, +[2761]=45, [2762]=45, [2763]=45, [2764]=45, [2765]=45, [2766]=45, [2767]=45, [2768]=47, +[2769]=46, [2770]=50, [2771]=45, [2772]=45, [2773]=45, [2781]=46, [2782]=47, [2783]=57, +[2784]=50, [2801]=57, [2821]=46, [2822]=46, [2841]=35, [2842]=35, [2843]=35, [2844]=49, +[2845]=49, [2846]=46, [2847]=45, [2848]=45, [2849]=45, [2850]=45, [2851]=45, [2852]=45, +[2853]=45, [2854]=45, [2855]=45, [2856]=45, [2857]=45, [2858]=45, [2859]=45, [2860]=45, +[2861]=46, [2862]=42, [2863]=43, [2864]=45, [2865]=45, [2866]=43, [2867]=43, [2869]=43, +[2870]=45, [2871]=45, [2872]=45, [2873]=45, [2874]=45, [2875]=45, [2876]=45, [2877]=48, +[2878]=55, [2879]=50, [2880]=45, [2881]=45, [2882]=45, [2902]=43, [2903]=43, [2904]=30, +[2922]=26, [2923]=26, [2924]=30, [2925]=30, [2926]=27, [2927]=27, [2928]=30, [2929]=35, +[2930]=30, [2931]=28, [2932]=42, [2933]=43, [2934]=45, [2935]=45, [2936]=45, [2937]=55, +[2938]=55, [2939]=47, [2940]=47, [2941]=48, [2942]=50, [2943]=48, [2944]=48, [2945]=34, +[2946]=50, [2947]=34, [2948]=35, [2949]=34, [2950]=35, [2951]=30, [2952]=30, [2953]=30, +[2954]=50, [2962]=30, [2963]=50, [2964]=50, [2965]=50, [2966]=50, [2967]=50, [2968]=50, +[2969]=47, [2970]=47, [2972]=47, [2973]=45, [2974]=45, [2975]=43, [2976]=45, [2977]=50, +[2978]=43, [2979]=46, [2980]=44, [2981]=43, [2982]=44, [2983]=10, [2984]=10, [2985]=20, +[2986]=20, [2987]=43, [2988]=45, [2989]=48, [2990]=47, [2991]=47, [2992]=47, [2993]=47, +[2994]=51, [2995]=47, [2996]=30, [2997]=12, [2998]=12, [2999]=12, [3000]=12, [3001]=30, +[3002]=47, [3022]=47, [3042]=45, [3062]=50, [3063]=50, [3065]=1, [3082]=1, [3083]=1, +[3084]=1, [3085]=1, [3086]=1, [3087]=1, [3088]=1, [3089]=1, [3090]=1, [3091]=1, +[3092]=1, [3093]=1, [3094]=1, [3095]=1, [3096]=1, [3097]=1, [3098]=1, [3099]=1, +[3100]=1, [3101]=1, [3102]=1, [3103]=1, [3104]=1, [3105]=1, [3106]=1, [3107]=1, +[3108]=1, [3109]=1, [3110]=1, [3111]=1, [3112]=1, [3113]=1, [3114]=1, [3115]=1, +[3116]=1, [3117]=1, [3118]=1, [3119]=1, [3120]=1, [3121]=45, [3122]=45, [3123]=47, +[3124]=47, [3125]=45, [3126]=50, [3127]=50, [3128]=50, [3129]=50, [3130]=43, [3141]=57, +[3161]=48, [3181]=48, [3182]=48, [3201]=48, [3221]=12, [3281]=18, [3301]=15, [3321]=50, +[3341]=42, [3361]=3, [3362]=50, [3363]=55, [3364]=5, [3365]=5, [3366]=25, [3367]=48, +[3368]=48, [3369]=25, [3370]=25, [3371]=55, [3372]=52, [3373]=55, [3374]=55, [3375]=42, +[3376]=5, [3377]=50, [3378]=50, [3379]=50, [3380]=51, [3381]=48, [3382]=57, [3385]=50, +[3402]=50, [3421]=55, [3441]=48, [3442]=48, [3443]=48, [3444]=51, [3445]=51, [3446]=51, +[3447]=51, [3448]=52, [3449]=52, [3450]=52, [3451]=52, [3452]=50, [3453]=50, [3454]=50, +[3461]=52, [3462]=50, [3463]=52, [3481]=50, [3482]=35, [3483]=52, [3501]=55, [3502]=55, +[3503]=55, [3504]=53, [3505]=53, [3506]=56, [3507]=56, [3508]=58, [3509]=58, [3510]=58, +[3511]=58, [3512]=55, [3513]=25, [3514]=29, [3517]=52, [3518]=52, [3519]=4, [3520]=44, +[3521]=4, [3522]=4, [3523]=37, [3524]=13, [3525]=37, [3526]=47, [3527]=47, [3528]=53, +[3541]=52, [3542]=52, [3561]=52, [3562]=52, [3563]=52, [3564]=52, [3565]=52, [3566]=52, +[3567]=25, [3568]=52, [3569]=52, [3570]=52, [3578]=45, [3579]=45, [3580]=45, [3581]=60, +[3601]=53, [3602]=58, [3621]=58, [3625]=58, [3626]=58, [3627]=60, [3628]=60, [3629]=47, +[3630]=47, [3631]=40, [3632]=47, [3633]=47, [3634]=47, [3635]=47, [3636]=42, [3637]=47, +[3638]=47, [3639]=47, [3640]=47, [3641]=47, [3642]=47, [3643]=47, [3644]=47, [3645]=47, +[3646]=47, [3647]=47, [3661]=47, [3681]=12, [3701]=54, [3702]=54, [3721]=50, [3741]=15, +[3761]=50, [3762]=50, [3763]=50, [3764]=50, [3765]=24, [3781]=50, [3782]=50, [3783]=56, +[3784]=50, [3785]=50, [3786]=50, [3787]=50, [3788]=50, [3789]=50, [3790]=50, [3791]=50, +[3792]=55, [3801]=52, [3802]=52, [3803]=55, [3804]=55, [3821]=52, [3822]=53, [3823]=52, +[3824]=53, [3825]=53, [3841]=47, [3842]=47, [3843]=47, [3844]=52, [3845]=52, [3861]=1, +[3881]=53, [3882]=51, [3883]=52, [3884]=50, [3901]=3, [3902]=3, [3903]=4, [3904]=4, +[3905]=4, [3906]=52, [3907]=56, [3908]=52, [3909]=52, [3912]=52, [3913]=52, [3914]=52, +[3921]=14, [3922]=15, [3923]=18, [3924]=19, [3941]=52, [3942]=54, [3961]=54, [3962]=56, +[3981]=52, [3982]=54, [4001]=54, [4002]=54, [4003]=59, [4004]=60, [4005]=54, [4021]=20, +[4022]=54, [4023]=54, [4024]=58, [4041]=52, [4061]=54, [4062]=54, [4063]=58, [4081]=52, +[4082]=54, [4083]=55, [4084]=54, [4101]=55, [4102]=55, [4103]=55, [4104]=55, [4105]=55, +[4106]=55, [4107]=55, [4108]=55, [4109]=55, [4110]=55, [4111]=55, [4112]=55, [4113]=55, +[4114]=55, [4115]=55, [4116]=55, [4117]=55, [4118]=55, [4119]=55, [4120]=52, [4121]=58, +[4122]=58, [4123]=55, [4124]=43, [4125]=43, [4126]=55, [4127]=44, [4128]=55, [4129]=44, +[4130]=44, [4131]=44, [4132]=58, [4133]=55, [4134]=55, [4135]=46, [4136]=53, [4141]=52, +[4142]=52, [4143]=52, [4144]=53, [4145]=52, [4146]=52, [4147]=52, [4148]=53, [4161]=7, +[4181]=47, [4182]=54, [4183]=54, [4184]=54, [4185]=54, [4186]=54, [4201]=54, [4221]=55, +[4222]=55, [4223]=54, [4224]=54, [4241]=54, [4242]=54, [4243]=53, [4244]=53, [4245]=53, +[4261]=56, [4262]=52, [4263]=56, [4264]=58, [4265]=46, [4266]=46, [4267]=46, [4281]=44, +[4282]=58, [4283]=56, [4284]=53, [4285]=53, [4286]=56, [4287]=53, [4288]=53, [4289]=55, +[4290]=53, [4291]=53, [4292]=56, [4293]=52, [4294]=56, [4295]=1, [4296]=50, [4297]=47, +[4298]=48, [4300]=52, [4301]=55, [4321]=53, [4322]=58, [4324]=53, [4341]=59, [4342]=59, +[4343]=55, [4361]=59, [4362]=59, [4363]=59, [4381]=53, [4382]=53, [4383]=53, [4384]=53, +[4385]=53, [4386]=53, [4401]=55, [4402]=3, [4403]=55, [4421]=54, [4441]=54, [4442]=54, +[4443]=55, [4444]=55, [4445]=55, [4446]=55, [4447]=55, [4448]=55, [4449]=45, [4450]=46, +[4451]=47, [4461]=55, [4462]=55, [4463]=55, [4464]=55, [4465]=55, [4466]=55, [4467]=55, +[4481]=55, [4482]=55, [4483]=55, [4484]=55, [4485]=40, [4486]=40, [4487]=40, [4488]=40, +[4489]=40, [4490]=40, [4491]=55, [4492]=55, [4493]=53, [4494]=53, [4495]=4, [4496]=53, +[4501]=55, [4502]=55, [4503]=51, [4504]=54, [4505]=54, [4506]=54, [4507]=54, [4508]=54, +[4509]=54, [4510]=54, [4511]=54, [4512]=52, [4513]=54, [4521]=56, [4542]=25, [4561]=52, +[4581]=29, [4601]=30, [4602]=30, [4603]=30, [4604]=30, [4605]=30, [4606]=30, [4621]=60, +[4641]=1, [4642]=55, [4661]=52, [4681]=14, [4701]=59, [4721]=59, [4722]=13, [4723]=13, +[4724]=59, [4725]=15, [4726]=52, [4727]=15, [4728]=14, [4729]=59, [4730]=16, [4731]=19, +[4732]=19, [4733]=19, [4734]=60, [4735]=60, [4736]=31, [4737]=31, [4738]=31, [4739]=31, +[4740]=18, [4741]=58, [4742]=60, [4743]=60, [4761]=15, [4762]=15, [4763]=18, [4764]=60, +[4765]=60, [4766]=60, [4767]=29, [4768]=60, [4769]=60, [4770]=29, [4771]=60, [4781]=34, +[4782]=34, [4783]=37, [4784]=37, [4785]=37, [4786]=38, [4787]=50, [4788]=58, [4801]=60, +[4802]=60, [4803]=60, [4804]=60, [4805]=60, [4806]=60, [4807]=60, [4808]=54, [4809]=54, +[4810]=54, [4811]=14, [4812]=14, [4813]=14, [4821]=26, [4822]=60, [4841]=25, [4842]=56, +[4861]=59, [4862]=59, [4863]=59, [4864]=59, [4865]=26, [4866]=60, [4867]=60, [4881]=28, +[4882]=59, [4883]=59, [4901]=59, [4902]=57, [4903]=60, [4904]=29, [4906]=54, [4907]=60, +[4921]=20, [4941]=60, [4961]=40, [4962]=40, [4963]=40, [4964]=40, [4965]=35, [4966]=28, +[4967]=35, [4968]=35, [4969]=35, [4970]=60, [4971]=56, [4972]=56, [4973]=56, [4974]=60, +[4975]=40, [4976]=40, [4981]=59, [4982]=59, [4983]=59, [4984]=54, [4985]=56, [4986]=56, +[4987]=56, [5001]=59, [5002]=59, [5021]=52, [5022]=52, [5023]=52, [5041]=14, [5042]=20, +[5043]=20, [5044]=20, [5045]=20, [5046]=20, [5047]=60, [5048]=52, [5049]=52, [5050]=52, +[5051]=54, [5052]=21, [5054]=56, [5055]=58, [5056]=60, [5057]=60, [5058]=55, [5059]=55, +[5060]=55, [5061]=16, [5062]=27, [5063]=60, [5064]=28, [5065]=58, [5066]=50, [5067]=60, +[5068]=60, [5081]=60, [5082]=56, [5083]=56, [5084]=56, [5085]=56, [5086]=56, [5087]=57, +[5088]=28, [5089]=60, [5090]=50, [5091]=50, [5092]=52, [5093]=50, [5094]=50, [5095]=50, +[5096]=53, [5097]=56, [5098]=56, [5102]=60, [5103]=60, [5121]=59, [5122]=60, [5123]=59, +[5124]=60, [5125]=60, [5126]=60, [5127]=60, [5128]=59, [5141]=55, [5142]=55, [5143]=55, +[5144]=55, [5145]=55, [5146]=55, [5147]=29, [5148]=55, [5149]=55, [5150]=55, [5151]=30, +[5152]=56, [5153]=56, [5154]=56, [5155]=51, [5156]=54, [5157]=52, [5158]=52, [5159]=54, +[5160]=60, [5161]=60, [5162]=60, [5163]=58, [5164]=60, [5165]=55, [5166]=60, [5167]=60, +[5168]=56, [5181]=57, [5201]=60, [5202]=55, [5203]=55, [5204]=57, [5206]=60, [5210]=56, +[5211]=55, [5212]=60, [5213]=60, [5214]=60, [5215]=53, [5216]=53, [5217]=53, [5218]=53, +[5219]=55, [5220]=55, [5221]=55, [5222]=55, [5223]=55, [5224]=55, [5225]=58, [5226]=58, +[5227]=58, [5228]=53, [5229]=53, [5230]=53, [5231]=55, [5232]=55, [5233]=55, [5234]=55, +[5235]=58, [5236]=58, [5237]=58, [5238]=58, [5241]=56, [5242]=58, [5243]=60, [5244]=56, +[5245]=56, [5246]=56, [5247]=57, [5248]=58, [5249]=56, [5250]=56, [5251]=60, [5252]=58, +[5253]=58, [5261]=2, [5262]=60, [5263]=60, [5264]=60, [5265]=60, [5281]=60, [5282]=60, +[5283]=40, [5284]=40, [5301]=40, [5302]=40, [5305]=60, [5306]=60, [5307]=60, [5321]=20, +[5341]=60, [5342]=60, [5343]=60, [5344]=60, [5361]=35, [5381]=38, [5382]=60, [5384]=60, +[5385]=57, [5386]=37, [5401]=55, [5402]=55, [5403]=55, [5404]=55, [5405]=55, [5406]=55, +[5407]=55, [5408]=55, [5421]=25, [5441]=4, [5461]=60, [5462]=60, [5463]=60, [5464]=60, +[5465]=60, [5466]=60, [5481]=5, [5482]=6, [5501]=39, [5502]=60, [5503]=55, [5504]=60, +[5505]=60, [5507]=60, [5508]=55, [5509]=55, [5510]=55, [5511]=60, [5513]=60, [5514]=57, +[5515]=60, [5517]=60, [5518]=60, [5519]=60, [5521]=60, [5522]=60, [5524]=60, [5525]=60, +[5526]=60, [5527]=60, [5528]=60, [5529]=58, [5531]=60, [5533]=55, [5534]=53, [5535]=47, +[5536]=47, [5537]=57, [5538]=57, [5541]=6, [5542]=56, [5543]=56, [5544]=56, [5545]=9, +[5561]=34, [5581]=38, [5582]=58, [5601]=55, [5621]=4, [5622]=4, [5623]=4, [5624]=4, +[5625]=4, [5626]=4, [5627]=10, [5628]=10, [5629]=10, [5630]=10, [5631]=10, [5632]=10, +[5633]=10, [5634]=10, [5635]=10, [5636]=10, [5637]=10, [5638]=10, [5639]=10, [5640]=10, +[5641]=20, [5642]=20, [5643]=20, [5644]=20, [5645]=20, [5646]=20, [5647]=20, [5648]=4, +[5649]=4, [5650]=4, [5651]=4, [5652]=10, [5654]=10, [5655]=10, [5656]=10, [5657]=10, +[5658]=10, [5659]=10, [5660]=10, [5661]=10, [5662]=10, [5663]=10, [5672]=20, [5673]=20, +[5674]=20, [5675]=20, [5676]=20, [5677]=20, [5678]=20, [5679]=20, [5680]=20, [5713]=15, +[5721]=60, [5722]=16, [5723]=15, [5724]=16, [5725]=16, [5726]=12, [5727]=12, [5728]=16, +[5729]=15, [5730]=16, [5741]=33, [5742]=56, [5761]=16, [5762]=31, [5763]=31, [5781]=57, +[5801]=57, [5802]=57, [5803]=60, [5804]=60, [5821]=35, [5845]=58, [5846]=58, [5848]=60, +[5861]=60, [5862]=60, [5863]=49, [5881]=28, [5882]=55, [5883]=55, [5884]=55, [5885]=55, +[5886]=55, [5887]=55, [5888]=55, [5889]=55, [5890]=55, [5891]=55, [5892]=55, [5893]=55, +[5901]=55, [5902]=55, [5903]=55, [5904]=55, [5921]=10, [5922]=10, [5923]=10, [5924]=10, +[5925]=10, [5926]=10, [5927]=10, [5928]=10, [5929]=10, [5930]=10, [5931]=10, [5932]=10, +[5941]=60, [5942]=60, [5943]=38, [5944]=60, [5961]=56, [5981]=60, [6000]=50, [6001]=10, +[6002]=10, [6004]=56, [6021]=55, [6022]=58, [6023]=57, [6024]=60, [6025]=58, [6026]=58, +[6027]=38, [6028]=52, [6029]=52, [6030]=52, [6031]=55, [6032]=55, [6041]=58, [6042]=58, +[6061]=10, [6062]=10, [6063]=10, [6064]=10, [6065]=10, [6066]=10, [6067]=10, [6068]=10, +[6069]=10, [6070]=10, [6071]=10, [6072]=10, [6073]=10, [6074]=10, [6075]=10, [6076]=10, +[6081]=10, [6082]=10, [6083]=10, [6084]=10, [6085]=10, [6086]=10, [6087]=10, [6088]=10, +[6089]=10, [6101]=10, [6102]=10, [6103]=10, [6121]=14, [6122]=14, [6123]=14, [6124]=14, +[6125]=14, [6126]=14, [6127]=14, [6128]=14, [6129]=14, [6130]=14, [6131]=48, [6132]=39, +[6133]=60, [6134]=39, [6135]=60, [6136]=60, [6141]=39, [6142]=35, [6143]=36, [6144]=60, +[6145]=60, [6146]=60, [6147]=60, [6148]=60, [6161]=36, [6162]=51, [6163]=60, [6164]=55, +[6165]=58, [6181]=10, [6182]=60, [6183]=60, [6184]=60, [6185]=60, [6186]=60, [6187]=60, +[6221]=55, [6241]=56, [6261]=10, [6281]=10, [6282]=26, [6283]=26, [6284]=21, [6285]=10, +[6301]=23, [6321]=10, [6322]=10, [6323]=10, [6324]=10, [6341]=10, [6342]=10, [6343]=10, +[6344]=10, [6361]=10, [6362]=10, [6363]=10, [6364]=10, [6365]=10, [6381]=25, [6382]=20, +[6383]=20, [6384]=10, [6385]=10, [6386]=10, [6387]=10, [6388]=10, [6389]=55, [6390]=55, +[6391]=10, [6392]=10, [6393]=25, [6394]=4, [6395]=5, [6401]=18, [6402]=60, [6403]=60, +[6421]=18, [6441]=26, [6442]=19, [6461]=19, [6462]=24, [6481]=20, [6482]=24, [6501]=60, +[6502]=60, [6503]=24, [6504]=30, [6521]=36, [6522]=36, [6523]=18, [6541]=19, [6542]=19, +[6543]=19, [6544]=24, [6545]=19, [6546]=25, [6547]=21, [6548]=18, [6561]=27, [6562]=22, +[6563]=22, [6564]=22, [6565]=26, [6566]=60, [6567]=60, [6568]=60, [6569]=60, [6570]=60, +[6571]=27, [6581]=27, [6582]=60, [6583]=60, [6584]=60, [6585]=60, [6601]=60, [6602]=60, +[6603]=56, [6604]=59, [6605]=54, [6606]=60, [6607]=45, [6608]=45, [6609]=45, [6610]=45, +[6611]=45, [6612]=45, [6621]=26, [6622]=45, [6623]=45, [6624]=45, [6625]=45, [6626]=35, +[6627]=30, [6628]=30, [6629]=18, [6641]=23, [6642]=60, [6643]=60, [6644]=60, [6645]=60, +[6646]=60, [6661]=12, [6662]=12, [6681]=24, [6701]=60, [6721]=10, [6722]=10, [6741]=60, +[6761]=55, [6762]=55, [6781]=60, [6801]=60, [6804]=56, [6805]=57, [6821]=60, [6822]=60, +[6823]=60, [6824]=60, [6825]=60, [6826]=60, [6827]=60, [6881]=60, [6901]=60, [6921]=27, +[6922]=30, [6941]=60, [6942]=60, [6943]=60, [6961]=60, [6962]=60, [6963]=60, [6964]=60, +[6981]=26, [6982]=55, [6983]=60, [6984]=60, [6985]=55, [7001]=60, [7002]=60, [7003]=48, +[7021]=60, [7022]=60, [7023]=60, [7024]=60, [7025]=60, [7026]=60, [7027]=60, [7028]=47, +[7029]=47, [7041]=47, [7042]=60, [7043]=60, [7044]=49, [7045]=60, [7046]=49, [7061]=60, +[7062]=60, [7063]=60, [7064]=51, [7065]=51, [7066]=51, [7067]=48, [7068]=42, [7070]=42, +[7081]=60, [7082]=60, [7101]=60, [7102]=60, [7121]=60, [7122]=60, [7123]=60, [7124]=60, +[7141]=60, [7142]=60, [7161]=60, [7162]=60, [7163]=60, [7164]=60, [7165]=60, [7166]=60, +[7167]=60, [7168]=60, [7169]=60, [7170]=60, [7171]=60, [7172]=60, [7181]=60, [7201]=54, +[7202]=60, [7223]=60, [7224]=60, [7241]=60, [7261]=60, [7281]=60, [7282]=60, [7301]=60, +[7302]=60, [7321]=31, [7341]=60, [7342]=60, [7361]=60, [7362]=60, [7363]=60, [7364]=60, +[7365]=60, [7366]=60, [7367]=60, [7368]=60, [7381]=60, [7382]=60, [7383]=11, [7385]=60, +[7386]=60, [7401]=60, [7402]=60, [7421]=60, [7422]=60, [7423]=60, [7424]=60, [7425]=60, +[7426]=60, [7427]=60, [7428]=60, [7429]=60, [7441]=58, [7461]=60, [7462]=60, [7463]=60, +[7478]=60, [7479]=60, [7480]=60, [7481]=60, [7482]=60, [7483]=60, [7484]=60, [7485]=60, +[7486]=60, [7487]=60, [7488]=57, [7489]=57, [7490]=60, [7491]=60, [7492]=57, [7493]=60, +[7494]=57, [7495]=60, [7496]=60, [7497]=60, [7498]=60, [7499]=60, [7500]=60, [7501]=60, +[7502]=60, [7503]=60, [7504]=60, [7505]=60, [7506]=60, [7507]=60, [7508]=60, [7509]=60, +[7521]=60, [7541]=40, [7562]=58, [7563]=58, [7564]=58, [7581]=60, [7582]=60, [7583]=60, +[7601]=50, [7602]=55, [7603]=55, [7604]=60, [7621]=60, [7622]=60, [7623]=58, [7624]=58, +[7625]=60, [7626]=60, [7627]=60, [7628]=60, [7629]=60, [7630]=60, [7631]=60, [7632]=60, +[7633]=60, [7634]=60, [7635]=60, [7636]=60, [7637]=60, [7638]=60, [7639]=60, [7640]=60, +[7641]=60, [7642]=60, [7643]=60, [7644]=60, [7645]=60, [7646]=60, [7647]=60, [7648]=60, +[7649]=60, [7650]=60, [7651]=60, [7652]=60, [7653]=60, [7654]=60, [7655]=60, [7656]=60, +[7657]=60, [7658]=60, [7659]=60, [7666]=60, [7667]=60, [7668]=60, [7701]=50, [7703]=60, +[7721]=48, [7722]=50, [7723]=49, [7724]=49, [7725]=55, [7726]=55, [7727]=49, [7728]=48, +[7729]=48, [7730]=45, [7731]=47, [7732]=48, [7733]=48, [7734]=48, [7735]=48, [7736]=60, +[7737]=60, [7738]=48, [7761]=60, [7781]=60, [7782]=60, [7783]=60, [7784]=60, [7785]=60, +[7786]=60, [7787]=60, [7788]=29, [7789]=29, [7791]=60, [7792]=60, [7793]=60, [7794]=60, +[7795]=60, [7796]=60, [7798]=60, [7799]=60, [7800]=60, [7801]=60, [7802]=60, [7803]=60, +[7804]=60, [7805]=60, [7806]=60, [7807]=60, [7808]=60, [7809]=60, [7810]=55, [7811]=60, +[7812]=60, [7813]=60, [7814]=60, [7815]=50, [7816]=48, [7817]=60, [7818]=60, [7819]=60, +[7820]=60, [7821]=60, [7822]=60, [7823]=60, [7824]=60, [7825]=60, [7826]=60, [7827]=60, +[7828]=48, [7829]=48, [7830]=48, [7831]=60, [7832]=60, [7833]=60, [7834]=60, [7835]=60, +[7836]=60, [7837]=60, [7838]=55, [7839]=48, [7840]=49, [7841]=48, [7842]=48, [7843]=50, +[7844]=48, [7845]=51, [7846]=51, [7847]=51, [7848]=60, [7849]=50, [7850]=50, [7861]=51, +[7862]=51, [7863]=34, [7864]=44, [7865]=60, [7866]=34, [7867]=44, [7868]=60, [7871]=39, +[7872]=49, [7873]=59, [7874]=39, [7875]=49, [7876]=59, [7877]=60, [7881]=60, [7882]=60, +[7883]=60, [7884]=60, [7885]=60, [7886]=55, [7887]=35, [7888]=45, [7889]=60, [7890]=60, +[7891]=60, [7892]=60, [7893]=60, [7894]=60, [7895]=60, [7896]=60, [7897]=60, [7898]=60, +[7899]=60, [7900]=60, [7901]=60, [7902]=60, [7903]=60, [7905]=60, [7907]=55, [7921]=25, +[7922]=55, [7923]=45, [7924]=35, [7925]=25, [7926]=60, [7927]=55, [7928]=55, [7929]=55, +[7930]=60, [7931]=60, [7932]=60, [7933]=60, [7934]=60, [7935]=60, [7936]=60, [7937]=60, +[7938]=60, [7939]=60, [7940]=60, [7941]=60, [7942]=60, [7943]=60, [7944]=60, [7945]=60, +[7946]=1, [7981]=60, [8001]=3, [8041]=60, [8042]=60, [8043]=60, [8044]=60, [8045]=60, +[8046]=60, [8047]=60, [8048]=60, [8049]=60, [8050]=60, [8051]=60, [8052]=60, [8053]=61, +[8054]=61, [8055]=61, [8056]=60, [8057]=60, [8058]=60, [8059]=60, [8060]=60, [8061]=60, +[8062]=60, [8063]=60, [8064]=60, [8065]=60, [8066]=60, [8067]=60, [8068]=60, [8069]=60, +[8070]=60, [8071]=60, [8072]=60, [8073]=60, [8074]=60, [8075]=60, [8076]=60, [8077]=60, +[8078]=60, [8079]=60, [8080]=59, [8081]=55, [8101]=60, [8102]=60, [8103]=60, [8104]=60, +[8105]=55, [8106]=60, [8107]=60, [8108]=60, [8109]=60, [8110]=60, [8111]=60, [8112]=60, +[8113]=60, [8114]=60, [8115]=60, [8116]=60, [8117]=60, [8118]=60, [8119]=60, [8120]=55, +[8121]=60, [8122]=60, [8123]=59, [8124]=55, [8141]=60, [8142]=60, [8143]=60, [8144]=60, +[8145]=60, [8146]=60, [8147]=60, [8148]=60, [8149]=60, [8150]=60, [8151]=52, [8153]=52, +[8154]=49, [8155]=29, [8156]=39, [8157]=45, [8158]=25, [8159]=35, [8160]=49, [8161]=39, +[8162]=29, [8163]=45, [8164]=35, [8165]=25, [8166]=45, [8167]=35, [8168]=25, [8169]=45, +[8170]=35, [8171]=25, [8181]=58, [8182]=58, [8183]=60, [8184]=60, [8185]=60, [8186]=60, +[8187]=60, [8188]=60, [8189]=60, [8190]=60, [8191]=60, [8192]=60, [8193]=60, [8194]=60, +[8195]=60, [8196]=60, [8201]=60, [8221]=60, [8222]=60, [8223]=60, [8224]=60, [8225]=60, +[8227]=60, [8228]=60, [8229]=60, [8231]=52, [8232]=52, [8233]=52, [8234]=52, [8235]=52, +[8236]=52, [8238]=60, [8239]=60, [8240]=60, [8241]=60, [8242]=60, [8243]=60, [8246]=60, +[8249]=60, [8250]=52, [8251]=52, [8252]=52, [8253]=52, [8254]=52, [8255]=52, [8256]=52, +[8257]=52, [8258]=60, [8260]=34, [8261]=44, [8262]=60, [8263]=34, [8264]=44, [8265]=60, +[8266]=39, [8267]=60, [8268]=39, [8269]=60, [8271]=60, [8272]=60, [8273]=47, [8275]=55, +[8276]=55, [8277]=55, [8278]=57, [8279]=60, [8280]=55, [8281]=57, [8282]=58, [8283]=59, +[8284]=58, [8285]=59, [8286]=60, [8287]=60, [8288]=60, [8289]=15, [8290]=19, [8291]=60, +[8292]=60, [8293]=60, [8294]=60, [8295]=19, [8296]=15, [8297]=60, [8298]=60, [8299]=60, +[8300]=60, [8301]=60, [8302]=60, [8303]=60, [8304]=60, [8305]=60, [8306]=60, [8307]=57, +[8308]=60, [8309]=60, [8310]=60, [8311]=60, [8312]=60, [8313]=57, [8314]=60, [8315]=60, +[8316]=60, [8317]=57, [8318]=60, [8319]=60, [8320]=60, [8321]=60, [8322]=60, [8323]=59, +[8324]=59, [8331]=60, [8332]=60, [8333]=60, [8341]=60, [8342]=60, [8343]=60, [8348]=60, +[8349]=60, [8351]=60, [8352]=60, [8353]=60, [8354]=60, [8355]=60, [8356]=60, [8357]=60, +[8358]=60, [8359]=60, [8360]=60, [8361]=60, [8362]=60, [8363]=60, [8364]=60, [8365]=45, +[8366]=45, [8367]=60, [8368]=19, [8369]=60, [8370]=29, [8371]=60, [8372]=19, [8373]=60, +[8374]=29, [8375]=60, [8376]=60, [8377]=60, [8378]=60, [8379]=60, [8380]=60, [8381]=60, +[8382]=60, [8383]=60, [8384]=29, [8385]=60, [8386]=19, [8387]=60, [8388]=60, [8389]=19, +[8390]=29, [8391]=39, [8392]=49, [8393]=39, [8394]=49, [8395]=59, [8396]=60, [8397]=59, +[8398]=60, [8399]=29, [8400]=39, [8401]=49, [8402]=59, [8403]=60, [8404]=29, [8405]=39, +[8406]=49, [8407]=59, [8408]=60, [8409]=60, [8410]=50, [8411]=50, [8412]=52, [8413]=52, +[8414]=52, [8415]=50, [8416]=52, [8417]=50, [8418]=52, [8419]=52, [8420]=52, [8421]=52, +[8422]=52, [8423]=52, [8424]=53, [8425]=52, [8426]=29, [8427]=39, [8428]=49, [8429]=59, +[8430]=60, [8431]=29, [8432]=39, [8433]=49, [8434]=59, [8435]=60, [8436]=39, [8437]=49, +[8438]=59, [8439]=60, [8440]=39, [8441]=49, [8442]=59, [8443]=60, [8446]=60, [8447]=60, +[8460]=48, [8461]=55, [8462]=55, [8464]=58, [8465]=55, [8466]=55, [8467]=55, [8469]=56, +[8470]=55, [8471]=56, [8481]=60, [8484]=60, [8485]=60, [8492]=60, [8493]=60, [8494]=60, +[8495]=60, [8496]=60, [8497]=60, [8498]=60, [8499]=60, [8500]=60, [8501]=60, [8502]=60, +[8503]=60, [8504]=60, [8505]=60, [8506]=60, [8507]=60, [8508]=60, [8509]=60, [8510]=60, +[8511]=60, [8512]=60, [8513]=60, [8514]=60, [8515]=60, [8516]=60, [8517]=60, [8518]=60, +[8519]=60, [8520]=60, [8521]=60, [8522]=60, [8523]=60, [8524]=60, [8525]=60, [8526]=60, +[8527]=60, [8528]=60, [8529]=60, [8532]=60, [8533]=60, [8534]=60, [8535]=60, [8536]=60, +[8537]=60, [8538]=60, [8539]=60, [8540]=60, [8541]=60, [8542]=60, [8543]=60, [8544]=60, +[8545]=60, [8546]=60, [8548]=60, [8549]=60, [8550]=60, [8551]=47, [8552]=50, [8553]=50, +[8554]=50, [8555]=60, [8556]=60, [8557]=60, [8558]=60, [8559]=60, [8560]=60, [8561]=60, +[8562]=60, [8572]=60, [8573]=60, [8574]=60, [8575]=60, [8576]=60, [8577]=60, [8578]=60, +[8579]=60, [8580]=60, [8581]=60, [8582]=60, [8583]=60, [8584]=60, [8585]=60, [8586]=60, +[8587]=60, [8588]=60, [8589]=60, [8590]=60, [8591]=60, [8592]=60, [8593]=60, [8594]=60, +[8595]=60, [8596]=60, [8597]=60, [8598]=60, [8599]=60, [8600]=60, [8601]=60, [8602]=60, +[8603]=60, [8604]=60, [8605]=60, [8606]=60, [8607]=60, [8608]=60, [8609]=60, [8610]=60, +[8611]=60, [8612]=60, [8613]=60, [8614]=60, [8615]=60, [8616]=60, [8619]=60, [8620]=60, +[8621]=60, [8622]=60, [8623]=60, [8624]=60, [8625]=60, [8626]=60, [8627]=60, [8628]=60, +[8629]=60, [8630]=60, [8631]=60, [8632]=60, [8633]=60, [8634]=60, [8635]=60, [8636]=60, +[8637]=60, [8638]=60, [8639]=60, [8640]=60, [8641]=60, [8642]=60, [8643]=60, [8644]=60, +[8645]=60, [8646]=60, [8647]=60, [8648]=60, [8649]=60, [8650]=60, [8651]=60, [8652]=60, +[8653]=60, [8654]=60, [8655]=60, [8656]=60, [8657]=60, [8658]=60, [8659]=60, [8660]=60, +[8661]=60, [8662]=60, [8663]=60, [8664]=60, [8665]=60, [8666]=60, [8667]=60, [8668]=60, +[8669]=60, [8670]=60, [8671]=60, [8672]=60, [8673]=60, [8674]=60, [8675]=60, [8676]=60, +[8677]=60, [8678]=60, [8679]=60, [8680]=60, [8681]=60, [8682]=60, [8683]=60, [8684]=60, +[8685]=60, [8686]=60, [8687]=60, [8688]=60, [8689]=60, [8690]=60, [8691]=60, [8692]=60, +[8693]=60, [8694]=60, [8695]=60, [8696]=60, [8697]=60, [8698]=60, [8699]=60, [8700]=60, +[8701]=60, [8702]=60, [8703]=60, [8704]=60, [8705]=60, [8706]=60, [8707]=60, [8708]=60, +[8709]=60, [8710]=60, [8711]=60, [8712]=60, [8713]=60, [8714]=60, [8715]=60, [8716]=60, +[8717]=60, [8718]=60, [8719]=60, [8720]=60, [8721]=60, [8722]=60, [8723]=60, [8724]=60, +[8725]=60, [8726]=60, [8727]=60, [8728]=60, [8729]=60, [8730]=60, [8731]=60, [8732]=60, +[8733]=60, [8734]=60, [8735]=60, [8736]=60, [8737]=60, [8738]=60, [8739]=60, [8740]=60, +[8741]=60, [8742]=60, [8743]=60, [8744]=1, [8745]=60, [8746]=60, [8747]=60, [8748]=60, +[8749]=60, [8750]=60, [8751]=60, [8752]=60, [8753]=60, [8754]=60, [8755]=60, [8756]=60, +[8757]=60, [8758]=60, [8759]=60, [8760]=60, [8761]=60, [8762]=60, [8763]=60, [8764]=60, +[8765]=60, [8766]=60, [8767]=1, [8768]=20, [8769]=40, [8770]=60, [8771]=60, [8772]=60, +[8773]=60, [8774]=60, [8775]=60, [8776]=60, [8777]=60, [8778]=60, [8779]=60, [8780]=60, +[8781]=60, [8782]=60, [8783]=60, [8784]=60, [8785]=60, [8786]=60, [8787]=60, [8788]=1, +[8789]=60, [8790]=60, [8791]=60, [8792]=60, [8793]=60, [8794]=60, [8795]=60, [8796]=60, +[8797]=60, [8798]=60, [8799]=60, [8800]=60, [8801]=60, [8802]=60, [8803]=10, [8804]=60, +[8805]=60, [8806]=60, [8807]=60, [8808]=60, [8809]=60, [8810]=60, [8811]=60, [8812]=60, +[8813]=60, [8814]=60, [8815]=60, [8816]=60, [8817]=60, [8818]=60, [8819]=60, [8820]=60, +[8821]=60, [8822]=60, [8823]=60, [8824]=60, [8825]=60, [8826]=60, [8827]=1, [8828]=1, +[8829]=60, [8830]=60, [8831]=60, [8832]=60, [8833]=60, [8834]=60, [8835]=60, [8836]=60, +[8837]=60, [8838]=60, [8839]=60, [8840]=60, [8841]=60, [8842]=60, [8843]=60, [8844]=60, +[8845]=60, [8846]=19, [8847]=29, [8848]=39, [8849]=49, [8850]=60, [8851]=19, [8852]=29, +[8853]=39, [8854]=49, [8855]=60, [8857]=60, [8858]=60, [8859]=60, [8860]=60, [8861]=60, +[8862]=60, [8863]=60, [8864]=60, [8865]=60, [8866]=60, [8867]=60, [8868]=60, [8870]=60, +[8871]=60, [8872]=60, [8873]=60, [8874]=60, [8875]=60, [8876]=60, [8877]=60, [8878]=60, +[8879]=60, [8880]=60, [8881]=60, [8882]=60, [8883]=60, [8893]=47, [8897]=60, [8898]=60, +[8899]=60, [8900]=60, [8901]=60, [8902]=60, [8903]=60, [8904]=60, [8905]=60, [8906]=60, +[8907]=60, [8908]=60, [8909]=60, [8910]=60, [8911]=60, [8912]=60, [8913]=60, [8914]=60, +[8915]=60, [8916]=60, [8917]=60, [8918]=60, [8919]=60, [8920]=60, [8921]=60, [8922]=60, +[8923]=60, [8924]=60, [8925]=60, [8926]=60, [8927]=60, [8928]=60, [8929]=60, [8930]=60, +[8931]=60, [8932]=60, [8933]=60, [8934]=60, [8935]=60, [8936]=60, [8937]=60, [8938]=60, +[8939]=60, [8940]=60, [8941]=60, [8942]=60, [8943]=60, [8944]=60, [8945]=60, [8946]=60, +[8947]=60, [8948]=60, [8949]=60, [8950]=60, [8951]=60, [8952]=60, [8953]=60, [8954]=60, +[8955]=60, [8956]=60, [8957]=60, [8958]=60, [8959]=60, [8960]=60, [8961]=60, [8962]=60, +[8963]=60, [8964]=60, [8965]=60, [8966]=60, [8967]=60, [8968]=60, [8969]=60, [8970]=60, +[8977]=60, [8978]=60, [8979]=60, [8980]=60, [8981]=60, [8982]=60, [8983]=60, [8984]=60, +[8985]=60, [8986]=60, [8987]=60, [8988]=60, [8989]=60, [8990]=60, [8991]=60, [8992]=60, +[8993]=60, [8994]=60, [8995]=60, [8996]=60, [8997]=60, [8998]=60, [8999]=60, [9000]=60, +[9001]=60, [9002]=60, [9003]=60, [9004]=60, [9005]=60, [9006]=60, [9007]=60, [9008]=60, +[9009]=60, [9010]=60, [9011]=60, [9012]=60, [9013]=60, [9014]=60, [9015]=60, [9016]=60, +[9017]=60, [9018]=60, [9019]=60, [9020]=60, [9021]=60, [9022]=60, [9023]=60, [9024]=60, +[9025]=60, [9026]=60, [9027]=60, [9028]=60, [9029]=60, [9032]=60, [9033]=60, [9034]=60, +[9036]=60, [9037]=60, [9038]=60, [9039]=60, [9040]=60, [9041]=60, [9042]=60, [9043]=60, +[9044]=60, [9045]=60, [9046]=60, [9047]=60, [9048]=60, [9049]=60, [9050]=60, [9051]=52, +[9052]=52, [9053]=52, [9054]=60, [9055]=60, [9056]=60, [9057]=60, [9058]=60, [9059]=60, +[9060]=60, [9061]=60, [9063]=52, [9068]=60, [9069]=60, [9070]=60, [9071]=60, [9072]=60, +[9073]=60, [9074]=60, [9075]=60, [9077]=60, [9078]=60, [9079]=60, [9080]=60, [9081]=60, +[9082]=60, [9083]=60, [9084]=60, [9085]=60, [9086]=60, [9087]=60, [9088]=60, [9089]=60, +[9090]=60, [9091]=60, [9092]=60, [9093]=60, [9094]=60, [9095]=60, [9096]=60, [9097]=60, +[9098]=60, [9099]=60, [9100]=60, [9101]=60, [9102]=60, [9103]=60, [9104]=60, [9105]=60, +[9106]=60, [9107]=60, [9108]=60, [9109]=60, [9110]=60, [9111]=60, [9112]=60, [9113]=60, +[9114]=60, [9115]=60, [9116]=60, [9117]=60, [9118]=60, [9120]=60, [9121]=60, [9122]=60, +[9123]=60, [9124]=60, [9125]=60, [9126]=60, [9127]=60, [9128]=60, [9129]=60, [9131]=60, +[9132]=60, [9136]=60, [9137]=60, [9141]=60, [9142]=60, [9153]=60, [9154]=60, [9165]=60, +[9178]=60, [9179]=60, [9181]=60, [9182]=60, [9183]=60, [9184]=60, [9185]=60, [9186]=60, +[9187]=60, [9188]=60, [9190]=60, [9191]=60, [9194]=60, [9195]=60, [9196]=60, [9197]=60, +[9198]=60, [9200]=60, [9201]=60, [9202]=60, [9203]=60, [9204]=60, [9205]=60, [9206]=60, +[9208]=60, [9209]=60, [9210]=60, [9211]=60, [9213]=60, [9221]=60, [9222]=60, [9223]=60, +[9224]=60, [9225]=60, [9226]=60, [9227]=60, [9228]=60, [9229]=60, [9230]=60, [9232]=60, +[9233]=60, [9234]=60, [9235]=60, [9236]=60, [9237]=60, [9238]=60, [9239]=60, [9240]=60, +[9241]=60, [9242]=60, [9243]=60, [9244]=60, [9245]=60, [9246]=60, [9247]=60, [9248]=60, +[9250]=60, [9251]=60, [9257]=60, [9259]=60, [9260]=6, [9261]=10, [9262]=10, [9263]=10, +[9264]=10, [9265]=8, [9266]=60, [9267]=60, [9268]=60, [9269]=60, [9270]=60, [9271]=60, +[9272]=55, [9292]=60, [9295]=60, [9299]=60, [9300]=60, [9301]=60, [9302]=60, [9304]=60, +[9310]=60, [9317]=60, [9318]=60, [9319]=60, [9320]=60, [9321]=60, [9322]=60, [9323]=60, +[9324]=1, [9325]=1, [9326]=1, [9330]=1, [9331]=1, [9332]=1, [9338]=60, [9339]=1, +[9341]=60, [9362]=60, [9364]=60, [9365]=1, [9367]=60, [9368]=60, [9378]=60, [9386]=60, +[9388]=25, [9389]=25, [9415]=60, [9416]=60, [9419]=60, [9422]=60, [9664]=60, [9665]=60, +[41747]=6, [41895]=6, [50003]=6, [60050]=5, +}