commit 51ac55313731e10c33aae213a0ffeb9e748e16b0 Author: Relationship <139162359+Relationship-OctoWoW@users.noreply.github.com> Date: Wed Jul 8 05:01:50 2026 +0100 Add files via upload diff --git a/Database.lua b/Database.lua new file mode 100644 index 0000000..887daa0 --- /dev/null +++ b/Database.lua @@ -0,0 +1,1242 @@ +RelationshipsDashboardDB_ItemLevels = { + [16391]=63,[16392]=63,[16393]=63,[16394]=60,[16395]=60,[16396]=63,[16397]=63,[16398]=60,[16399]=60,[16400]=60, + [16401]=63,[16402]=60,[16403]=63,[16404]=60,[16405]=63,[16406]=63,[16407]=60,[25]=2,[16409]=63,[16410]=63,[16411]=60, + [16412]=60,[16413]=63,[16414]=63,[16415]=63,[16416]=63,[16417]=63,[35]=2,[36]=2,[37]=2,[16421]=63,[39]=1,[40]=1, + [16424]=63,[16425]=63,[43]=1,[44]=1,[16428]=63,[16429]=63,[47]=1,[48]=1,[16432]=63,[16433]=63,[51]=1,[52]=1,[16436]=63, + [16437]=65,[55]=1,[56]=1,[57]=1,[16441]=65,[59]=1,[60]=5,[61]=5,[16445]=65,[16446]=71,[16447]=65,[16448]=71,[16449]=74, + [16450]=71,[16451]=74,[16452]=74,[16453]=74,[16454]=71,[16455]=74,[16456]=71,[16457]=74,[16458]=65,[16459]=71, + [77]=4,[16461]=65,[79]=5,[80]=5,[16464]=65,[16465]=65,[16466]=65,[16467]=65,[85]=5,[86]=1,[87]=1,[16471]=71,[16472]=71, + [16473]=74,[16474]=74,[16475]=71,[16476]=74,[16477]=74,[16478]=74,[16479]=71,[16480]=74,[98]=1,[99]=1,[16483]=71, + [16484]=71,[16485]=63,[16486]=63,[16487]=63,[16488]=60,[16489]=63,[16490]=63,[16491]=63,[16492]=63,[16493]=60, + [16494]=63,[16495]=60,[16496]=63,[16497]=63,[16498]=63,[16499]=63,[16500]=60,[16501]=63,[16502]=63,[120]=1,[121]=1, + [16505]=63,[16506]=63,[16507]=63,[16508]=63,[16509]=63,[16510]=63,[128]=1,[129]=1,[16513]=63,[16514]=63,[16515]=63, + [16516]=63,[16517]=60,[16518]=63,[16519]=63,[137]=1,[16521]=63,[139]=1,[140]=1,[16524]=63,[16525]=63,[16526]=63, + [16527]=63,[16528]=63,[146]=1,[147]=1,[16531]=63,[16532]=63,[16533]=65,[16534]=65,[16535]=65,[153]=1,[16537]=65, + [155]=1,[16539]=65,[16540]=65,[16541]=74,[16542]=74,[16543]=71,[16544]=74,[16545]=71,[16546]=65,[16547]=65,[16548]=71, + [16549]=65,[16550]=65,[16551]=65,[16552]=65,[16553]=65,[16554]=65,[16555]=65,[16556]=65,[16557]=65,[16558]=65, + [16559]=65,[16560]=65,[16561]=65,[16562]=65,[16563]=65,[16564]=65,[16565]=65,[16566]=65,[16567]=65,[16568]=65, + [16569]=65,[16570]=65,[16571]=65,[16572]=65,[16573]=65,[16574]=65,[16575]=65,[193]=5,[194]=5,[195]=5,[16579]=65, + [16580]=65,[16582]=1,[200]=22,[201]=22,[202]=22,[203]=22,[209]=5,[210]=5,[16604]=5,[16605]=5,[16606]=5,[16607]=5, + [16608]=16,[236]=22,[237]=22,[238]=22,[239]=22,[16623]=57,[16658]=32,[16659]=27,[16660]=27,[16661]=27,[16664]=54, + [16666]=63,[16667]=62,[285]=22,[286]=22,[287]=22,[16671]=57,[16672]=59,[16673]=58,[16674]=63,[16675]=59,[16676]=59, + [16677]=62,[16678]=61,[16679]=60,[16680]=58,[16681]=57,[16682]=59,[16683]=57,[16684]=59,[16685]=58,[16686]=62, + [16687]=61,[16688]=63,[16689]=60,[16690]=63,[16691]=59,[16692]=59,[16693]=62,[16694]=61,[16695]=60,[16696]=58, + [16697]=57,[16698]=62,[16699]=61,[16700]=63,[16701]=60,[16702]=58,[16703]=57,[16704]=59,[16705]=59,[16706]=63, + [16707]=62,[16708]=60,[16709]=61,[16710]=57,[16711]=59,[16712]=59,[16713]=58,[16714]=57,[16715]=59,[16716]=58, + [16717]=59,[16718]=60,[16719]=61,[16720]=62,[16721]=63,[16722]=57,[16723]=58,[16724]=59,[16725]=59,[16726]=63, + [16727]=62,[16728]=61,[16729]=60,[16730]=63,[16731]=62,[16732]=61,[16733]=60,[16734]=59,[16735]=57,[16736]=58, + [16737]=59,[16738]=48,[16739]=48,[16740]=31,[16741]=31,[16768]=52,[16769]=52,[16787]=1,[16788]=36,[16789]=36, + [16791]=38,[16792]=37,[16793]=38,[16794]=38,[16795]=66,[16796]=66,[16797]=66,[16798]=66,[16799]=66,[16800]=66, + [16801]=66,[16802]=66,[16803]=66,[16804]=66,[16805]=66,[16806]=66,[16807]=66,[16808]=66,[16809]=66,[16810]=66, + [16811]=66,[16812]=66,[16813]=66,[16814]=66,[16815]=66,[16816]=66,[16817]=66,[16818]=76,[16819]=66,[16820]=66, + [16821]=66,[16822]=66,[16823]=66,[16824]=66,[16825]=66,[16826]=66,[16827]=66,[16828]=66,[16829]=66,[16830]=66, + [16831]=66,[16832]=76,[16833]=66,[16834]=66,[16835]=66,[16836]=66,[16837]=66,[16838]=66,[16839]=66,[16840]=66, + [16841]=66,[16842]=66,[16843]=66,[16844]=66,[16845]=66,[16846]=66,[16847]=66,[16848]=66,[16849]=66,[16850]=66, + [16851]=66,[16852]=66,[16853]=66,[16854]=66,[16855]=66,[16856]=66,[16857]=66,[16858]=66,[16859]=66,[16860]=66, + [16861]=66,[16862]=66,[16863]=66,[16864]=66,[16865]=66,[16866]=66,[16867]=66,[16868]=66,[16873]=38,[16886]=30, + [16887]=30,[16889]=24,[16890]=24,[16891]=21,[16894]=21,[16897]=76,[16898]=76,[16899]=76,[16900]=76,[16901]=76, + [16902]=76,[16903]=76,[16904]=76,[16905]=76,[16906]=76,[16907]=76,[16908]=76,[16909]=76,[16910]=76,[16911]=76, + [16912]=76,[16913]=76,[16914]=76,[16915]=76,[16916]=76,[16917]=76,[16918]=76,[16919]=76,[16920]=76,[16921]=76, + [16922]=76,[16923]=76,[16924]=76,[16925]=76,[16926]=76,[16927]=76,[16928]=76,[16929]=76,[16930]=76,[16931]=76, + [16932]=76,[16933]=76,[16934]=76,[16935]=76,[16936]=76,[16937]=76,[16938]=76,[16939]=76,[16940]=76,[16941]=76, + [16942]=76,[16943]=76,[16944]=76,[16945]=76,[16946]=76,[16947]=76,[16948]=76,[16949]=76,[16950]=76,[16951]=76, + [16952]=76,[16953]=76,[16954]=76,[16955]=76,[16956]=76,[16957]=76,[16958]=76,[16959]=76,[16960]=76,[16961]=76, + [16962]=76,[16963]=76,[16964]=76,[16965]=76,[16966]=76,[16967]=40,[16975]=27,[16977]=27,[16978]=27,[16979]=62, + [16980]=61,[16981]=20,[16982]=59,[16983]=60,[16984]=61,[16985]=25,[16986]=25,[16987]=27,[16988]=62,[16989]=59, + [16990]=27,[16992]=60,[16993]=60,[16994]=60,[16995]=60,[16996]=62,[16997]=62,[16998]=62,[16999]=59,[17000]=62, + [17001]=62,[17002]=61,[17003]=61,[17004]=61,[17005]=27,[17006]=27,[17007]=51,[17013]=60,[17014]=59,[17015]=65, + [17016]=65,[647]=57,[17039]=36,[17040]=1,[17041]=1,[17042]=36,[17043]=36,[17044]=61,[17045]=61,[17046]=31,[17047]=30, + [17050]=52,[17054]=50,[17055]=50,[17061]=58,[17063]=78,[17064]=71,[17065]=61,[17066]=60,[17067]=76,[17068]=75, + [17069]=69,[17070]=70,[17071]=69,[17072]=70,[17073]=60,[17074]=63,[17075]=63,[17076]=77,[17077]=63,[17078]=63, + [17082]=74,[710]=14,[711]=5,[714]=5,[718]=22,[719]=5,[720]=28,[17104]=76,[17105]=65,[17106]=75,[17107]=73,[17108]=65, + [17109]=65,[727]=10,[17111]=68,[17112]=66,[17113]=67,[17123]=1,[744]=44,[751]=3,[753]=28,[754]=47,[756]=29,[17142]=70, + [763]=12,[766]=7,[767]=8,[768]=9,[776]=31,[778]=7,[781]=9,[788]=1,[789]=22,[790]=23,[791]=31,[792]=10,[793]=10, + [794]=10,[795]=10,[796]=10,[797]=10,[798]=10,[799]=10,[17183]=3,[17184]=3,[17185]=8,[17186]=8,[17187]=14,[17188]=19, + [17189]=34,[17190]=47,[809]=50,[810]=54,[811]=57,[812]=54,[816]=11,[820]=17,[821]=13,[826]=15,[827]=17,[832]=15, + [833]=56,[837]=17,[838]=17,[839]=17,[840]=17,[843]=17,[844]=17,[845]=17,[846]=17,[847]=17,[848]=17,[849]=17,[850]=17, + [851]=15,[852]=14,[853]=16,[854]=16,[860]=13,[862]=50,[863]=37,[864]=38,[865]=31,[866]=42,[867]=42,[868]=43,[869]=41, + [870]=40,[871]=47,[872]=21,[873]=40,[876]=1,[880]=23,[885]=24,[886]=26,[888]=27,[890]=24,[892]=22,[897]=29,[899]=19, + [17283]=1,[905]=1,[906]=1,[907]=1,[908]=1,[909]=1,[911]=25,[913]=29,[914]=30,[917]=18,[920]=25,[922]=26,[923]=26, + [924]=26,[925]=25,[926]=25,[927]=24,[928]=25,[934]=37,[935]=20,[936]=38,[937]=38,[940]=47,[941]=40,[942]=52,[943]=48, + [944]=61,[945]=1,[948]=1,[17342]=1,[17343]=1,[983]=9,[996]=2,[997]=1,[17382]=1,[17383]=1,[1008]=10,[1009]=13, + [1010]=8,[1011]=8,[1018]=1,[1020]=1,[1021]=1,[1022]=1,[1023]=1,[1024]=1,[1025]=1,[1026]=1,[1027]=1,[1028]=20, + [1046]=1,[1047]=1,[1076]=25,[1077]=26,[17462]=1,[17463]=1,[17482]=1,[1116]=31,[1117]=1,[1121]=24,[1122]=45,[1123]=45, + [1124]=45,[17508]=41,[1131]=25,[17523]=58,[1154]=14,[1155]=29,[1156]=22,[1157]=4,[1158]=10,[1159]=5,[1161]=5, + [1162]=10,[1163]=10,[1166]=5,[1167]=10,[1168]=59,[1169]=46,[1170]=8,[1171]=10,[1172]=21,[1173]=10,[1174]=10,[17562]=63, + [17563]=60,[17564]=63,[1182]=10,[17566]=63,[17567]=63,[17568]=63,[17569]=63,[17570]=63,[17571]=63,[17572]=63, + [17573]=63,[17574]=60,[1192]=20,[17576]=63,[17577]=63,[1195]=6,[1196]=14,[1197]=15,[1198]=15,[17582]=65,[17583]=65, + [17584]=65,[1202]=17,[17586]=65,[1204]=41,[17588]=65,[17589]=65,[1207]=39,[17591]=65,[17592]=65,[17593]=71,[17594]=63, + [17595]=60,[17596]=63,[1214]=17,[17598]=63,[17599]=63,[17600]=63,[17601]=63,[17602]=65,[17603]=65,[17604]=65, + [17605]=65,[17606]=65,[17607]=65,[17608]=65,[17609]=65,[17610]=63,[17611]=63,[17612]=63,[17613]=63,[17614]=60, + [17615]=60,[17616]=63,[17617]=63,[17618]=65,[17619]=65,[17620]=65,[17621]=65,[17622]=65,[17623]=65,[17624]=65, + [17625]=65,[1254]=28,[1258]=40,[1259]=1,[1263]=60,[1264]=26,[1265]=39,[1266]=20,[1270]=15,[1272]=18,[1273]=25, + [1275]=25,[1276]=27,[1279]=19,[1280]=38,[1282]=33,[1287]=15,[1292]=25,[1296]=21,[1297]=31,[1298]=18,[1299]=22, + [1300]=20,[1302]=18,[1303]=20,[1304]=20,[17688]=40,[1306]=20,[17690]=60,[17691]=60,[17692]=23,[1310]=20,[17694]=25, + [17695]=26,[1313]=18,[1314]=20,[1315]=51,[1317]=25,[1318]=23,[1319]=25,[17704]=38,[17705]=53,[17707]=54,[17710]=54, + [17711]=54,[17713]=54,[17714]=54,[17715]=54,[17717]=53,[17718]=53,[17719]=53,[17721]=38,[17728]=53,[17730]=53, + [17732]=53,[17733]=53,[1351]=28,[17736]=53,[17737]=53,[1355]=15,[17739]=52,[17740]=52,[17741]=51,[1359]=8,[1360]=10, + [17744]=51,[17745]=51,[17746]=51,[1364]=5,[17748]=51,[17749]=51,[17750]=51,[17751]=51,[17752]=50,[1370]=4,[17754]=50, + [1372]=3,[1374]=4,[1376]=5,[1377]=3,[1378]=2,[1379]=3,[1380]=4,[1382]=5,[17766]=54,[1384]=3,[17768]=47,[1386]=5, + [17770]=47,[1388]=3,[1389]=7,[17773]=42,[1391]=18,[17775]=47,[17776]=47,[17777]=47,[17778]=47,[17779]=47,[17780]=54, + [1398]=1,[17782]=80,[17783]=80,[1403]=40,[1404]=41,[1405]=17,[1406]=21,[1411]=8,[1412]=7,[1413]=8,[1414]=9,[1415]=9, + [1416]=9,[1417]=8,[1418]=7,[1419]=8,[1420]=9,[1421]=10,[1422]=6,[1423]=7,[1424]=8,[1425]=9,[1427]=10,[1429]=6, + [1430]=7,[1431]=8,[1432]=9,[1433]=7,[1435]=15,[1436]=17,[1438]=9,[1440]=19,[1443]=60,[1444]=40,[1445]=23,[1446]=19, + [1447]=46,[1448]=20,[1449]=24,[1454]=27,[1455]=24,[1457]=22,[1458]=23,[1459]=24,[1460]=20,[1461]=25,[1462]=25, + [1465]=38,[1469]=19,[1472]=40,[1473]=19,[1479]=12,[1480]=17,[1481]=25,[1482]=24,[1483]=21,[1484]=22,[1485]=25, + [1486]=24,[1488]=31,[1489]=25,[1490]=50,[1491]=25,[1493]=27,[1495]=13,[1497]=14,[1498]=15,[1499]=11,[1500]=12, + [1501]=13,[1502]=14,[1503]=15,[1504]=11,[1505]=12,[1506]=13,[1507]=14,[1508]=15,[1509]=11,[1510]=12,[1511]=13, + [1512]=12,[1513]=14,[1514]=14,[1515]=12,[1516]=14,[17900]=60,[17901]=60,[17902]=60,[17903]=60,[1521]=44,[17905]=60, + [1523]=36,[17907]=60,[17908]=60,[17909]=60,[1535]=38,[1539]=19,[1544]=40,[1545]=18,[1547]=30,[1557]=20,[17942]=1, + [17943]=53,[1561]=15,[1566]=17,[17982]=65,[1602]=39,[1604]=45,[1607]=54,[1608]=47,[1613]=44,[18002]=1,[1622]=42, + [1624]=43,[1625]=41,[18022]=62,[1640]=42,[1659]=40,[18043]=57,[18044]=57,[18047]=62,[18048]=62,[1677]=46,[1678]=37, + [1679]=36,[1680]=44,[1684]=44,[18082]=47,[18083]=47,[1713]=45,[1714]=43,[1715]=44,[1716]=40,[1717]=30,[1718]=43, + [18102]=63,[18103]=63,[18104]=63,[1722]=42,[1726]=36,[1727]=28,[1728]=65,[1730]=12,[1731]=13,[1732]=14,[1733]=15, + [1734]=11,[1735]=12,[1736]=13,[1737]=14,[1738]=19,[1739]=20,[1740]=16,[1741]=17,[1742]=18,[1743]=19,[1744]=20, + [1745]=16,[1746]=25,[1747]=21,[1748]=22,[1749]=23,[1750]=24,[1751]=25,[1752]=21,[1753]=22,[1754]=26,[1755]=27, + [1756]=28,[1757]=29,[1758]=30,[1759]=26,[1760]=27,[1761]=28,[1764]=17,[1766]=18,[1767]=19,[1768]=20,[1769]=20, + [1770]=17,[1772]=23,[1774]=24,[1775]=25,[1776]=21,[1777]=22,[1778]=23,[18162]=1,[1780]=29,[18164]=1,[1782]=30, + [1783]=26,[1784]=27,[1785]=28,[1786]=29,[1787]=18,[1788]=19,[1789]=20,[1790]=16,[1791]=17,[1792]=18,[1793]=20, + [1794]=20,[1795]=24,[1796]=25,[1797]=21,[1798]=22,[1799]=23,[1800]=24,[1801]=25,[1802]=21,[1803]=30,[1804]=26, + [1805]=27,[1806]=28,[1807]=29,[1808]=30,[1809]=26,[1810]=27,[1811]=17,[1812]=17,[1813]=18,[1814]=19,[1815]=17, + [1816]=19,[1817]=19,[1818]=24,[1819]=22,[1820]=22,[1821]=24,[18205]=71,[1823]=22,[1824]=23,[18208]=67,[1826]=27, + [1827]=27,[1828]=27,[1829]=29,[1830]=28,[1831]=28,[1832]=17,[1835]=5,[1836]=5,[1839]=10,[1840]=10,[1843]=17,[1844]=17, + [1845]=17,[1846]=17,[1849]=22,[1850]=22,[1852]=22,[1853]=22,[1854]=40,[18238]=40,[18263]=64,[1893]=20,[1895]=1, + [1896]=1,[1897]=1,[18282]=65,[1900]=1,[1901]=1,[1902]=1,[1903]=1,[1904]=1,[1905]=1,[18289]=56,[1907]=1,[1908]=1, + [1909]=1,[18293]=1,[1911]=1,[18295]=55,[1913]=10,[1914]=40,[18298]=56,[1917]=10,[18301]=58,[18302]=58,[18303]=58, + [18304]=58,[18305]=58,[18306]=58,[18307]=58,[18308]=58,[18309]=59,[18310]=59,[18311]=58,[18312]=59,[1930]=18, + [18314]=59,[18315]=59,[1933]=15,[18317]=58,[18318]=59,[18319]=58,[1937]=21,[1938]=22,[18322]=58,[18323]=58,[18324]=58, + [18325]=58,[18326]=59,[18327]=59,[18328]=59,[1948]=16,[1951]=19,[18337]=59,[1955]=27,[18339]=59,[18340]=59,[1958]=17, + [1959]=17,[18343]=59,[18344]=59,[18345]=60,[18346]=60,[18347]=61,[18348]=71,[18349]=61,[18350]=61,[18351]=61, + [18352]=61,[18353]=61,[18354]=60,[18355]=60,[1973]=59,[1974]=22,[1975]=28,[1976]=29,[1978]=27,[1979]=50,[1980]=43, + [1981]=44,[1982]=44,[18366]=60,[18367]=60,[18368]=60,[1986]=41,[18370]=62,[18371]=61,[18372]=62,[18373]=62,[18374]=62, + [18375]=62,[18376]=62,[18377]=62,[18378]=62,[18379]=62,[18380]=62,[18381]=62,[18382]=62,[18383]=61,[18384]=62, + [18385]=62,[18386]=61,[18387]=60,[18388]=62,[18389]=62,[18390]=61,[18391]=62,[18392]=62,[18393]=61,[2011]=26, + [18395]=62,[18396]=62,[18397]=61,[2015]=28,[18399]=63,[18400]=57,[2018]=27,[18402]=57,[18403]=74,[2021]=21,[18405]=62, + [18406]=74,[18407]=62,[18408]=62,[2026]=21,[2027]=19,[18411]=57,[2029]=20,[18413]=62,[2032]=36,[2033]=25,[2034]=25, + [2035]=24,[2036]=18,[2037]=18,[18421]=63,[2039]=29,[2040]=48,[18424]=63,[18425]=60,[2043]=35,[18427]=35,[18428]=50, + [18429]=63,[18430]=50,[2048]=5,[18432]=50,[18434]=63,[18435]=50,[18436]=50,[18437]=50,[2055]=4,[2056]=10,[18440]=35, + [18441]=50,[2059]=24,[18443]=63,[18444]=50,[18445]=63,[18447]=50,[18448]=63,[18449]=50,[18450]=60,[18451]=60, + [18452]=63,[18453]=50,[18454]=63,[18455]=50,[18456]=63,[18457]=50,[18458]=60,[18459]=60,[18460]=60,[18461]=63, + [18462]=60,[18463]=60,[18464]=60,[18465]=62,[18466]=62,[18467]=62,[18468]=62,[18469]=62,[18470]=62,[18471]=62, + [18472]=62,[18473]=62,[2092]=2,[18476]=60,[18477]=60,[18478]=60,[18479]=60,[18480]=60,[18481]=60,[18482]=60,[2100]=48, + [18484]=61,[18485]=61,[18486]=61,[2106]=1,[18490]=61,[18491]=57,[2109]=5,[2110]=4,[18494]=60,[2112]=9,[18496]=60, + [2114]=8,[18498]=60,[18499]=62,[2117]=5,[2119]=5,[2120]=5,[2121]=5,[2122]=5,[18506]=62,[18507]=62,[18508]=62, + [18509]=62,[2127]=5,[18511]=62,[2129]=5,[2130]=3,[2131]=3,[2132]=4,[2133]=5,[2134]=4,[2137]=5,[18521]=63,[2139]=3, + [2140]=11,[18524]=63,[2142]=27,[2143]=27,[2144]=27,[2145]=27,[2146]=27,[18530]=62,[2148]=27,[2149]=27,[2150]=27, + [2151]=27,[2152]=27,[2153]=27,[18537]=63,[18538]=63,[2156]=27,[2158]=27,[2159]=27,[2160]=27,[18544]=71,[18545]=69, + [2163]=53,[2164]=45,[2165]=10,[2166]=20,[2167]=20,[2168]=21,[2169]=21,[2170]=20,[2172]=5,[2173]=5,[2175]=23,[2176]=1, + [2177]=1,[2178]=1,[2179]=1,[2180]=1,[2181]=1,[18565]=35,[18566]=35,[2184]=1,[2186]=5,[2189]=100,[2194]=25,[2195]=5, + [2196]=1,[2197]=1,[2198]=1,[18582]=100,[18583]=100,[18584]=100,[18585]=35,[2203]=19,[2204]=17,[2205]=25,[2206]=22, + [2207]=16,[2208]=19,[2209]=24,[2210]=2,[2211]=4,[2212]=6,[2213]=7,[2214]=15,[2215]=11,[2216]=16,[2217]=17,[2218]=13, + [18602]=60,[2220]=23,[2221]=28,[2222]=29,[2224]=5,[2225]=11,[2226]=27,[18610]=6,[18611]=7,[18612]=8,[2230]=24, + [2231]=40,[2232]=25,[2233]=27,[2234]=30,[2235]=19,[2236]=25,[2237]=10,[2238]=10,[2240]=15,[2241]=20,[2243]=62, + [2244]=56,[2245]=59,[2246]=58,[2249]=10,[18634]=52,[2254]=12,[18638]=58,[2256]=24,[2257]=10,[2258]=8,[2259]=8, + [2260]=9,[18644]=1,[2262]=36,[2263]=25,[2264]=30,[2265]=13,[2266]=13,[2267]=15,[2268]=10,[2271]=23,[2273]=15, + [2274]=17,[2275]=20,[2276]=37,[2277]=35,[2278]=31,[2280]=27,[2281]=11,[2282]=10,[2283]=15,[2284]=15,[18671]=59, + [18672]=59,[18673]=59,[2291]=49,[2292]=25,[18676]=61,[18677]=61,[18678]=61,[18679]=61,[18680]=61,[18681]=61,[2299]=33, + [2300]=12,[18684]=61,[2302]=8,[2303]=10,[2305]=6,[18689]=62,[2307]=18,[18691]=61,[18692]=59,[2310]=13,[18694]=62, + [18695]=62,[18696]=62,[2314]=24,[18698]=56,[2316]=22,[18700]=58,[18701]=59,[18702]=60,[18706]=40,[2326]=10,[18710]=50, + [18711]=50,[18712]=50,[18713]=75,[18715]=75,[18716]=61,[18717]=63,[18718]=63,[18720]=63,[18721]=61,[18722]=62, + [18723]=62,[18725]=59,[18726]=59,[18727]=59,[18728]=60,[18729]=60,[18730]=60,[18734]=62,[18735]=62,[18736]=62, + [18737]=62,[18738]=61,[18739]=61,[18740]=61,[18741]=61,[18742]=60,[18743]=59,[2361]=2,[2362]=1,[2364]=10,[2366]=10, + [2367]=10,[2369]=10,[2370]=10,[2371]=10,[2372]=10,[2373]=10,[2374]=10,[2375]=10,[18759]=62,[2377]=10,[18761]=62, + [18762]=54,[2380]=5,[2381]=5,[18765]=52,[2383]=5,[2384]=5,[2385]=5,[2386]=5,[2387]=5,[2388]=5,[2389]=5,[2390]=5, + [2391]=5,[2392]=10,[2393]=10,[2394]=10,[2395]=10,[2396]=10,[2397]=10,[2398]=10,[2399]=10,[2400]=10,[2401]=10, + [2402]=10,[2403]=10,[2410]=1,[2417]=37,[2418]=37,[2419]=37,[2420]=37,[2421]=37,[2422]=37,[2423]=50,[2424]=50, + [2425]=50,[2426]=50,[2427]=50,[18811]=71,[2429]=37,[18813]=73,[2431]=37,[18815]=75,[18816]=77,[18817]=76,[2435]=50, + [18820]=66,[2438]=50,[18822]=68,[18823]=69,[18824]=70,[18825]=78,[18826]=78,[18827]=78,[18828]=78,[18829]=71, + [18830]=78,[2448]=37,[18832]=70,[18833]=78,[2451]=50,[18835]=78,[18836]=78,[18837]=78,[18838]=78,[18840]=78,[18842]=70, + [18843]=78,[18844]=78,[18845]=0,[18846]=0,[18847]=78,[18848]=78,[18849]=0,[18850]=0,[18851]=0,[2469]=37,[2470]=50, + [2471]=50,[2472]=50,[2473]=50,[2474]=50,[2475]=50,[18859]=0,[18860]=78,[18861]=61,[2479]=4,[2480]=3,[18864]=0, + [18865]=78,[18866]=78,[18867]=78,[18868]=78,[18869]=78,[18870]=62,[2488]=9,[2489]=7,[2490]=9,[2491]=8,[2492]=7, + [2493]=9,[2494]=8,[18878]=65,[18879]=66,[2497]=9,[2498]=8,[2499]=9,[2500]=7,[2501]=9,[2502]=7,[2503]=8,[2504]=2, + [2505]=4,[2506]=8,[2507]=16,[2508]=2,[2509]=9,[2510]=3,[2511]=14,[2520]=36,[2521]=36,[2522]=35,[2523]=35,[2524]=34, + [2525]=35,[2526]=34,[2527]=36,[2528]=46,[2529]=46,[2530]=46,[2531]=44,[2532]=46,[2533]=45,[2534]=44,[2535]=45, + [2543]=3,[2545]=26,[2546]=11,[2547]=5,[2549]=27,[2550]=1,[2551]=1,[2552]=1,[2557]=1,[2558]=1,[2559]=1,[2562]=23, + [2564]=50,[2565]=35,[2566]=27,[2567]=23,[2568]=8,[2569]=13,[2570]=6,[2571]=7,[2572]=10,[2573]=9,[18957]=10,[2578]=14, + [2580]=12,[2582]=17,[2583]=19,[2584]=16,[2585]=21,[2586]=1,[18970]=60,[2588]=20,[18982]=60,[18983]=1,[18984]=55, + [18985]=1,[18986]=52,[2612]=8,[2613]=13,[2614]=17,[2615]=29,[2616]=23,[2617]=37,[2618]=50,[2620]=39,[2621]=36, + [2622]=37,[2623]=41,[2624]=42,[19014]=1,[2632]=14,[2635]=8,[19019]=80,[19022]=50,[19024]=55,[2642]=9,[2643]=10, + [2644]=6,[19028]=30,[2646]=8,[2647]=9,[2648]=10,[2649]=2,[2650]=3,[2651]=4,[2652]=5,[2653]=4,[19037]=48,[19038]=48, + [19039]=48,[19040]=48,[19041]=48,[19042]=48,[19043]=58,[19044]=58,[19047]=58,[19048]=64,[19049]=64,[19050]=64, + [19051]=58,[19052]=58,[19053]=1,[19056]=58,[19057]=64,[19058]=64,[19059]=64,[19065]=59,[2690]=5,[2691]=5,[2694]=17, + [2695]=1,[19083]=60,[19084]=60,[19085]=60,[19086]=60,[19087]=60,[19088]=60,[19089]=60,[19090]=60,[19091]=60,[19092]=60, + [19093]=60,[19094]=60,[19095]=60,[19096]=60,[19097]=60,[19098]=60,[19099]=65,[19100]=65,[19101]=65,[19102]=65, + [19103]=65,[2721]=32,[19105]=63,[19106]=63,[19107]=63,[19108]=63,[19109]=63,[19110]=63,[19111]=63,[19112]=63, + [19113]=63,[19114]=51,[19115]=51,[19116]=50,[19117]=50,[19118]=50,[19119]=50,[19120]=51,[19121]=51,[19123]=48, + [19124]=48,[19125]=49,[19126]=49,[19127]=50,[19128]=50,[19129]=49,[19130]=70,[19131]=69,[19132]=68,[19133]=71, + [19134]=68,[19135]=66,[19136]=71,[2754]=3,[19138]=78,[19139]=71,[19140]=71,[19141]=50,[19142]=70,[19143]=69,[19144]=68, + [19145]=66,[2763]=14,[2764]=18,[2765]=23,[2766]=29,[2773]=8,[2774]=7,[19158]=80,[19159]=51,[2777]=13,[2778]=13, + [19162]=70,[2780]=19,[2781]=18,[2782]=24,[2783]=22,[19167]=66,[2785]=28,[2786]=29,[2787]=3,[2800]=26,[2801]=64, + [2802]=43,[2803]=40,[2804]=40,[2805]=34,[19189]=63,[2807]=23,[2808]=29,[2809]=1,[2810]=1,[2811]=29,[2812]=29, + [2813]=1,[2814]=29,[2815]=45,[2816]=33,[2817]=12,[2818]=15,[2819]=28,[2820]=50,[2821]=18,[2822]=18,[2823]=19, + [2824]=53,[2825]=42,[2826]=40,[2827]=1,[19214]=1,[19226]=60,[2844]=9,[2845]=9,[2847]=9,[2848]=22,[2849]=23,[2850]=24, + [2851]=11,[2852]=9,[2853]=7,[2854]=19,[2857]=18,[2864]=18,[2865]=21,[2866]=23,[2867]=23,[2868]=25,[2869]=26,[2870]=29, + [2877]=33,[2878]=30,[2879]=22,[2884]=1,[2898]=7,[2899]=15,[2900]=10,[2901]=4,[2902]=30,[2903]=15,[2904]=16,[2905]=10, + [2906]=26,[2907]=20,[2908]=20,[19292]=34,[19293]=55,[2911]=23,[19295]=20,[2913]=28,[2915]=52,[2916]=34,[2917]=33, + [2918]=26,[19302]=55,[19303]=55,[2921]=15,[2922]=20,[2923]=25,[19308]=65,[19309]=65,[19310]=65,[19311]=65,[19312]=65, + [19313]=63,[19314]=63,[19315]=65,[2933]=31,[19321]=65,[19323]=65,[2941]=26,[2942]=26,[2943]=31,[2944]=31,[2945]=3, + [2946]=8,[2947]=3,[2948]=40,[2949]=25,[2950]=25,[2951]=36,[19335]=73,[2953]=33,[2954]=33,[2955]=40,[19339]=76, + [2957]=11,[2958]=10,[2959]=9,[2960]=9,[2961]=11,[2962]=10,[2963]=9,[2964]=10,[2965]=11,[2966]=10,[2967]=10,[2968]=9, + [2969]=17,[2970]=16,[2971]=14,[2972]=14,[19356]=81,[19357]=75,[19358]=70,[2976]=15,[19360]=81,[19361]=77,[19362]=70, + [19363]=81,[19364]=81,[19365]=75,[19366]=83,[19367]=75,[19368]=75,[19369]=73,[2987]=18,[2988]=19,[2989]=21,[2990]=21, + [2991]=21,[2992]=20,[19376]=83,[19377]=83,[19378]=83,[19379]=83,[19380]=83,[19381]=83,[19382]=83,[3000]=10,[19384]=83, + [19385]=77,[19386]=77,[19387]=77,[19388]=77,[19389]=77,[19390]=77,[3008]=9,[19392]=77,[19393]=77,[3011]=36,[19395]=75, + [19396]=75,[19397]=75,[19398]=75,[19399]=75,[19400]=75,[3018]=23,[3019]=18,[3020]=33,[3021]=25,[3022]=23,[3023]=21, + [3024]=26,[3025]=36,[3026]=21,[3027]=25,[3028]=34,[3036]=15,[3037]=34,[3038]=25,[3039]=23,[3040]=19,[3041]=31, + [3042]=33,[19426]=65,[3044]=1,[3045]=27,[3046]=26,[3047]=27,[3048]=26,[3049]=27,[19433]=75,[19434]=70,[19435]=70, + [3053]=28,[19437]=70,[3055]=26,[3056]=26,[3057]=24,[3058]=25,[3059]=26,[3060]=27,[3061]=28,[3062]=25,[3063]=27, + [3064]=25,[3065]=23,[3066]=24,[3067]=26,[3068]=32,[3069]=27,[3070]=5,[3071]=12,[3072]=26,[3073]=26,[3074]=24, + [3075]=55,[3076]=23,[3077]=26,[3078]=26,[3079]=12,[19485]=1,[3103]=12,[19487]=1,[19488]=1,[19489]=63,[3107]=16, + [3108]=27,[3109]=26,[3111]=3,[19502]=63,[19503]=80,[19504]=70,[19507]=41,[19508]=41,[19509]=41,[19510]=63,[19511]=53, + [19512]=43,[19513]=33,[3131]=8,[19515]=43,[19516]=53,[19517]=33,[3135]=16,[19519]=53,[3137]=27,[19521]=33,[19522]=63, + [19523]=53,[19524]=43,[19525]=33,[19526]=63,[19527]=53,[19528]=43,[19529]=33,[19530]=63,[19531]=53,[19532]=43, + [19533]=33,[19534]=63,[19535]=53,[19536]=43,[3154]=18,[19538]=63,[19539]=53,[19540]=43,[3158]=12,[19542]=63,[19543]=53, + [3161]=15,[19545]=33,[19546]=63,[19547]=53,[19548]=43,[3166]=15,[19550]=63,[19551]=53,[19552]=43,[19553]=33,[19554]=63, + [19555]=53,[19556]=43,[19557]=33,[19558]=63,[19559]=53,[19560]=43,[19561]=33,[19562]=63,[19563]=53,[19564]=43, + [19565]=33,[19566]=63,[19567]=53,[19568]=43,[19569]=33,[19570]=63,[19571]=53,[19572]=43,[19573]=33,[19574]=60, + [19575]=60,[19576]=68,[19577]=65,[19578]=65,[19579]=60,[19580]=55,[19581]=45,[19582]=65,[19583]=55,[19584]=45, + [19585]=60,[19586]=68,[19587]=65,[19588]=65,[19589]=55,[19590]=45,[19591]=60,[19592]=60,[19593]=68,[19594]=65, + [19595]=65,[19596]=55,[3214]=9,[19598]=60,[19599]=60,[3217]=15,[19601]=65,[19602]=60,[19603]=60,[19604]=68,[19605]=65, + [19606]=60,[19607]=60,[3225]=9,[19609]=65,[19610]=60,[19611]=60,[19612]=68,[19613]=65,[3231]=25,[19615]=60,[19616]=68, + [19617]=65,[3235]=20,[19619]=60,[19620]=68,[19621]=65,[19622]=63,[19623]=1,[3242]=1,[3243]=1,[3244]=1,[3245]=1, + [3246]=1,[3247]=1,[3260]=4,[3261]=5,[3262]=3,[3263]=3,[3267]=5,[3268]=5,[3269]=5,[3270]=5,[3271]=4,[3272]=5,[3273]=5, + [3274]=5,[3275]=5,[3276]=5,[3277]=5,[3278]=30,[3279]=12,[3280]=9,[3281]=11,[3282]=12,[3283]=13,[3284]=12,[3285]=10, + [3286]=12,[3287]=12,[3288]=13,[3289]=11,[3290]=12,[3291]=13,[3292]=13,[3293]=3,[3294]=3,[3295]=3,[3296]=3,[19682]=65, + [19683]=65,[19684]=65,[19685]=65,[19686]=65,[19687]=65,[19688]=65,[19689]=65,[19690]=65,[19691]=65,[19692]=65, + [19693]=65,[19694]=65,[19695]=65,[3313]=18,[3314]=15,[3315]=17,[3319]=9,[3320]=9,[3321]=9,[3322]=6,[3323]=8,[3324]=28, + [3325]=9,[3326]=1,[3327]=9,[3328]=9,[3329]=11,[3330]=13,[3331]=12,[3332]=9,[3333]=11,[3334]=7,[3335]=6,[3336]=29, + [3341]=32,[3344]=15,[3345]=37,[3346]=1,[3350]=1,[3351]=1,[19742]=60,[3360]=30,[3361]=1,[3362]=1,[3363]=3,[3364]=1, + [3365]=5,[3366]=1,[3367]=1,[3368]=1,[3370]=8,[3373]=9,[3374]=14,[3375]=12,[3376]=18,[3377]=19,[3378]=21,[3379]=22, + [3380]=30,[3381]=28,[3392]=30,[3398]=71,[3400]=25,[3413]=25,[3414]=27,[3415]=24,[3416]=26,[3417]=26,[3419]=20, + [3420]=40,[3421]=10,[3422]=30,[3423]=50,[3424]=60,[19808]=45,[19809]=60,[19810]=60,[19811]=60,[19812]=61,[3430]=44, + [3431]=25,[3432]=1,[3433]=1,[3435]=8,[3436]=8,[3437]=8,[19822]=65,[19823]=61,[19824]=61,[19825]=65,[19826]=61, + [19827]=61,[19828]=65,[19829]=61,[3447]=8,[19831]=68,[19832]=61,[19833]=61,[19834]=65,[19835]=61,[19836]=61,[3454]=14, + [3455]=11,[19839]=61,[19840]=61,[3458]=18,[19842]=61,[19843]=61,[3461]=24,[19845]=61,[3463]=37,[19847]=65,[19848]=61, + [19849]=61,[3469]=9,[19853]=68,[19854]=68,[19855]=68,[19856]=68,[19857]=68,[3475]=65,[19859]=68,[19861]=68,[19862]=68, + [19863]=71,[19864]=68,[19865]=68,[19866]=66,[19867]=66,[3485]=30,[19869]=71,[19870]=71,[19871]=68,[3489]=17,[19873]=71, + [19874]=66,[19875]=71,[19876]=68,[19877]=71,[19878]=71,[19879]=70,[19884]=66,[19885]=66,[19886]=71,[19887]=71, + [19888]=71,[19889]=71,[19890]=66,[19891]=66,[19892]=71,[19893]=71,[19894]=71,[19895]=71,[19896]=65,[19897]=65, + [19898]=68,[19899]=68,[19900]=68,[19901]=68,[19903]=65,[19904]=65,[19905]=68,[19906]=68,[19907]=68,[19908]=65, + [19909]=65,[19910]=65,[3528]=1,[19912]=68,[19913]=68,[19915]=68,[19916]=1,[19917]=1,[19918]=65,[19919]=68,[19920]=68, + [19921]=65,[19922]=68,[19923]=68,[19924]=1,[19925]=68,[3543]=1,[19927]=65,[19928]=68,[19929]=71,[19930]=68,[3548]=1, + [3549]=1,[3555]=25,[3556]=30,[3558]=25,[3559]=21,[3560]=35,[19944]=65,[19945]=65,[19946]=68,[19947]=68,[19948]=68, + [19949]=68,[3567]=19,[19951]=65,[3569]=26,[3570]=16,[3571]=21,[19955]=65,[19956]=65,[19957]=65,[19958]=65,[19959]=65, + [3578]=15,[19962]=68,[19963]=68,[19964]=68,[19965]=68,[3583]=12,[19967]=68,[19968]=68,[19969]=40,[19970]=20,[3588]=50, + [19972]=40,[3590]=17,[3591]=27,[3592]=27,[3593]=37,[3594]=37,[3595]=5,[19979]=65,[3597]=22,[3598]=22,[19982]=52, + [3600]=5,[19984]=52,[3602]=10,[3603]=10,[19987]=1,[19988]=1,[3606]=10,[3607]=10,[19991]=52,[19992]=52,[19993]=68, + [19998]=65,[19999]=65,[20003]=52,[20005]=52,[20006]=52,[3641]=8,[3642]=9,[3643]=14,[3644]=12,[3645]=17,[3646]=26, + [3647]=23,[3648]=9,[20032]=65,[20033]=65,[20034]=65,[20035]=52,[20036]=52,[20037]=52,[20038]=66,[20039]=70,[20041]=63, + [20042]=63,[20043]=63,[3661]=2,[20045]=63,[20046]=63,[20047]=63,[20048]=63,[20049]=63,[20050]=63,[20051]=63,[20052]=63, + [20053]=63,[20054]=63,[20055]=65,[20056]=65,[20057]=65,[20058]=65,[20059]=65,[20060]=65,[20061]=65,[20068]=65, + [20069]=65,[20070]=65,[20071]=63,[20072]=63,[20073]=65,[3694]=1,[3695]=1,[3696]=1,[3697]=1,[3698]=1,[20082]=52, + [20083]=52,[20084]=52,[20086]=52,[20088]=53,[20089]=43,[20090]=33,[20091]=53,[20092]=43,[20093]=33,[20094]=53, + [20095]=43,[20096]=33,[20097]=53,[20098]=43,[20099]=33,[20100]=53,[20101]=43,[20102]=33,[20103]=53,[20104]=43, + [20105]=33,[20106]=53,[20107]=43,[20108]=33,[20109]=53,[20110]=43,[20111]=33,[20112]=53,[20113]=43,[20114]=33, + [20115]=53,[20116]=43,[20117]=33,[20118]=53,[20119]=43,[20120]=33,[3738]=25,[3739]=25,[3740]=24,[20124]=53,[20125]=43, + [20126]=33,[20127]=53,[20128]=43,[20129]=33,[20130]=52,[3748]=28,[3749]=30,[3750]=30,[20134]=62,[3752]=22,[3753]=34, + [3754]=33,[3755]=32,[3756]=1,[3757]=1,[3758]=33,[3759]=33,[3760]=32,[3761]=32,[20145]=90,[3763]=40,[3764]=40, + [3765]=40,[20149]=90,[20150]=63,[20151]=53,[20152]=33,[20153]=43,[20154]=63,[20155]=53,[20156]=43,[20157]=33, + [20158]=65,[20159]=63,[20160]=53,[20161]=43,[20162]=33,[20163]=63,[20164]=33,[3782]=35,[3783]=36,[20167]=63,[20168]=43, + [20169]=33,[20170]=53,[20171]=63,[20172]=33,[20173]=43,[20174]=53,[20175]=65,[20176]=65,[3794]=38,[3795]=36,[3796]=33, + [3797]=39,[3798]=35,[3799]=37,[3800]=39,[3801]=35,[3802]=34,[20186]=63,[20187]=43,[20188]=33,[20189]=53,[20190]=63, + [20191]=33,[20192]=43,[20193]=53,[20194]=65,[20195]=63,[20196]=53,[20197]=33,[20198]=43,[20199]=63,[20200]=43, + [20201]=33,[20202]=53,[20203]=65,[20204]=63,[20205]=53,[20206]=43,[20207]=33,[20208]=63,[20209]=43,[20210]=33, + [20211]=53,[20212]=65,[20213]=70,[20214]=65,[20215]=70,[20216]=70,[20217]=70,[20218]=59,[20219]=59,[20220]=65, + [3840]=32,[3841]=35,[3842]=31,[3843]=34,[3844]=36,[3845]=40,[3846]=37,[3847]=40,[3848]=20,[3849]=32,[3850]=35, + [3851]=31,[3852]=34,[3853]=36,[3854]=40,[3855]=37,[3856]=40,[20240]=90,[20241]=90,[20242]=90,[20245]=90,[20246]=90, + [20247]=90,[3865]=2,[20249]=90,[20250]=90,[20251]=90,[20252]=90,[20255]=52,[20257]=68,[20258]=65,[20259]=65,[20260]=68, + [20261]=65,[20262]=68,[20263]=65,[20264]=68,[20265]=68,[20266]=68,[3884]=22,[3885]=22,[3886]=27,[3887]=27,[3888]=27, + [3889]=37,[3890]=37,[3891]=37,[3892]=50,[3893]=50,[3894]=50,[3895]=30,[20279]=90,[20280]=63,[20281]=63,[20282]=63, + [20283]=63,[20284]=63,[3902]=18,[20286]=63,[20287]=63,[20288]=63,[20289]=63,[20290]=63,[20291]=63,[20292]=63, + [20294]=59,[20295]=60,[20296]=56,[20297]=90,[20298]=90,[20299]=90,[20300]=90,[20301]=90,[20302]=90,[20303]=90, + [20304]=90,[20305]=90,[20306]=90,[20307]=90,[20308]=90,[20309]=90,[20311]=63,[20312]=63,[20313]=63,[20314]=63, + [20315]=63,[3933]=23,[3934]=24,[3935]=25,[3936]=42,[3937]=46,[3938]=44,[3939]=47,[3940]=48,[3941]=45,[3942]=49, + [3943]=43,[3944]=53,[3945]=55,[3946]=54,[3947]=52,[3948]=58,[3949]=59,[3950]=56,[3951]=57,[3952]=68,[3953]=64, + [3954]=65,[3955]=62,[3956]=63,[3957]=67,[3958]=69,[3959]=66,[20343]=90,[3961]=44,[3962]=48,[3963]=43,[3964]=46, + [3965]=49,[3966]=42,[3967]=47,[3968]=45,[3969]=55,[3970]=54,[3971]=59,[3972]=56,[3973]=58,[3974]=53,[3975]=52, + [3976]=57,[3977]=63,[3978]=69,[3979]=67,[3980]=62,[3981]=68,[3982]=66,[3983]=65,[3984]=64,[3985]=40,[20369]=52, + [3987]=53,[3988]=65,[3989]=42,[3990]=56,[3991]=68,[3992]=52,[3993]=53,[3994]=58,[3995]=57,[3996]=59,[20380]=68, + [3998]=55,[3999]=54,[4000]=44,[4001]=46,[4002]=48,[4003]=49,[4004]=47,[4005]=43,[4006]=42,[4007]=45,[20391]=1, + [20392]=1,[4010]=66,[4011]=68,[4012]=67,[4013]=64,[4014]=69,[4015]=62,[4017]=46,[4018]=42,[4019]=48,[4020]=49, + [4021]=46,[4022]=50,[20406]=60,[20407]=60,[20408]=60,[4026]=43,[20412]=1,[4030]=45,[4031]=45,[4032]=50,[4033]=50, + [20417]=1,[4035]=31,[4036]=27,[4037]=30,[4038]=37,[20422]=1,[4040]=34,[4041]=39,[20425]=23,[20426]=23,[20427]=23, + [20428]=23,[20429]=23,[20430]=23,[20431]=23,[4049]=28,[4050]=31,[20434]=23,[4052]=35,[20437]=23,[20438]=23,[20439]=23, + [20440]=23,[20441]=23,[20442]=23,[20443]=23,[20444]=23,[4062]=45,[4063]=43,[4064]=30,[4065]=36,[4066]=35,[4067]=39, + [20451]=60,[4069]=47,[4070]=41,[4071]=31,[4072]=30,[4073]=31,[4074]=36,[4075]=34,[4076]=35,[4077]=35,[4078]=39, + [4079]=40,[4080]=45,[4081]=45,[4082]=47,[4083]=44,[4084]=46,[20468]=1,[4086]=37,[4087]=41,[4088]=47,[4089]=48, + [4090]=46,[4091]=47,[20476]=62,[20477]=62,[20478]=62,[20479]=62,[20480]=62,[20481]=62,[20487]=75,[20488]=75,[4107]=37, + [4108]=40,[4109]=41,[4110]=45,[4111]=45,[4112]=44,[4113]=45,[4114]=42,[4115]=37,[4116]=41,[4117]=44,[4118]=50, + [4119]=43,[20503]=52,[20504]=52,[20505]=52,[4123]=37,[4124]=40,[4125]=43,[4126]=34,[4127]=40,[4128]=41,[20512]=52, + [4130]=50,[4131]=44,[4132]=37,[4133]=37,[20517]=52,[4135]=35,[4136]=42,[4137]=42,[20521]=52,[4139]=37,[4140]=34, + [20524]=52,[20525]=52,[20529]=52,[20530]=52,[20534]=52,[20536]=52,[20537]=63,[20538]=63,[20539]=63,[20549]=63, + [20550]=63,[20551]=63,[20556]=52,[20561]=1,[20562]=1,[20563]=1,[20564]=1,[20565]=1,[20566]=1,[20567]=1,[20568]=1, + [20569]=1,[20570]=1,[20571]=1,[20572]=1,[20573]=1,[20574]=1,[20575]=20,[4193]=27,[20577]=71,[20578]=71,[20579]=71, + [4197]=36,[20581]=71,[20582]=71,[20583]=45,[20584]=45,[20585]=45,[20586]=45,[20587]=45,[20588]=45,[20589]=45, + [20590]=45,[20591]=45,[20592]=45,[20593]=45,[20594]=45,[20595]=45,[20596]=45,[20597]=45,[20598]=45,[20599]=71, + [20600]=72,[20615]=71,[20616]=71,[20617]=72,[20618]=72,[20619]=72,[4237]=10,[20621]=71,[4239]=13,[20623]=72,[20624]=72, + [20625]=71,[20626]=71,[4244]=20,[20628]=72,[20629]=72,[20630]=72,[20631]=71,[20632]=71,[20633]=72,[20634]=72, + [20635]=71,[20636]=71,[20637]=72,[20638]=72,[20639]=72,[20640]=45,[20641]=45,[20642]=47,[20643]=47,[4261]=8,[20645]=60, + [20646]=59,[4264]=40,[20648]=63,[20649]=60,[20650]=60,[20652]=60,[20653]=60,[20654]=60,[20655]=60,[20656]=60, + [20657]=60,[20658]=60,[20659]=60,[20660]=60,[20661]=60,[20662]=60,[20663]=60,[20664]=65,[20665]=62,[20666]=62, + [20667]=65,[20668]=62,[20669]=62,[20670]=65,[20671]=62,[20672]=62,[4290]=18,[20674]=62,[20675]=62,[20680]=68, + [20681]=68,[20682]=65,[20683]=68,[20684]=68,[20685]=65,[4303]=12,[20687]=68,[20688]=65,[20689]=68,[20690]=68, + [20691]=65,[20692]=60,[20693]=60,[20694]=60,[20695]=63,[20696]=63,[20697]=63,[20698]=63,[20699]=63,[20700]=63, + [20701]=63,[20702]=63,[20703]=63,[20704]=63,[20705]=63,[20706]=63,[20707]=63,[4325]=35,[4326]=37,[20710]=63,[20711]=63, + [4329]=40,[20713]=63,[4331]=25,[20715]=63,[20716]=63,[20717]=63,[20718]=1,[20719]=1,[20720]=65,[20721]=65,[20722]=65, + [20723]=62,[20724]=62,[4343]=10,[20738]=1,[4362]=10,[4368]=20,[4369]=21,[4372]=24,[4373]=24,[4379]=26,[4381]=28, + [4383]=29,[4385]=30,[4393]=37,[4396]=40,[4397]=40,[4430]=43,[20814]=65,[4434]=20,[4436]=21,[4437]=20,[4438]=30, + [4439]=22,[4442]=23,[4443]=36,[4444]=24,[4445]=23,[4446]=26,[4447]=26,[4448]=27,[4449]=27,[4454]=26,[4455]=33, + [4456]=33,[4462]=31,[4463]=31,[4464]=32,[4465]=32,[4474]=32,[4476]=34,[4477]=34,[4478]=45,[4491]=1,[4504]=31, + [4505]=31,[4507]=42,[4508]=42,[4509]=40,[4511]=40,[20905]=1,[4534]=29,[4535]=31,[4543]=40,[4545]=40,[4547]=40, + [4548]=41,[4549]=46,[4550]=46,[4560]=6,[4561]=11,[4562]=10,[4563]=9,[4564]=13,[4565]=6,[4566]=13,[4567]=16,[4568]=21, + [4569]=14,[4570]=15,[4571]=17,[4574]=25,[4575]=19,[4576]=21,[4577]=13,[4614]=35,[4616]=1,[4642]=1,[4643]=33,[4652]=45, + [4653]=45,[21040]=1,[4658]=8,[4659]=8,[4660]=18,[4661]=26,[4662]=8,[4663]=9,[4664]=11,[4665]=8,[4666]=9,[4667]=13, + [4668]=9,[4669]=10,[4670]=13,[4671]=9,[4672]=10,[4673]=12,[4674]=9,[4675]=10,[4676]=17,[4677]=12,[4678]=14,[4679]=15, + [4680]=13,[4681]=14,[4682]=17,[4683]=13,[4684]=13,[4685]=18,[4686]=12,[4687]=14,[4688]=15,[4689]=13,[4690]=13, + [4691]=15,[4692]=12,[4693]=14,[4694]=22,[4695]=18,[4696]=59,[4697]=20,[4698]=21,[4699]=18,[4700]=21,[4701]=16, + [4704]=1,[4705]=27,[4706]=24,[4707]=26,[4708]=24,[4709]=25,[4710]=22,[4711]=28,[4712]=29,[4713]=26,[4714]=27, + [4715]=27,[4716]=32,[4717]=34,[4718]=35,[4719]=32,[4720]=33,[4721]=35,[4722]=32,[4723]=29,[4724]=30,[4725]=40, + [4726]=36,[4727]=38,[4728]=0,[4729]=39,[4730]=7,[4731]=39,[21115]=53,[21116]=43,[21117]=53,[4735]=41,[4736]=42, + [4737]=44,[4738]=42,[21122]=1,[21123]=1,[4741]=37,[21125]=75,[21126]=84,[4744]=39,[21128]=75,[4746]=40,[4750]=1, + [21134]=84,[21135]=63,[4760]=1,[4761]=10,[4762]=1,[4763]=9,[4764]=10,[4765]=14,[4766]=13,[4767]=15,[4768]=15, + [21154]=1,[4772]=11,[4773]=12,[21157]=1,[4777]=18,[4778]=19,[4781]=20,[4782]=18,[4785]=24,[4786]=20,[21170]=1, + [4788]=20,[4789]=18,[4790]=25,[4792]=23,[4793]=24,[4794]=25,[21178]=62,[21179]=62,[21180]=66,[21181]=66,[21182]=66, + [21183]=66,[21184]=62,[21185]=62,[21186]=62,[21187]=62,[21188]=66,[21189]=62,[21190]=66,[21192]=1,[4810]=37,[4811]=20, + [4812]=19,[21196]=60,[21197]=65,[21198]=70,[21199]=75,[21200]=80,[21201]=60,[21202]=65,[21203]=70,[21204]=75, + [21205]=80,[21206]=60,[21207]=65,[21208]=70,[21209]=75,[21210]=80,[4828]=27,[4829]=29,[4830]=28,[4831]=26,[4832]=29, + [4833]=28,[4835]=30,[4836]=28,[4837]=30,[4838]=26,[4840]=10,[4842]=0,[4853]=5,[4854]=11,[4855]=35,[4856]=35,[4857]=35, + [4858]=35,[21242]=79,[21244]=79,[21268]=79,[21269]=79,[21272]=79,[21273]=79,[21275]=79,[21276]=80,[21278]=62, + [4899]=25,[4900]=25,[4901]=25,[4902]=1,[21286]=1,[4906]=7,[4907]=5,[4908]=5,[4909]=15,[4910]=5,[4911]=5,[4912]=25, + [4913]=5,[4914]=5,[4915]=5,[4916]=5,[4917]=5,[4919]=5,[4920]=5,[4921]=5,[4922]=5,[4923]=5,[4924]=5,[4925]=5,[21311]=48, + [21312]=48,[4931]=11,[4932]=11,[21316]=55,[21317]=55,[21318]=58,[21319]=58,[21320]=58,[4938]=11,[21322]=58,[4940]=10, + [4942]=12,[21326]=62,[4944]=12,[21329]=81,[21330]=78,[21331]=88,[21332]=81,[21333]=78,[21334]=88,[21335]=78,[21336]=81, + [21337]=81,[21338]=78,[4956]=5,[4958]=8,[4959]=7,[21343]=88,[21344]=78,[21345]=78,[21346]=81,[4964]=12,[21348]=81, + [21349]=78,[21350]=78,[21351]=88,[21352]=81,[21353]=81,[21354]=78,[21355]=78,[21356]=81,[21357]=88,[4975]=39, + [21359]=78,[21360]=81,[21361]=78,[21362]=81,[4980]=37,[21364]=88,[21365]=78,[21366]=81,[4984]=41,[21368]=81,[21370]=88, + [4988]=50,[21372]=81,[21373]=78,[21374]=88,[21375]=81,[21376]=78,[4994]=1,[4996]=10,[4998]=24,[4999]=27,[5000]=26, + [5001]=27,[5002]=30,[5003]=31,[21387]=81,[5005]=35,[21389]=88,[21390]=81,[21391]=78,[5009]=36,[21393]=65,[21394]=67, + [21395]=70,[21396]=65,[21397]=67,[21398]=70,[21399]=65,[21400]=67,[21401]=70,[21402]=65,[21403]=67,[21404]=70, + [21405]=65,[21406]=67,[21407]=70,[21408]=65,[21409]=67,[21410]=70,[21411]=65,[5029]=47,[21413]=70,[21414]=65, + [21415]=67,[21416]=70,[21417]=65,[21418]=67,[21419]=1,[21420]=1,[21421]=1,[21422]=1,[5040]=32,[21424]=1,[21425]=1, + [21426]=1,[21427]=1,[21428]=1,[21429]=1,[21430]=1,[21431]=1,[21432]=1,[21433]=1,[21434]=1,[21435]=1,[5053]=1, + [21437]=1,[21439]=1,[21440]=1,[21441]=1,[21442]=1,[21443]=1,[21444]=1,[21445]=1,[21446]=1,[21447]=1,[21448]=1, + [21449]=1,[21450]=1,[21451]=1,[21452]=72,[21453]=72,[5071]=14,[21455]=74,[21456]=72,[21457]=72,[21458]=72,[21459]=72, + [21460]=72,[21461]=72,[5079]=40,[21463]=72,[21464]=72,[21465]=1,[21466]=69,[21467]=69,[21468]=74,[21469]=74,[21470]=74, + [21471]=69,[21472]=69,[21473]=74,[21474]=74,[21475]=74,[21476]=74,[21477]=74,[21478]=68,[21479]=68,[21480]=73, + [21481]=73,[21482]=73,[21483]=73,[21484]=73,[21485]=68,[21486]=68,[21487]=68,[21488]=73,[21489]=73,[21490]=73, + [21491]=73,[21492]=66,[21493]=66,[21494]=71,[5112]=15,[21496]=71,[21497]=71,[21498]=66,[21499]=66,[21500]=71, + [21501]=71,[21502]=71,[21503]=71,[21504]=70,[21505]=70,[21506]=70,[21507]=70,[21516]=63,[21517]=75,[21518]=63, + [21520]=76,[21521]=76,[21522]=76,[21523]=76,[21524]=1,[21525]=1,[21526]=77,[21527]=77,[21529]=77,[21530]=77,[21531]=77, + [21532]=77,[21538]=1,[21539]=1,[21541]=1,[21542]=1,[21543]=1,[21544]=1,[21549]=1,[21550]=1,[21551]=1,[21553]=1, + [21554]=1,[21555]=1,[21563]=65,[5181]=33,[21565]=45,[21566]=25,[21567]=45,[21568]=25,[5187]=20,[21572]=1,[21573]=1, + [5191]=24,[5192]=22,[5193]=25,[5194]=23,[5195]=22,[21579]=88,[5197]=21,[21581]=88,[21582]=88,[21583]=88,[5201]=23, + [21585]=88,[21586]=88,[21587]=88,[21588]=88,[5207]=20,[5208]=20,[5209]=21,[5210]=25,[5211]=25,[5212]=17,[21596]=88, + [21597]=81,[21598]=81,[21599]=81,[21600]=81,[21601]=81,[21602]=81,[21603]=78,[21604]=81,[21605]=81,[21606]=81, + [21607]=81,[21608]=81,[21609]=81,[21610]=81,[21611]=81,[21612]=81,[5230]=26,[5231]=38,[21615]=81,[21616]=78,[21617]=78, + [21618]=78,[5236]=34,[21620]=78,[21621]=78,[21622]=78,[21623]=78,[21624]=78,[21625]=78,[21626]=78,[21627]=77, + [5245]=34,[5246]=30,[5247]=39,[5248]=37,[5249]=40,[5250]=28,[21635]=77,[5253]=40,[5254]=20,[5255]=15,[21639]=77, + [5257]=37,[5258]=1,[5259]=1,[5260]=1,[5261]=1,[21645]=77,[21647]=77,[21648]=76,[5266]=53,[5267]=63,[21651]=77, + [21652]=77,[5274]=27,[5275]=15,[5276]=1,[5277]=1,[5278]=1,[5279]=20,[21663]=77,[21664]=77,[21665]=77,[21666]=76, + [21667]=76,[21668]=76,[21669]=76,[21670]=76,[21671]=76,[21672]=76,[21673]=76,[21674]=76,[21675]=76,[21676]=76, + [21677]=78,[21678]=76,[21679]=81,[21680]=78,[21681]=78,[5299]=20,[21683]=76,[21684]=76,[5302]=20,[21686]=76,[21687]=76, + [21688]=75,[21689]=75,[21690]=75,[21691]=75,[21692]=75,[21693]=75,[21694]=75,[21695]=75,[21696]=75,[21697]=75, + [21698]=73,[21699]=73,[21700]=73,[21701]=73,[21702]=73,[21703]=73,[21704]=73,[21705]=73,[21706]=73,[21707]=73, + [21708]=73,[21709]=88,[21710]=88,[5328]=15,[21712]=88,[21715]=72,[5337]=16,[5340]=15,[5341]=15,[5343]=18,[5344]=14, + [5345]=14,[5346]=14,[5347]=35,[5351]=20,[5355]=28,[5356]=27,[5357]=27,[5358]=27,[5378]=1,[5379]=8,[5387]=20,[5392]=5, + [5393]=5,[5394]=5,[5395]=5,[5398]=5,[5399]=5,[5404]=23,[5405]=5,[5408]=1,[5409]=14,[21794]=1,[21795]=1,[21796]=1, + [21797]=100,[21798]=100,[21799]=80,[21800]=68,[21801]=68,[5419]=7,[5420]=14,[21804]=68,[5422]=20,[5423]=20,[5425]=20, + [5426]=20,[21810]=71,[21814]=73,[5443]=20,[5444]=19,[21832]=1,[21836]=71,[21837]=71,[21838]=71,[21839]=84,[5458]=10, + [5459]=13,[21856]=71,[5491]=1,[5495]=1,[5502]=1,[21888]=71,[21889]=75,[21890]=75,[21891]=75,[5516]=16,[5522]=31, + [5532]=1,[5540]=23,[5541]=28,[5542]=19,[5545]=45,[5546]=70,[5548]=70,[5549]=60,[5550]=70,[5551]=60,[5552]=45, + [5553]=60,[5554]=45,[5555]=60,[5556]=45,[5557]=45,[5558]=45,[5559]=43,[5560]=33,[5561]=1,[5579]=5,[5580]=5,[5581]=5, + [5586]=5,[5587]=13,[5589]=10,[5590]=11,[5591]=11,[5592]=11,[5593]=11,[5595]=11,[5596]=11,[5597]=1,[5598]=1,[5599]=1, + [5600]=1,[5604]=13,[5605]=10,[5606]=9,[5607]=8,[5608]=40,[5609]=22,[5610]=15,[5611]=16,[5612]=13,[5613]=23,[5614]=31, + [5615]=20,[5616]=47,[5617]=13,[5618]=11,[22002]=65,[22003]=60,[22004]=65,[5622]=22,[22006]=55,[5624]=38,[22008]=65, + [5626]=20,[5627]=20,[22011]=65,[5629]=20,[5630]=20,[22015]=55,[22016]=65,[22017]=66,[22060]=60,[22061]=60,[22062]=65, + [22063]=65,[22064]=60,[22065]=60,[22066]=55,[22067]=66,[22068]=65,[22069]=60,[22070]=65,[22071]=65,[22072]=66, + [22073]=65,[22074]=60,[22075]=60,[22076]=60,[22077]=55,[22078]=65,[22079]=65,[22080]=60,[22081]=55,[22082]=65, + [22083]=60,[22084]=60,[22085]=66,[22086]=65,[22087]=60,[22088]=65,[22089]=60,[22090]=55,[22091]=60,[22092]=66, + [22093]=65,[22095]=65,[22096]=60,[22097]=60,[22098]=65,[22099]=55,[22100]=66,[22101]=65,[22102]=60,[22106]=65, + [22107]=60,[22108]=65,[22109]=60,[22110]=55,[22111]=66,[22112]=65,[22113]=60,[5739]=38,[5742]=40,[5743]=40,[5744]=12, + [5745]=1,[5746]=1,[5747]=1,[5748]=16,[5749]=23,[5750]=23,[5751]=25,[5752]=26,[5753]=31,[5754]=31,[5755]=35,[5756]=37, + [5757]=20,[5761]=5,[5766]=27,[5767]=9,[5770]=30,[5776]=5,[5777]=5,[5778]=5,[5779]=5,[5780]=18,[5781]=19,[5782]=34, + [5783]=38,[22191]=72,[22194]=70,[5812]=25,[5813]=32,[5814]=30,[5815]=31,[22199]=1,[5817]=30,[5818]=30,[5819]=33, + [5820]=32,[22204]=60,[22205]=57,[22206]=1,[22207]=60,[22208]=58,[22210]=1,[22211]=1,[22212]=56,[22213]=1,[22215]=1, + [22223]=55,[22225]=60,[22230]=52,[22231]=61,[22232]=61,[22234]=53,[5856]=1,[22240]=53,[22241]=57,[22242]=56,[22245]=56, + [22247]=63,[22253]=63,[22254]=57,[22255]=57,[22256]=57,[22257]=57,[22266]=57,[22267]=63,[22268]=63,[22269]=63, + [22270]=55,[22271]=57,[22272]=52,[22273]=52,[22274]=52,[22275]=57,[22276]=1,[22277]=1,[22278]=1,[22279]=1,[22280]=1, + [22281]=1,[22282]=1,[22301]=63,[22302]=63,[22303]=62,[22304]=61,[22305]=61,[22306]=61,[22311]=61,[22313]=61,[22314]=61, + [22315]=61,[22316]=20,[22317]=61,[22318]=61,[5936]=8,[22321]=61,[5939]=8,[5940]=12,[5941]=11,[22325]=61,[5943]=25, + [5944]=15,[22328]=63,[22329]=63,[22330]=61,[22331]=62,[22332]=62,[22333]=62,[22334]=62,[22335]=63,[22336]=63, + [22337]=63,[5956]=1,[5957]=8,[5958]=21,[22342]=63,[22343]=63,[5961]=23,[5962]=32,[5963]=34,[5964]=35,[5965]=37, + [5966]=38,[5967]=18,[5968]=15,[5969]=23,[5970]=23,[5971]=26,[5975]=23,[22377]=65,[22378]=65,[22379]=65,[22380]=65, + [22383]=64,[22384]=63,[22385]=60,[22391]=63,[22394]=62,[22395]=57,[22396]=78,[22397]=57,[22398]=62,[22399]=78, + [22400]=57,[22401]=62,[22402]=78,[22403]=61,[22404]=61,[22405]=61,[22406]=61,[22407]=61,[22408]=63,[22409]=63, + [22410]=63,[22411]=63,[22412]=63,[22416]=92,[22417]=88,[22418]=88,[22419]=86,[22420]=86,[22421]=88,[22422]=88, + [6040]=37,[22424]=88,[22425]=92,[22426]=88,[22427]=88,[22428]=88,[22429]=86,[22430]=86,[22431]=88,[22433]=63, + [22436]=92,[22437]=88,[22438]=88,[22439]=86,[22440]=86,[6058]=5,[6059]=5,[6060]=5,[6061]=8,[6062]=10,[6063]=8, + [6070]=5,[22458]=52,[6076]=5,[6078]=5,[22464]=92,[22465]=88,[22466]=88,[6084]=13,[6085]=13,[22469]=88,[6087]=24, + [22471]=88,[22472]=61,[6092]=18,[6093]=27,[6094]=18,[6095]=24,[22479]=86,[22480]=86,[6098]=1,[22482]=88,[22483]=88, + [22488]=92,[22489]=88,[22490]=88,[22491]=86,[22492]=86,[22493]=88,[22494]=88,[22495]=88,[22496]=92,[22497]=88, + [22498]=88,[22499]=86,[22500]=86,[6118]=1,[6119]=1,[22503]=88,[6121]=1,[6122]=1,[6123]=1,[6124]=1,[22508]=86, + [6126]=1,[6127]=1,[22511]=88,[6129]=1,[22513]=88,[22514]=88,[22515]=86,[22516]=86,[22517]=88,[6135]=1,[22519]=88, + [6137]=1,[6138]=1,[6139]=1,[6140]=1,[6141]=1,[6143]=1,[6144]=1,[6147]=10,[6148]=10,[6171]=5,[6173]=5,[6174]=20, + [6176]=5,[6177]=12,[6179]=19,[6180]=15,[6182]=10,[6185]=5,[6186]=18,[6187]=17,[6188]=15,[6189]=24,[6191]=23,[6194]=32, + [6195]=15,[6196]=34,[6197]=22,[6198]=30,[6199]=24,[6200]=29,[6201]=10,[6202]=11,[6203]=11,[6204]=32,[6205]=15, + [6206]=15,[22596]=1,[6214]=16,[6215]=13,[6219]=10,[6220]=29,[6223]=35,[6224]=1,[6225]=1,[6226]=23,[6227]=1,[6228]=1, + [6229]=1,[6230]=1,[6231]=1,[6232]=1,[6233]=1,[6234]=1,[6235]=1,[6236]=1,[6237]=1,[6238]=10,[6239]=12,[6240]=12, + [6241]=10,[6242]=14,[6243]=18,[6244]=0,[22630]=90,[22631]=90,[22632]=90,[6254]=1,[6255]=19,[6256]=1,[6263]=20, + [6264]=23,[6266]=13,[6267]=12,[6268]=13,[6269]=12,[22654]=80,[22655]=80,[22656]=60,[22657]=60,[22658]=80,[22659]=60, + [22660]=70,[22661]=80,[22662]=80,[22663]=80,[22664]=80,[6282]=32,[22666]=80,[22667]=60,[22668]=60,[22669]=80, + [22670]=80,[22671]=80,[22672]=65,[22673]=65,[6292]=15,[22676]=65,[6294]=15,[6295]=15,[22680]=66,[22681]=66,[22688]=66, + [22689]=66,[22690]=66,[22691]=86,[6309]=15,[6310]=15,[6311]=15,[6314]=27,[6315]=27,[22699]=80,[22700]=80,[6318]=26, + [6319]=26,[6320]=28,[6321]=26,[6322]=1,[6323]=25,[6324]=29,[22709]=1,[6327]=37,[22711]=68,[22712]=68,[22713]=68, + [6331]=36,[6332]=22,[6333]=22,[6334]=1,[6335]=29,[6336]=13,[6337]=12,[22721]=65,[22722]=65,[6340]=26,[6341]=19, + [22725]=70,[22730]=88,[22731]=88,[22732]=88,[6350]=18,[22736]=100,[22738]=1,[22740]=65,[22741]=65,[22742]=1,[6360]=25, + [22744]=1,[22745]=1,[6363]=25,[6364]=25,[6365]=10,[22749]=65,[6367]=30,[22751]=65,[22752]=65,[22753]=65,[22756]=70, + [22757]=70,[22758]=70,[22759]=70,[22760]=70,[6378]=17,[6379]=17,[6380]=18,[6381]=23,[6382]=23,[6383]=24,[6386]=30, + [6387]=29,[6388]=30,[6389]=31,[6392]=29,[6393]=28,[6394]=27,[6395]=29,[6396]=32,[6397]=29,[6398]=29,[6399]=30, + [6400]=31,[6402]=36,[6403]=33,[6404]=35,[6405]=36,[6406]=34,[6407]=33,[6408]=34,[6409]=34,[6410]=33,[6411]=41, + [6412]=39,[6413]=37,[6414]=29,[6415]=41,[6416]=38,[6417]=37,[6418]=37,[22802]=89,[6420]=39,[6421]=38,[6422]=39, + [6423]=45,[6424]=42,[6425]=44,[6426]=43,[6427]=46,[6428]=43,[6429]=44,[6430]=46,[6431]=43,[6432]=41,[6433]=43, + [6434]=1,[22818]=83,[22819]=92,[22820]=83,[22821]=92,[6440]=48,[6447]=20,[6448]=22,[6449]=22,[6459]=23,[6460]=24, + [6461]=27,[6463]=26,[6465]=22,[6466]=18,[6467]=21,[6468]=23,[6469]=24,[6472]=24,[6473]=23,[22857]=66,[22858]=66, + [22859]=66,[6477]=20,[6478]=23,[22862]=66,[6480]=20,[6481]=23,[6482]=24,[22867]=66,[22868]=66,[22869]=66,[22870]=66, + [22872]=68,[22873]=68,[22874]=68,[22875]=68,[22876]=68,[22877]=68,[22878]=68,[22879]=68,[22880]=68,[22881]=68, + [22882]=68,[22883]=68,[22884]=68,[6502]=22,[6503]=22,[6504]=24,[6505]=24,[6506]=11,[6507]=10,[6508]=9,[6509]=10, + [6510]=11,[6511]=11,[6512]=13,[6513]=10,[6514]=10,[6515]=11,[6517]=10,[6518]=11,[6519]=10,[6520]=9,[6521]=11, + [6523]=17,[6524]=22,[6525]=27,[6526]=37,[6527]=13,[6528]=17,[6531]=18,[6536]=19,[6537]=15,[6538]=19,[6539]=16, + [6540]=18,[6541]=16,[6542]=15,[6543]=15,[6545]=18,[6546]=17,[6547]=17,[6548]=16,[6549]=14,[6550]=15,[6551]=17, + [6552]=19,[6553]=18,[6554]=17,[6555]=14,[6556]=15,[6557]=16,[6558]=15,[6559]=16,[6560]=17,[6561]=21,[6562]=21, + [6563]=20,[6564]=21,[6565]=22,[6566]=24,[6567]=25,[6568]=24,[6569]=25,[6570]=22,[6571]=22,[6572]=23,[6573]=23, + [6574]=22,[6575]=20,[6576]=22,[6577]=23,[6578]=23,[6579]=24,[6580]=23,[6581]=21,[6582]=22,[6583]=21,[6584]=25, + [6585]=20,[6586]=23,[6587]=24,[6588]=23,[6589]=26,[6590]=29,[6591]=27,[6592]=29,[6593]=26,[6594]=28,[6595]=28, + [6596]=28,[6597]=28,[6598]=28,[6599]=29,[6600]=27,[6601]=28,[6602]=27,[6603]=30,[6604]=26,[6605]=28,[6606]=25, + [6607]=30,[6608]=27,[6609]=32,[6610]=32,[6611]=29,[6612]=28,[6613]=28,[6614]=28,[6615]=29,[6616]=32,[6617]=30, + [23001]=85,[23004]=83,[6622]=63,[23006]=83,[23009]=83,[6627]=28,[6628]=22,[6629]=23,[6630]=25,[6631]=25,[6632]=20, + [6633]=23,[23017]=83,[23018]=83,[23019]=83,[23020]=83,[23021]=83,[23023]=83,[6641]=26,[6642]=25,[23027]=85,[23028]=83, + [23029]=83,[23030]=83,[23031]=83,[23032]=83,[23033]=83,[6651]=12,[23035]=83,[6653]=1,[6654]=1,[23038]=85,[23039]=83, + [23040]=90,[23041]=90,[6659]=20,[6660]=55,[23044]=83,[23045]=90,[23046]=90,[6664]=26,[6665]=26,[6666]=22,[6667]=27, + [6668]=27,[6669]=25,[6670]=27,[6671]=27,[23056]=89,[23057]=92,[6675]=27,[6676]=27,[6677]=26,[6678]=28,[6679]=29, + [23063]=92,[6681]=32,[6682]=31,[23066]=92,[23067]=92,[6685]=30,[6686]=33,[6687]=34,[6688]=32,[6689]=32,[6690]=34, + [6691]=35,[6692]=36,[6693]=36,[6694]=36,[6695]=32,[6696]=32,[6697]=32,[23081]=63,[23082]=63,[23084]=63,[23085]=63, + [23087]=63,[23088]=63,[23089]=63,[23090]=63,[23091]=63,[6709]=18,[23093]=63,[6711]=1,[6713]=5,[6719]=30,[6720]=37, + [6721]=24,[6722]=30,[6723]=45,[6724]=1,[6725]=36,[6726]=41,[6727]=41,[6728]=1,[6729]=38,[6730]=16,[6731]=20,[6732]=38, + [6733]=28,[6737]=35,[6738]=35,[6739]=29,[6740]=29,[6741]=29,[6742]=36,[6743]=25,[6744]=33,[6745]=33,[6746]=40, + [6747]=40,[6748]=31,[6749]=31,[6750]=31,[6751]=30,[6752]=30,[23139]=62,[6757]=38,[6773]=42,[6774]=42,[6780]=36, + [6784]=36,[23168]=35,[6786]=10,[6787]=22,[6788]=42,[6789]=42,[6790]=32,[6791]=40,[6792]=40,[6793]=40,[6794]=40, + [23178]=41,[6797]=37,[6798]=37,[6801]=40,[6802]=44,[6803]=44,[6804]=40,[6806]=40,[23197]=65,[23198]=65,[23199]=65, + [23200]=65,[23201]=65,[23203]=65,[23206]=90,[23207]=90,[6828]=38,[6829]=44,[6830]=44,[6831]=44,[6832]=42,[6834]=1, + [6835]=23,[23219]=85,[23220]=85,[23221]=83,[23226]=83,[23237]=83,[23238]=83,[23242]=88,[23243]=71,[23244]=71, + [23251]=71,[23252]=71,[23253]=71,[23254]=71,[23255]=71,[23256]=71,[23257]=71,[23258]=71,[23259]=71,[23260]=71, + [23261]=71,[23262]=71,[23263]=71,[23264]=71,[6886]=1,[23272]=68,[23273]=68,[23274]=66,[23275]=66,[23276]=71,[23277]=71, + [23278]=66,[23279]=66,[23280]=66,[23281]=66,[23282]=66,[6900]=38,[6901]=29,[6902]=27,[6903]=28,[6904]=28,[6905]=27, + [6906]=28,[6907]=25,[6908]=25,[6909]=31,[6910]=31,[6911]=31,[23295]=68,[23296]=68,[23297]=68,[23298]=68,[23299]=68, + [23300]=68,[23301]=68,[23302]=68,[23303]=68,[23304]=68,[23305]=68,[23306]=71,[23307]=71,[23308]=71,[23309]=71, + [23310]=71,[23311]=71,[23312]=71,[23313]=71,[23314]=71,[23315]=71,[23316]=71,[23317]=71,[23318]=71,[23319]=71, + [23323]=1,[23324]=1,[23328]=1,[6946]=1,[6953]=31,[6966]=15,[6967]=15,[6968]=15,[6969]=15,[6970]=20,[6971]=31, + [6972]=30,[6973]=29,[6974]=31,[6975]=40,[6976]=40,[6977]=40,[6978]=15,[6979]=15,[6980]=15,[6981]=15,[6982]=15, + [6983]=15,[6984]=15,[6985]=15,[23369]=1,[6998]=25,[7000]=25,[7001]=29,[7002]=29,[7003]=27,[7004]=27,[7005]=4, + [7026]=9,[7027]=28,[7046]=28,[7047]=29,[7048]=29,[7049]=30,[7050]=32,[7051]=34,[7052]=35,[7053]=35,[7054]=38, + [7055]=35,[7056]=36,[7057]=36,[7058]=37,[7059]=38,[7060]=38,[7061]=39,[7062]=39,[7063]=41,[7064]=42,[7065]=33, + [7066]=27,[23451]=78,[23452]=78,[23453]=78,[23454]=78,[23455]=78,[23456]=78,[23464]=78,[23465]=78,[23466]=78, + [23467]=78,[23468]=78,[23469]=78,[7094]=10,[7095]=9,[7106]=33,[7107]=33,[7108]=11,[7109]=9,[7110]=31,[7111]=37, + [7112]=41,[7113]=46,[7115]=15,[7116]=15,[7117]=15,[7118]=15,[7120]=20,[7129]=31,[7130]=31,[7132]=29,[7133]=30, + [7148]=33,[7166]=11,[7167]=11,[7169]=11,[7170]=20,[7171]=1,[23557]=81,[23558]=81,[23570]=81,[7188]=24,[7189]=45, + [23577]=89,[23582]=1,[23583]=1,[7229]=13,[7230]=23,[7248]=12,[7276]=9,[7277]=9,[7280]=11,[7281]=14,[7282]=19, + [7283]=20,[7284]=24,[7285]=24,[7297]=33,[7298]=13,[7299]=30,[7326]=15,[7327]=15,[7328]=15,[7329]=15,[7330]=33, + [7331]=34,[7332]=45,[23716]=1,[7334]=28,[7335]=28,[7336]=24,[7337]=60,[7338]=10,[7339]=40,[7340]=50,[7341]=20, + [7342]=30,[7344]=33,[7348]=25,[7349]=27,[7350]=10,[7351]=11,[7352]=27,[7353]=35,[7354]=33,[7355]=31,[7356]=30, + [7357]=34,[7358]=28,[7359]=29,[23743]=1,[7366]=32,[7367]=33,[7368]=34,[7369]=35,[7370]=31,[7373]=33,[7374]=35, + [7375]=35,[7377]=36,[7378]=37,[7386]=38,[7387]=39,[7390]=40,[7391]=40,[7406]=32,[7407]=35,[7408]=33,[7409]=33, + [7410]=31,[7411]=31,[7412]=32,[7413]=33,[7414]=34,[7415]=29,[7416]=31,[7417]=34,[7418]=35,[7419]=30,[7420]=33, + [7421]=33,[7422]=32,[7423]=34,[7424]=33,[7426]=30,[7427]=31,[7429]=40,[7430]=40,[7431]=39,[7432]=38,[7433]=37, + [7434]=37,[7435]=38,[7436]=35,[7437]=36,[7438]=36,[7439]=40,[7440]=39,[7441]=38,[7443]=37,[7444]=37,[7445]=38, + [7446]=36,[7447]=36,[7448]=36,[7454]=39,[7455]=39,[7456]=38,[7457]=37,[7458]=37,[7459]=38,[7460]=34,[7461]=36, + [7462]=37,[7463]=38,[7465]=39,[7466]=37,[7467]=35,[7468]=45,[7469]=44,[7470]=42,[7471]=42,[7472]=41,[7473]=42, + [7474]=40,[7475]=41,[7476]=40,[7477]=45,[7478]=43,[7479]=42,[7480]=41,[7481]=42,[7482]=42,[7483]=40,[7484]=41, + [7485]=41,[7486]=44,[7487]=43,[7488]=42,[7489]=41,[7490]=42,[7491]=43,[7492]=39,[7493]=40,[7494]=41,[7495]=44, + [7496]=43,[7497]=40,[7506]=25,[7507]=10,[7508]=10,[7509]=15,[7510]=15,[7511]=26,[7512]=26,[7513]=40,[7514]=40, + [7515]=40,[7517]=50,[7518]=50,[7519]=47,[7520]=47,[7521]=46,[7522]=45,[7523]=46,[7524]=44,[7525]=45,[7526]=46, + [7527]=50,[7528]=48,[7529]=47,[7530]=46,[7531]=46,[7532]=47,[7533]=44,[7534]=45,[7535]=46,[7536]=48,[7537]=49, + [7538]=48,[7539]=48,[7540]=47,[7541]=46,[7542]=46,[7543]=47,[7544]=44,[7545]=45,[7546]=46,[7547]=46,[7548]=46, + [7549]=47,[7550]=47,[7551]=47,[7552]=44,[7553]=48,[7554]=19,[7555]=45,[7556]=40,[7557]=50,[7558]=25,[7559]=17, + [7606]=22,[7607]=22,[7608]=21,[7609]=35,[7610]=41,[7611]=46,[7612]=1,[7673]=47,[7677]=29,[7682]=34,[7683]=34, + [7684]=35,[7685]=38,[7686]=35,[7687]=35,[7688]=35,[7689]=35,[7690]=35,[7691]=35,[7706]=1,[7707]=40,[7708]=35, + [7709]=35,[7710]=36,[7711]=38,[7712]=38,[7713]=39,[7714]=39,[7717]=42,[7718]=42,[7719]=42,[7720]=44,[7721]=44, + [7722]=44,[7723]=44,[7724]=44,[7726]=44,[7727]=32,[7728]=34,[7729]=33,[7730]=34,[7731]=35,[7734]=51,[7736]=39, + [7738]=18,[7739]=18,[7746]=41,[7747]=41,[7748]=45,[7749]=41,[7750]=33,[7751]=30,[7752]=33,[7753]=32,[7754]=30, + [7755]=38,[7756]=34,[7757]=37,[7758]=39,[7759]=38,[7760]=39,[7761]=38,[7786]=30,[7787]=31,[7809]=30,[7826]=1, + [24222]=57,[7888]=47,[7913]=32,[7914]=32,[7915]=35,[7916]=36,[7917]=37,[7918]=41,[7919]=41,[7920]=42,[7921]=42, + [7922]=43,[7924]=43,[7925]=44,[7926]=44,[7927]=44,[7928]=45,[7929]=42,[7930]=46,[7931]=46,[7932]=47,[7933]=47, + [7934]=47,[7935]=48,[7936]=49,[7937]=49,[7938]=45,[7939]=49,[7940]=40,[7941]=42,[7942]=44,[7943]=45,[7944]=48, + [7945]=46,[7946]=49,[7947]=51,[7948]=32,[7949]=36,[7950]=42,[7951]=32,[7952]=36,[7953]=42,[7954]=47,[7955]=11, + [7956]=25,[7957]=26,[7958]=27,[7959]=50,[7960]=52,[7961]=49,[7963]=40,[24358]=6,[7996]=20,[7997]=15,[8006]=39, + [24418]=1,[8071]=23,[8080]=58,[8081]=57,[8082]=52,[8083]=53,[8084]=56,[8085]=55,[8086]=54,[8088]=50,[8089]=50, + [8090]=50,[8091]=50,[8092]=50,[8093]=50,[8094]=50,[8106]=51,[8107]=47,[8108]=47,[8109]=46,[8110]=47,[8111]=48, + [8112]=49,[8113]=51,[8114]=47,[8115]=48,[8116]=47,[8117]=47,[8118]=46,[8119]=51,[8120]=45,[8121]=47,[8122]=48, + [8123]=49,[8124]=48,[8125]=48,[8126]=51,[8127]=47,[8128]=49,[8129]=49,[8130]=49,[8131]=50,[8132]=51,[8133]=50, + [8134]=51,[8135]=46,[8137]=43,[8138]=47,[8139]=44,[8140]=43,[8141]=44,[8142]=44,[8143]=46,[8144]=45,[8156]=40, + [8157]=42,[8158]=40,[8159]=40,[8160]=40,[8161]=40,[8162]=41,[8163]=41,[8174]=40,[8175]=41,[8176]=41,[8177]=7, + [8178]=10,[8179]=6,[8180]=11,[8181]=9,[8182]=7,[8183]=27,[8184]=29,[8185]=47,[8186]=26,[8187]=41,[8188]=37,[8189]=42, + [8190]=55,[8191]=46,[8192]=42,[8193]=46,[8194]=43,[8195]=46,[8196]=43,[8197]=47,[8198]=42,[8199]=47,[8200]=43, + [8201]=44,[8202]=47,[8203]=44,[8204]=45,[8205]=44,[8206]=49,[8207]=48,[8208]=50,[8209]=47,[8210]=44,[8211]=45, + [8212]=50,[8213]=49,[8214]=45,[8215]=50,[8216]=48,[8223]=37,[8224]=36,[8225]=36,[8226]=31,[8245]=56,[8246]=52, + [8247]=51,[8248]=50,[8249]=52,[8250]=52,[8251]=54,[8252]=56,[8253]=51,[8254]=53,[8255]=50,[8256]=52,[8257]=50, + [8258]=56,[8259]=50,[8260]=52,[8261]=54,[8262]=54,[8263]=53,[8264]=52,[8265]=56,[8266]=51,[8267]=54,[8268]=54, + [8269]=55,[8270]=55,[8271]=56,[8272]=54,[8273]=46,[8274]=51,[8275]=56,[8276]=47,[8277]=46,[8278]=47,[8279]=48, + [8280]=49,[8281]=48,[8282]=51,[8283]=61,[8284]=57,[8285]=56,[8286]=55,[8287]=57,[8288]=59,[8289]=60,[8290]=61, + [8291]=56,[8292]=58,[8293]=56,[8294]=57,[8295]=56,[8296]=61,[8297]=55,[8298]=57,[8299]=59,[8300]=60,[8301]=59, + [8302]=58,[8303]=62,[8304]=57,[8305]=59,[8306]=59,[8307]=60,[8308]=60,[8309]=61,[8310]=60,[8311]=53,[8312]=57, + [8313]=62,[8314]=53,[8315]=52,[8316]=53,[8317]=54,[8318]=56,[8319]=55,[8320]=57,[8345]=45,[8346]=46,[8347]=45, + [8348]=50,[8349]=50,[8350]=15,[8367]=51,[8624]=10,[8625]=10,[8626]=10,[8663]=40,[8688]=40,[8703]=45,[8708]=50, + [8746]=33,[8747]=35,[8748]=30,[8749]=43,[8750]=42,[8751]=44,[8752]=54,[8753]=57,[8754]=56,[8755]=55,[9042]=1, + [9239]=1,[9243]=45,[9285]=41,[9286]=44,[9287]=41,[9288]=41,[9289]=41,[9290]=42,[9291]=43,[9292]=42,[9333]=1,[9359]=45, + [9362]=31,[9366]=41,[9372]=55,[9375]=38,[9376]=60,[9377]=60,[9378]=38,[9379]=49,[9380]=50,[9381]=38,[9382]=38, + [9383]=40,[9384]=36,[9385]=36,[9386]=36,[9387]=41,[9388]=40,[9389]=41,[9390]=40,[9391]=37,[9392]=40,[9393]=38, + [9394]=42,[9395]=34,[9396]=39,[9397]=39,[9398]=40,[9400]=41,[9401]=43,[9402]=60,[9403]=40,[9404]=42,[9405]=33, + [9406]=35,[9407]=40,[9408]=42,[9409]=42,[9410]=45,[9411]=45,[9412]=47,[9413]=49,[9414]=46,[9415]=47,[9416]=47, + [9417]=47,[9418]=49,[9419]=46,[9420]=37,[9422]=43,[9423]=45,[9424]=41,[9425]=44,[9426]=41,[9427]=42,[9428]=35, + [9429]=44,[9430]=45,[9431]=43,[9432]=42,[9433]=46,[9434]=41,[9435]=36,[9444]=26,[9445]=34,[9446]=34,[9447]=34, + [9448]=33,[9449]=34,[9450]=33,[9452]=32,[9453]=32,[9454]=32,[9455]=33,[9456]=35,[9457]=35,[9458]=37,[9459]=37, + [9461]=37,[9465]=45,[9467]=47,[9469]=48,[9470]=49,[9473]=49,[9474]=49,[9475]=49,[9476]=50,[9477]=50,[9478]=50, + [9479]=50,[9480]=48,[9481]=49,[9482]=47,[9483]=49,[9484]=50,[9485]=30,[9486]=28,[9487]=29,[9488]=28,[9489]=31, + [9490]=29,[9491]=32,[9492]=37,[9508]=31,[9509]=30,[9510]=32,[9511]=46,[9512]=46,[9513]=10,[9514]=10,[9515]=26, + [9516]=26,[9517]=40,[9518]=36,[9519]=36,[9520]=41,[9521]=41,[9522]=36,[9527]=46,[9531]=46,[9533]=47,[9534]=47, + [9535]=30,[9536]=30,[9538]=35,[9588]=35,[9598]=10,[9599]=10,[9600]=12,[9601]=12,[9602]=10,[9603]=10,[9604]=30, + [9605]=30,[9607]=25,[9608]=31,[9609]=31,[9622]=35,[9623]=37,[9624]=37,[9625]=37,[9626]=42,[9627]=42,[9630]=45, + [9631]=45,[9632]=45,[9633]=45,[9634]=46,[9635]=45,[9636]=45,[9637]=45,[9638]=50,[9639]=48,[9640]=48,[9641]=48, + [9642]=50,[9643]=51,[9644]=51,[9645]=49,[9646]=49,[9647]=48,[9648]=48,[9649]=55,[9650]=55,[9651]=53,[9652]=53, + [9653]=50,[9654]=50,[9655]=50,[9656]=49,[9657]=49,[9658]=43,[9659]=1,[9660]=43,[9661]=43,[9662]=43,[9663]=45, + [9664]=45,[9665]=50,[9666]=50,[9678]=43,[9679]=43,[9680]=43,[9682]=44,[9683]=50,[9684]=51,[9685]=51,[9686]=51, + [9687]=33,[9698]=33,[9699]=33,[9700]=1,[9701]=1,[9702]=1,[9703]=43,[9704]=43,[9705]=43,[9706]=43,[9718]=38,[9742]=12, + [9743]=12,[9744]=12,[9745]=11,[9746]=13,[9747]=14,[9748]=15,[9749]=15,[9750]=12,[9751]=12,[9752]=12,[9753]=12, + [9754]=11,[9755]=13,[9756]=14,[9757]=15,[9758]=12,[9759]=13,[9760]=12,[9761]=11,[9762]=13,[9763]=14,[9764]=13, + [9765]=15,[9766]=22,[9767]=23,[9768]=21,[9769]=27,[9770]=20,[9771]=25,[9772]=27,[9773]=27,[9774]=27,[9775]=19, + [9776]=20,[9777]=19,[9778]=20,[9779]=18,[9780]=20,[9781]=22,[9782]=23,[9783]=20,[9784]=19,[9785]=17,[9786]=16, + [9787]=19,[9788]=18,[9789]=19,[9790]=19,[9791]=29,[9792]=25,[9793]=25,[9794]=25,[9795]=26,[9796]=27,[9797]=28, + [9798]=29,[9799]=26,[9800]=29,[9801]=25,[9802]=26,[9803]=26,[9804]=26,[9805]=24,[9806]=27,[9807]=27,[9808]=28, + [9809]=28,[9810]=25,[9811]=24,[9812]=22,[9813]=25,[9814]=24,[9815]=25,[9816]=25,[9817]=26,[9818]=25,[9819]=34, + [9820]=31,[9821]=30,[9822]=29,[9823]=31,[9824]=32,[9825]=33,[9826]=34,[9827]=30,[9828]=31,[9829]=29,[9830]=32, + [9831]=29,[9832]=31,[9833]=33,[9834]=32,[9835]=33,[9836]=33,[9837]=30,[9838]=29,[9839]=31,[9840]=31,[9841]=32, + [9842]=32,[9843]=33,[9844]=38,[9845]=35,[9846]=35,[9847]=33,[9848]=36,[9849]=36,[9850]=36,[9851]=37,[9852]=38, + [9853]=34,[9854]=38,[9855]=35,[9856]=36,[9857]=34,[9858]=36,[9859]=36,[9860]=34,[9861]=35,[9862]=37,[9863]=37, + [9864]=36,[9865]=34,[9866]=38,[9867]=33,[9868]=35,[9869]=35,[9870]=36,[9871]=37,[9872]=37,[9873]=37,[9874]=43, + [9875]=39,[9876]=40,[9877]=38,[9878]=41,[9879]=39,[9880]=40,[9881]=41,[9882]=43,[9883]=42,[9884]=43,[9885]=40, + [9886]=39,[9887]=43,[9888]=36,[9889]=40,[9890]=38,[9891]=39,[9892]=40,[9893]=42,[9894]=41,[9895]=40,[9896]=39, + [9897]=42,[9898]=38,[9899]=42,[9900]=40,[9901]=40,[9902]=41,[9903]=42,[9904]=41,[9905]=48,[9906]=44,[9907]=44, + [9908]=43,[9909]=43,[9910]=44,[9911]=46,[9912]=45,[9913]=48,[9914]=48,[9915]=45,[9916]=44,[9917]=44,[9918]=45, + [9919]=43,[9920]=44,[9921]=45,[9922]=46,[9923]=45,[9924]=48,[9925]=44,[9926]=43,[9927]=42,[9928]=45,[9929]=41, + [9930]=43,[9931]=43,[9932]=44,[9933]=45,[9934]=44,[9935]=45,[9936]=49,[9937]=48,[9938]=48,[9939]=49,[9940]=50, + [9941]=49,[9942]=50,[9943]=53,[9944]=53,[9945]=48,[9946]=53,[9947]=48,[9948]=49,[9949]=48,[9950]=53,[9951]=47, + [9952]=49,[9953]=50,[9954]=51,[9955]=50,[9956]=46,[9957]=50,[9958]=50,[9959]=45,[9960]=47,[9961]=47,[9962]=48, + [9963]=48,[9964]=49,[9965]=49,[9966]=45,[9967]=43,[9968]=42,[9969]=43,[9970]=44,[9971]=43,[9972]=42,[9973]=42, + [9974]=52,[9978]=1,[9998]=41,[9999]=41,[10001]=42,[10002]=42,[10003]=43,[10004]=43,[10006]=43,[10007]=43,[10008]=43, + [10009]=43,[10010]=44,[10011]=44,[10018]=45,[10019]=45,[10020]=45,[10021]=45,[10023]=45,[10024]=46,[10025]=49, + [10026]=46,[10027]=46,[10028]=47,[10029]=47,[10030]=48,[10031]=48,[10032]=48,[10033]=48,[10035]=35,[10036]=35, + [10037]=49,[10038]=49,[10039]=50,[10040]=35,[10041]=50,[10042]=45,[10043]=31,[10044]=49,[10045]=7,[10046]=9,[10047]=15, + [10048]=24,[10049]=25,[10053]=47,[10057]=55,[10058]=50,[10059]=50,[10060]=49,[10061]=51,[10062]=51,[10063]=51, + [10064]=53,[10065]=55,[10066]=49,[10067]=49,[10068]=51,[10069]=49,[10070]=55,[10071]=49,[10072]=51,[10073]=52, + [10074]=53,[10075]=51,[10076]=49,[10077]=53,[10078]=53,[10079]=48,[10080]=50,[10081]=50,[10082]=51,[10083]=51, + [10084]=52,[10085]=52,[10086]=49,[10087]=46,[10088]=45,[10089]=45,[10090]=46,[10091]=47,[10092]=47,[10093]=54, + [10094]=45,[10095]=56,[10096]=54,[10097]=57,[10098]=53,[10099]=55,[10100]=57,[10101]=58,[10102]=59,[10103]=54, + [10104]=59,[10105]=60,[10106]=56,[10107]=54,[10108]=53,[10109]=54,[10110]=55,[10111]=57,[10112]=58,[10113]=57, + [10118]=58,[10119]=57,[10120]=53,[10121]=56,[10122]=55,[10123]=57,[10124]=57,[10125]=56,[10126]=54,[10127]=49, + [10128]=54,[10129]=50,[10130]=50,[10131]=50,[10132]=51,[10133]=52,[10134]=51,[10135]=64,[10136]=60,[10137]=61, + [10138]=59,[10139]=62,[10140]=61,[10141]=63,[10142]=62,[10143]=64,[10144]=60,[10145]=59,[10146]=61,[10147]=60, + [10148]=58,[10149]=61,[10150]=62,[10151]=64,[10152]=63,[10153]=62,[10154]=61,[10155]=61,[10156]=60,[10157]=64, + [10158]=64,[10159]=59,[10160]=62,[10161]=61,[10162]=63,[10163]=62,[10164]=58,[10165]=55,[10166]=54,[10167]=55, + [10168]=56,[10169]=57,[10170]=56,[10171]=54,[10172]=55,[10173]=53,[10174]=52,[10175]=55,[10176]=54,[10177]=56, + [10178]=58,[10179]=54,[10180]=52,[10181]=58,[10182]=58,[10183]=54,[10184]=52,[10185]=51,[10186]=53,[10187]=55, + [10188]=56,[10189]=55,[10190]=52,[10191]=51,[10192]=53,[10193]=55,[10194]=50,[10195]=55,[10196]=52,[10197]=52, + [10198]=53,[10199]=54,[10200]=53,[10201]=48,[10202]=48,[10203]=52,[10204]=55,[10205]=49,[10206]=48,[10207]=49, + [10208]=50,[10209]=50,[10210]=60,[10211]=59,[10212]=57,[10213]=58,[10214]=59,[10215]=62,[10216]=58,[10217]=61, + [10218]=62,[10219]=60,[10220]=63,[10221]=58,[10222]=59,[10223]=58,[10224]=57,[10225]=59,[10226]=61,[10227]=62, + [10228]=60,[10229]=56,[10230]=60,[10231]=55,[10232]=58,[10233]=57,[10234]=58,[10235]=59,[10236]=59,[10237]=58, + [10238]=52,[10239]=51,[10240]=55,[10241]=53,[10242]=52,[10243]=51,[10244]=54,[10245]=53,[10246]=65,[10247]=63, + [10248]=62,[10249]=61,[10250]=63,[10251]=63,[10252]=64,[10253]=63,[10254]=65,[10255]=62,[10256]=61,[10257]=62, + [10258]=60,[10259]=62,[10260]=63,[10261]=63,[10262]=64,[10263]=63,[10264]=65,[10265]=62,[10266]=65,[10267]=61, + [10268]=63,[10269]=62,[10270]=63,[10271]=65,[10272]=63,[10273]=64,[10274]=63,[10275]=60,[10276]=56,[10277]=57, + [10278]=55,[10279]=58,[10280]=59,[10281]=58,[10282]=56,[10287]=26,[10288]=31,[10289]=32,[10298]=30,[10299]=31, + [10328]=39,[10329]=37,[10330]=43,[10331]=38,[10332]=35,[10333]=36,[10358]=36,[10359]=36,[10362]=58,[10363]=60, + [10364]=58,[10365]=59,[10366]=63,[10367]=65,[10368]=62,[10369]=58,[10370]=57,[10371]=58,[10372]=59,[10373]=61, + [10374]=59,[10375]=57,[10376]=60,[10377]=59,[10378]=63,[10379]=61,[10380]=60,[10381]=59,[10382]=62,[10383]=61, + [10384]=65,[10385]=62,[10386]=62,[10387]=61,[10388]=63,[10389]=64,[10390]=63,[10391]=60,[10399]=24,[10400]=18, + [10401]=18,[10402]=18,[10403]=22,[10404]=30,[10405]=22,[10406]=32,[10407]=21,[10408]=32,[10409]=32,[10410]=23, + [10411]=23,[10412]=21,[10413]=19,[10418]=50,[10421]=7,[10422]=31,[10423]=31,[10455]=60,[10461]=45,[10462]=47, + [10499]=35,[10500]=41,[10501]=44,[10502]=43,[10503]=46,[10504]=49,[10506]=46,[10508]=41,[10510]=44,[10515]=1, + [10518]=45,[10542]=41,[10543]=41,[10544]=5,[10545]=42,[10547]=8,[10549]=12,[10550]=12,[10553]=11,[10554]=11,[10555]=1, + [10567]=38,[10568]=1,[10570]=39,[10571]=37,[10572]=39,[10573]=37,[10574]=40,[10576]=50,[10577]=41,[10578]=38, + [10581]=40,[10582]=36,[10583]=39,[10584]=36,[10585]=44,[10587]=46,[10588]=47,[10591]=1,[10596]=46,[10611]=1,[10612]=1, + [10613]=1,[10614]=1,[10615]=1,[10616]=1,[10617]=1,[10618]=1,[10619]=1,[10623]=48,[10624]=47,[10625]=49,[10626]=50, + [10627]=47,[10628]=48,[10629]=50,[10630]=51,[10631]=46,[10632]=49,[10633]=51,[10634]=46,[10635]=5,[10636]=5,[10637]=15, + [10638]=15,[10645]=48,[10652]=51,[10653]=30,[10654]=31,[10655]=5,[10656]=5,[10657]=26,[10658]=25,[10659]=57,[10685]=1, + [10686]=55,[10696]=60,[10697]=60,[10698]=60,[10700]=45,[10701]=45,[10702]=43,[10703]=45,[10704]=46,[10705]=47, + [10706]=47,[10707]=52,[10708]=52,[10709]=55,[10710]=38,[10711]=44,[10716]=41,[10720]=42,[10721]=43,[10723]=44, + [10724]=45,[10725]=46,[10726]=47,[10727]=48,[10739]=53,[10740]=53,[10741]=53,[10742]=51,[10743]=51,[10744]=51, + [10745]=50,[10746]=50,[10747]=41,[10748]=41,[10749]=54,[10750]=54,[10751]=54,[10756]=1,[10758]=42,[10760]=39, + [10761]=44,[10762]=44,[10763]=44,[10764]=44,[10765]=43,[10766]=40,[10767]=42,[10768]=42,[10769]=41,[10770]=41, + [10771]=41,[10772]=41,[10774]=42,[10775]=42,[10776]=42,[10777]=42,[10778]=60,[10779]=60,[10780]=55,[10781]=55, + [10782]=55,[10783]=52,[10784]=52,[10785]=52,[10786]=52,[10787]=52,[10788]=52,[10795]=54,[10796]=54,[10797]=53, + [10798]=51,[10799]=51,[10800]=52,[10801]=52,[10802]=52,[10803]=54,[10804]=54,[10805]=54,[10806]=55,[10807]=55, + [10808]=55,[10820]=15,[10821]=15,[10823]=45,[10824]=45,[10825]=1,[10826]=48,[10827]=48,[10828]=56,[10829]=56, + [10833]=56,[10835]=56,[10836]=56,[10837]=56,[10838]=54,[10842]=54,[10843]=54,[10844]=54,[10845]=54,[10846]=54, + [10847]=57,[10878]=1,[10898]=1,[10919]=18,[11019]=1,[11021]=1,[11025]=1,[11041]=1,[11042]=1,[11086]=50,[11087]=1, + [11118]=47,[11120]=55,[11121]=26,[11122]=50,[11123]=55,[11124]=55,[11170]=1,[11182]=0,[11183]=0,[11187]=5,[11189]=5, + [11190]=5,[11191]=10,[11192]=5,[11193]=57,[11194]=57,[11195]=57,[11196]=57,[11199]=1,[11200]=1,[11201]=1,[11229]=32, + [11262]=44,[11263]=40,[11264]=1,[11265]=42,[11287]=10,[11288]=18,[11289]=31,[11290]=35,[11302]=52,[11303]=16, + [11304]=19,[11305]=35,[11306]=32,[11307]=47,[11308]=49,[11310]=47,[11311]=46,[11314]=1,[11317]=1,[11321]=1,[11322]=1, + [11323]=1,[11342]=1,[11343]=1,[11344]=43,[11345]=34,[11365]=1,[11369]=1,[11383]=1,[11411]=28,[11424]=1,[11469]=46, + [11475]=5,[11502]=46,[11505]=1,[11506]=1,[11508]=1,[11522]=0,[11542]=1,[11585]=1,[11586]=1,[11587]=1,[11588]=1, + [11589]=1,[11591]=1,[11603]=51,[11604]=59,[11605]=58,[11606]=56,[11607]=57,[11608]=55,[11623]=52,[11624]=52,[11625]=53, + [11626]=53,[11627]=53,[11628]=53,[11629]=53,[11631]=52,[11632]=52,[11633]=54,[11634]=54,[11635]=54,[11662]=54, + [11665]=54,[11669]=59,[11675]=55,[11677]=55,[11678]=55,[11679]=55,[11684]=60,[11685]=55,[11686]=55,[11702]=55, + [11703]=55,[11722]=55,[11726]=57,[11728]=57,[11729]=57,[11730]=57,[11731]=57,[11735]=57,[11743]=55,[11744]=56, + [11745]=56,[11746]=56,[11747]=53,[11748]=53,[11749]=53,[11750]=53,[11755]=56,[11762]=1,[11763]=1,[11764]=57,[11765]=57, + [11766]=57,[11767]=57,[11768]=57,[11782]=57,[11783]=57,[11784]=53,[11785]=58,[11786]=56,[11787]=58,[11802]=58, + [11803]=56,[11805]=56,[11807]=58,[11808]=59,[11809]=56,[11810]=60,[11811]=55,[11812]=58,[11814]=58,[11815]=58, + [11816]=56,[11817]=56,[11819]=59,[11820]=58,[11821]=58,[11822]=59,[11823]=59,[11824]=54,[11832]=58,[11838]=1, + [11839]=55,[11841]=55,[11842]=55,[11847]=5,[11848]=5,[11849]=5,[11850]=5,[11851]=5,[11852]=5,[11853]=18,[11854]=19, + [11855]=19,[11856]=45,[11857]=46,[11858]=45,[11859]=45,[11860]=46,[11861]=46,[11862]=52,[11863]=52,[11864]=52, + [11865]=53,[11866]=55,[11867]=53,[11868]=53,[11869]=53,[11870]=54,[11871]=54,[11872]=54,[11873]=56,[11874]=56, + [11875]=54,[11876]=56,[11882]=56,[11884]=33,[11888]=50,[11889]=50,[11902]=56,[11904]=56,[11905]=56,[11906]=55, + [11907]=55,[11908]=55,[11909]=55,[11910]=55,[11911]=55,[11913]=55,[11915]=55,[11916]=55,[11917]=55,[11918]=55, + [11919]=55,[11920]=56,[11921]=57,[11922]=57,[11923]=57,[11924]=60,[11925]=57,[11926]=57,[11927]=57,[11928]=60, + [11929]=57,[11930]=60,[11931]=59,[11932]=59,[11933]=60,[11934]=61,[11935]=58,[11936]=20,[11945]=53,[11946]=52, + [11962]=55,[11963]=53,[11964]=55,[11965]=20,[11967]=23,[11968]=26,[11969]=29,[11970]=34,[11971]=37,[11972]=40, + [11973]=43,[11974]=46,[11975]=49,[11976]=52,[11977]=55,[11978]=58,[11979]=61,[11980]=64,[11981]=20,[11982]=23, + [11983]=26,[11984]=29,[11985]=35,[11986]=39,[11987]=43,[11988]=47,[11989]=51,[11990]=55,[11991]=59,[11992]=63, + [11993]=22,[11994]=25,[11995]=28,[11996]=34,[11997]=38,[11998]=42,[11999]=46,[12000]=55,[12001]=50,[12002]=54, + [12004]=58,[12005]=62,[12006]=22,[12007]=25,[12008]=28,[12009]=33,[12010]=37,[12011]=41,[12012]=45,[12013]=49, + [12014]=53,[12015]=57,[12016]=61,[12017]=65,[12018]=54,[12019]=32,[12020]=36,[12021]=54,[12022]=41,[12023]=45, + [12024]=50,[12025]=54,[12026]=59,[12027]=63,[12028]=32,[12029]=35,[12030]=39,[12031]=44,[12032]=48,[12034]=53, + [12035]=57,[12036]=62,[12038]=54,[12039]=33,[12040]=38,[12041]=54,[12042]=42,[12043]=47,[12044]=51,[12045]=56, + [12046]=60,[12047]=30,[12048]=65,[12049]=53,[12050]=54,[12051]=54,[12052]=21,[12053]=21,[12054]=24,[12055]=52, + [12056]=56,[12057]=60,[12058]=64,[12059]=58,[12061]=60,[12062]=60,[12063]=1,[12064]=1,[12065]=60,[12066]=58,[12082]=58, + [12083]=58,[12102]=54,[12103]=63,[12104]=60,[12105]=60,[12106]=60,[12107]=60,[12108]=58,[12109]=58,[12110]=58, + [12111]=58,[12112]=56,[12113]=56,[12114]=56,[12115]=56,[12142]=1,[12182]=1,[12183]=1,[12185]=60,[12187]=60,[12188]=60, + [12189]=60,[12221]=10,[12222]=14,[12225]=10,[12243]=54,[12244]=60,[12245]=60,[12246]=0,[12247]=32,[12248]=34, + [12249]=31,[12250]=34,[12251]=37,[12252]=39,[12253]=41,[12254]=44,[12255]=46,[12256]=49,[12257]=42,[12258]=44, + [12259]=36,[12260]=39,[12282]=2,[12285]=1,[12290]=1,[12294]=1,[12295]=15,[12296]=17,[12297]=1,[12298]=1,[12299]=8, + [12304]=1,[12322]=1,[12328]=1,[12329]=1,[12331]=1,[12332]=1,[12333]=1,[12338]=1,[12344]=61,[12348]=1,[12385]=0, + [12403]=1,[12405]=50,[12406]=50,[12407]=51,[12408]=51,[12409]=56,[12410]=56,[12413]=60,[12414]=60,[12415]=54, + [12416]=52,[12417]=59,[12418]=57,[12419]=58,[12420]=61,[12421]=1,[12422]=60,[12423]=56,[12424]=53,[12425]=54, + [12426]=59,[12427]=59,[12428]=53,[12429]=61,[12442]=1,[12443]=1,[12446]=5,[12447]=5,[12448]=5,[12449]=5,[12452]=1, + [12453]=1,[12454]=1,[12456]=1,[12461]=1,[12462]=55,[12463]=53,[12464]=53,[12465]=53,[12466]=53,[12468]=53,[12469]=47, + [12470]=47,[12471]=47,[12482]=1,[12502]=1,[12522]=15,[12523]=1,[12527]=53,[12528]=52,[12531]=51,[12532]=56,[12535]=54, + [12542]=51,[12543]=60,[12544]=60,[12545]=60,[12546]=54,[12547]=56,[12548]=60,[12549]=52,[12550]=53,[12551]=56, + [12552]=55,[12553]=59,[12554]=59,[12555]=55,[12556]=59,[12557]=59,[12582]=60,[12583]=63,[12584]=78,[12587]=63, + [12588]=63,[12589]=61,[12590]=63,[12591]=1,[12592]=63,[12593]=1,[12602]=63,[12603]=61,[12604]=60,[12605]=56,[12606]=61, + [12608]=58,[12609]=61,[12610]=60,[12611]=60,[12612]=61,[12613]=62,[12614]=62,[12615]=62,[12616]=63,[12617]=63, + [12618]=63,[12619]=63,[12620]=62,[12621]=59,[12624]=54,[12625]=58,[12626]=59,[12628]=57,[12629]=1,[12631]=58, + [12632]=59,[12633]=60,[12634]=60,[12636]=61,[12637]=60,[12639]=62,[12640]=61,[12641]=63,[12651]=59,[12653]=59, + [12686]=62,[21172]=1,[21169]=1,[20523]=52,[20386]=0,[20133]=63,[12709]=63,[19985]=63,[19359]=73,[19294]=30,[19285]=1, + [18439]=65,[1395]=1,[1664]=41,[18872]=63,[18857]=0,[18855]=78,[18202]=66,[2108]=4,[2013]=26,[1996]=37,[1993]=36, + [1991]=34,[1988]=38,[1965]=10,[1944]=18,[1943]=19,[1936]=18,[1934]=20,[1929]=18,[1928]=16,[1927]=15,[17774]=48, + [17767]=51,[2200]=1,[132]=1,[22961]=83,[16529]=60,[18800]=67,[12742]=1,[12743]=1,[12744]=1,[12745]=1,[12746]=1, + [12747]=1,[12748]=1,[12749]=1,[12750]=1,[12751]=1,[12752]=62,[20239]=90,[12754]=1,[12755]=1,[12756]=62,[12757]=62, + [5034]=45,[6128]=1,[5290]=1,[5070]=1,[5039]=45,[5037]=45,[12764]=52,[5036]=19,[5035]=45,[12767]=53,[5033]=45, + [12769]=54,[5032]=45,[5031]=19,[12772]=54,[12773]=55,[12774]=55,[12775]=56,[12776]=56,[12777]=56,[3896]=50,[12779]=57, + [3579]=7,[12781]=57,[12782]=58,[12783]=63,[12784]=63,[3479]=23,[12786]=1,[12787]=1,[12788]=1,[3359]=1,[12790]=63, + [12791]=55,[12792]=58,[12793]=55,[12794]=63,[12795]=60,[12796]=63,[12797]=63,[12798]=63,[3106]=25,[3105]=20,[12801]=1, + [12802]=60,[3104]=15,[2952]=17,[12805]=46,[2301]=4,[192]=75,[24071]=69,[23714]=20,[23072]=90,[23058]=92,[23034]=83, + [22817]=77,[22814]=81,[22805]=77,[22346]=1,[21782]=63,[21614]=81,[21613]=81,[21594]=88,[21584]=88,[21423]=1,[21339]=78, + [21127]=75,[21124]=75,[21102]=63,[21101]=63,[20522]=52,[20502]=52,[20446]=60,[20445]=60,[20372]=77,[20370]=90, + [20368]=60,[20363]=63,[20362]=63,[20361]=63,[20360]=63,[20359]=63,[20358]=63,[20357]=63,[20356]=63,[20355]=63, + [20354]=63,[20353]=63,[12846]=1,[20352]=63,[20351]=63,[20350]=90,[12850]=1,[12851]=1,[12852]=1,[12853]=1,[12854]=1, + [12855]=1,[12856]=1,[12857]=1,[12858]=1,[12859]=1,[12860]=1,[12861]=1,[12862]=1,[12863]=1,[12864]=1,[12865]=1, + [12866]=1,[12867]=1,[12868]=1,[12869]=1,[12870]=1,[20349]=90,[20348]=90,[20347]=90,[20346]=90,[20345]=90,[20344]=90, + [20342]=90,[20341]=90,[20340]=90,[20339]=90,[20338]=90,[12882]=1,[12883]=1,[20337]=0,[20336]=90,[20335]=90,[20334]=90, + [20333]=90,[12889]=1,[12890]=1,[20332]=90,[12892]=1,[12893]=1,[20331]=90,[12895]=62,[20330]=90,[20329]=90,[20328]=90, + [20327]=90,[20326]=90,[12901]=1,[12902]=1,[12903]=62,[12904]=61,[12905]=61,[20325]=90,[20324]=90,[20323]=63,[20322]=63, + [20321]=63,[20320]=63,[20319]=63,[20318]=63,[20317]=63,[20316]=63,[20285]=63,[20278]=90,[20277]=90,[20276]=90, + [20275]=90,[20274]=90,[20273]=90,[20272]=90,[20271]=90,[20270]=90,[12926]=61,[12927]=61,[20269]=90,[12929]=61, + [12930]=60,[12931]=1,[12932]=1,[12933]=1,[12934]=1,[12935]=63,[12936]=63,[12937]=1,[20268]=90,[12939]=63,[12940]=63, + [12941]=1,[20267]=90,[12943]=1,[12944]=1,[12945]=62,[20248]=90,[12947]=60,[12948]=1,[12949]=1,[12950]=1,[12951]=1, + [12952]=60,[12953]=63,[20238]=90,[20185]=53,[20183]=43,[20182]=33,[20180]=43,[12959]=1,[12960]=60,[12961]=1,[12962]=1, + [12963]=63,[12964]=63,[12965]=63,[12966]=63,[12967]=63,[12968]=63,[12969]=63,[12970]=63,[12971]=50,[12972]=50, + [20179]=53,[12974]=31,[12975]=20,[12976]=20,[12977]=20,[12978]=20,[12979]=21,[12980]=1,[12981]=1,[12982]=21,[12983]=21, + [12984]=21,[12985]=22,[12986]=1,[12987]=22,[12988]=22,[12989]=22,[12990]=23,[12991]=1,[12992]=23,[12993]=1,[12994]=23, + [12995]=1,[12996]=23,[12997]=24,[12998]=25,[12999]=25,[13000]=62,[13001]=61,[13002]=59,[13003]=56,[13004]=58, + [13005]=28,[13006]=62,[13007]=58,[13008]=52,[13009]=51,[13010]=26,[13011]=27,[13012]=27,[13013]=56,[13014]=53, + [13015]=61,[13016]=26,[13017]=40,[13018]=48,[13019]=32,[13020]=39,[13021]=47,[13022]=55,[13023]=63,[13024]=29, + [13025]=37,[13026]=45,[13027]=53,[13028]=61,[13029]=43,[13030]=51,[13031]=28,[13032]=27,[13033]=34,[13034]=41, + [13035]=49,[13036]=57,[13037]=32,[13038]=40,[13039]=48,[13040]=56,[13041]=26,[13042]=41,[13043]=49,[13044]=57, + [13045]=35,[13046]=50,[13047]=58,[13048]=31,[13049]=29,[13050]=1,[13051]=44,[13052]=52,[13053]=60,[13054]=40, + [13055]=48,[13056]=56,[13057]=28,[13058]=44,[13059]=52,[13060]=60,[13061]=1,[13062]=27,[13063]=34,[13064]=42, + [13065]=50,[13066]=51,[13067]=54,[13068]=42,[13069]=1,[13070]=58,[13071]=45,[13072]=60,[13073]=52,[13074]=46, + [13075]=63,[13076]=48,[13077]=57,[13078]=1,[13079]=30,[13080]=63,[13081]=38,[13082]=46,[13083]=62,[13084]=35, + [13085]=51,[20178]=33,[13087]=33,[13088]=41,[13089]=49,[13090]=63,[13091]=57,[13092]=63,[13093]=37,[13094]=30, + [13095]=44,[13096]=60,[13097]=29,[13098]=63,[13099]=29,[13100]=44,[13101]=59,[13102]=47,[13103]=38,[13104]=1, + [13105]=37,[13106]=31,[13107]=62,[13108]=34,[13109]=49,[13110]=36,[13111]=54,[13112]=48,[13113]=63,[13114]=30, + [13115]=45,[13116]=61,[13117]=42,[13118]=57,[13119]=39,[13120]=55,[13121]=38,[13122]=55,[13123]=62,[13124]=35, + [13125]=50,[13126]=53,[13127]=32,[13128]=47,[13129]=39,[13130]=56,[13131]=29,[13132]=43,[13133]=61,[13134]=49, + [13135]=59,[13136]=21,[13137]=34,[13138]=42,[13139]=50,[20146]=90,[13141]=63,[13142]=63,[13143]=61,[13144]=53, + [13145]=40,[13146]=58,[13147]=1,[13148]=61,[20144]=90,[13150]=1,[20143]=90,[20142]=90,[20141]=90,[20140]=90,[20139]=90, + [20138]=90,[20137]=90,[20136]=90,[20135]=90,[13160]=1,[13161]=61,[13162]=61,[13163]=62,[13164]=61,[13165]=1,[13166]=60, + [13167]=60,[13168]=60,[13169]=60,[13170]=60,[13171]=61,[20123]=33,[13173]=60,[20122]=43,[13175]=60,[20121]=53, + [13177]=60,[13178]=60,[13179]=60,[19989]=52,[13181]=57,[13182]=54,[13183]=60,[13184]=61,[13185]=61,[19986]=52, + [19983]=1,[19966]=68,[19926]=63,[19868]=66,[19844]=65,[19837]=65,[19743]=38,[19662]=80,[19490]=63,[19486]=1,[19457]=80, + [13198]=60,[13199]=41,[19456]=80,[19455]=70,[19428]=63,[13203]=60,[13204]=58,[13205]=61,[13206]=61,[19427]=63, + [13208]=61,[13209]=61,[13210]=60,[13211]=60,[13212]=60,[13213]=60,[13214]=1,[19201]=63,[13216]=61,[13217]=61, + [13218]=61,[13219]=1,[13220]=1,[13221]=1,[13222]=1,[19200]=63,[19199]=63,[19198]=63,[19197]=63,[19196]=63,[19195]=63, + [19194]=63,[19193]=63,[19192]=63,[19191]=63,[19190]=63,[19188]=63,[19187]=63,[19186]=63,[19185]=63,[19184]=63, + [18971]=60,[18968]=60,[18951]=50,[13242]=60,[13243]=62,[13244]=60,[13245]=20,[13246]=62,[18882]=80,[13248]=56, + [13249]=62,[18881]=80,[18801]=75,[13252]=60,[13253]=60,[13254]=56,[13255]=59,[13256]=1,[13257]=59,[13258]=61, + [13259]=61,[13260]=61,[13261]=59,[13262]=76,[18764]=52,[18763]=52,[18747]=63,[18438]=40,[18342]=59,[18341]=59, + [18320]=58,[18316]=58,[18165]=1,[18163]=1,[18161]=1,[18023]=59,[17802]=80,[17769]=47,[17597]=60,[17587]=65,[17585]=65, + [17575]=60,[17565]=60,[13282]=59,[13283]=59,[13284]=59,[13285]=58,[13286]=58,[16576]=65,[16538]=65,[13289]=1, + [13290]=1,[13291]=1,[13292]=1,[13293]=1,[13294]=0,[16520]=60,[16512]=60,[16511]=60,[16482]=65,[16481]=65,[16470]=65, + [16469]=65,[16460]=65,[16439]=65,[16438]=65,[17223]=63,[17193]=67,[17906]=60,[17922]=10,[18510]=62,[3195]=18, + [3196]=18,[13312]=1,[3197]=35,[13314]=62,[13315]=61,[13316]=1,[19345]=76,[13318]=1,[13319]=1,[19325]=65,[19324]=65, + [3302]=15,[3303]=12,[3304]=14,[3305]=16,[3306]=18,[3307]=15,[3308]=15,[3309]=16,[3310]=18,[3312]=13,[19290]=66, + [19289]=66,[19288]=66,[19287]=66,[13336]=1,[13337]=1,[13338]=1,[13339]=1,[13340]=63,[13341]=1,[19169]=70,[19168]=70, + [13344]=63,[13345]=63,[13346]=63,[13347]=1,[13348]=63,[13349]=63,[19165]=70,[19164]=70,[19163]=70,[13353]=63, + [19156]=66,[19148]=66,[19147]=66,[19146]=65,[13358]=63,[13359]=63,[13360]=63,[13361]=63,[18948]=32,[18877]=78, + [18876]=78,[18875]=64,[18874]=78,[18873]=78,[13368]=62,[13369]=63,[18871]=78,[13371]=58,[13372]=60,[13373]=60, + [13374]=60,[13375]=60,[13376]=59,[18862]=0,[13378]=58,[13379]=58,[13380]=61,[13381]=61,[13382]=61,[13383]=58, + [13384]=58,[13385]=61,[13386]=61,[13387]=61,[13388]=61,[13389]=61,[13390]=61,[13391]=61,[13392]=61,[13393]=61, + [13394]=59,[13395]=59,[13396]=57,[13397]=61,[13398]=62,[13399]=59,[13400]=59,[13401]=61,[13402]=59,[13403]=59, + [13404]=57,[13405]=57,[13406]=1,[13407]=1,[13408]=57,[13409]=57,[18856]=0,[18854]=0,[18853]=0,[18852]=0,[18821]=67, + [3429]=24,[3439]=8,[3445]=12,[3446]=13,[19830]=61,[3449]=15,[3450]=15,[3451]=18,[18531]=62,[18528]=61,[18527]=63, + [18526]=63,[18525]=63,[18523]=63,[18522]=63,[3806]=37,[3807]=33,[3808]=34,[3809]=32,[3810]=38,[3811]=37,[3813]=35, + [3814]=39,[3815]=33,[3816]=36,[3817]=33,[3822]=32,[1721]=54,[17579]=65,[4039]=35,[18369]=60,[4025]=45,[2656]=5, + [2654]=2,[3836]=34,[3805]=32,[3652]=14,[2495]=8,[2468]=37,[2446]=27,[2444]=50,[2437]=50,[2312]=15,[2098]=27,[1935]=24, + [1394]=15,[22198]=70,[22319]=61,[22339]=63,[22477]=88,[22940]=83,[22941]=83,[22942]=81,[22943]=83,[22947]=85, + [22954]=85,[22960]=83,[13472]=60,[13473]=54,[13474]=56,[13475]=55,[22967]=83,[22968]=83,[22981]=83,[22983]=83, + [22988]=83,[23000]=85,[23291]=66,[2708]=1,[2710]=1,[25818]=1,[23356]=1,[5287]=1,[21998]=55,[22322]=61,[6898]=25, + [5291]=1,[23287]=66,[3596]=5,[92]=1,[94]=1,[97]=1,[100]=1,[13498]=62,[102]=1,[103]=1,[104]=1,[13502]=63,[13503]=60, + [13504]=1,[13505]=63,[113]=1,[114]=1,[115]=1,[122]=1,[124]=1,[125]=1,[126]=1,[130]=1,[131]=1,[13515]=60,[13516]=60, + [135]=1,[136]=1,[141]=1,[149]=1,[150]=1,[152]=1,[156]=1,[13524]=62,[13525]=62,[13526]=62,[13527]=62,[13528]=62, + [13529]=61,[13530]=61,[13531]=61,[13532]=61,[13533]=61,[13534]=60,[13535]=60,[1125]=45,[13537]=60,[13538]=60, + [13539]=60,[1184]=40,[1186]=40,[1216]=33,[1311]=18,[13544]=60,[1312]=18,[1324]=1,[1350]=40,[1354]=8,[1363]=15, + [1371]=2,[1385]=4,[1392]=23,[1397]=1,[1700]=43,[1719]=1,[1912]=40,[1960]=15,[1969]=15,[1999]=34,[2012]=40,[2016]=26, + [2038]=24,[2045]=30,[2107]=1,[2128]=4,[2487]=4,[2496]=8,[2574]=15,[2655]=3,[2664]=18,[2919]=30,[2920]=10,[2993]=20, + [2994]=23,[2995]=23,[3001]=20,[3002]=30,[3003]=10,[3004]=15,[3005]=20,[3006]=25,[3007]=15,[3015]=40,[3050]=28, + [3051]=25,[13586]=60,[3052]=26,[3054]=24,[3128]=4,[3136]=19,[3159]=15,[3215]=25,[3219]=18,[3221]=15,[3222]=19, + [3226]=12,[3232]=33,[3459]=12,[6896]=20,[7187]=25,[6899]=35,[13602]=43,[13603]=60,[13604]=1,[13605]=1,[13606]=1, + [13607]=1,[13608]=1,[13609]=1,[13610]=1,[13611]=1,[13612]=1,[6837]=1,[6708]=1,[6707]=1,[6698]=1,[6674]=1,[6673]=1, + [6131]=1,[6036]=39,[5954]=60,[13622]=1,[13623]=1,[5953]=60,[13625]=1,[5828]=1,[13627]=1,[13628]=1,[13629]=1,[13630]=1, + [13631]=1,[13632]=1,[5822]=24,[5821]=24,[5625]=23,[5308]=20,[5307]=20,[5298]=18,[5297]=17,[5296]=15,[5295]=13, + [5294]=12,[5283]=1,[5282]=1,[5235]=7,[5226]=37,[5222]=28,[5108]=32,[5106]=15,[5010]=40,[5008]=36,[5004]=35,[4990]=50, + [4989]=50,[4985]=25,[4965]=10,[4955]=4,[4950]=11,[4943]=8,[4934]=8,[4815]=17,[4774]=15,[4657]=11,[4196]=30,[4195]=27, + [4194]=27,[4192]=27,[4191]=27,[4190]=27,[4009]=65,[4008]=63,[3883]=22,[3791]=40,[3790]=35,[3789]=35,[3788]=40, + [3687]=40,[3675]=1,[3547]=1,[3546]=1,[3545]=1,[3544]=1,[3542]=1,[3541]=1,[3540]=1,[3539]=1,[3538]=1,[3537]=1, + [3536]=1,[3535]=1,[3534]=1,[3533]=1,[3532]=1,[3529]=1,[3527]=1,[3526]=1,[3525]=1,[13698]=1,[13699]=36,[13700]=46, + [13701]=56,[3524]=1,[3523]=1,[3522]=1,[13705]=1,[13706]=1,[13707]=1,[13708]=1,[13709]=1,[13710]=60,[13711]=60, + [13712]=60,[13713]=60,[13714]=60,[13715]=60,[13716]=60,[13717]=60,[13718]=1,[13719]=1,[13720]=1,[13721]=1,[13722]=1, + [13723]=1,[3150]=1,[3145]=1,[13726]=1,[13727]=100,[13728]=100,[13729]=100,[13730]=100,[13731]=100,[13732]=1,[13733]=1, + [13734]=1,[13735]=100,[13736]=100,[13737]=100,[13738]=100,[13739]=100,[13740]=100,[13741]=100,[13742]=100,[13743]=100, + [13744]=100,[13745]=100,[13746]=100,[13747]=100,[13748]=100,[13749]=100,[13750]=1,[13751]=1,[2486]=3,[13753]=1, + [2485]=3,[2484]=4,[2483]=3,[2482]=3,[2481]=4,[2478]=40,[2306]=6,[2255]=10,[13762]=100,[13763]=100,[13764]=100, + [13765]=100,[13766]=100,[13767]=100,[13768]=100,[13769]=100,[13770]=100,[13771]=100,[13772]=100,[13773]=100,[13774]=100, + [13775]=100,[13776]=100,[13777]=100,[13778]=100,[13779]=100,[13780]=100,[13781]=100,[13782]=100,[13783]=100,[13784]=100, + [13785]=100,[13786]=100,[13787]=1,[13788]=100,[13789]=100,[13790]=1,[13791]=100,[13792]=100,[13793]=1,[13794]=100, + [13795]=100,[13796]=1,[13797]=100,[13798]=100,[13799]=100,[13800]=100,[13801]=100,[13802]=100,[13803]=100,[13804]=100, + [13805]=100,[13806]=100,[13807]=100,[13808]=100,[13809]=100,[95]=1,[13811]=60,[13812]=58,[91]=1,[13814]=1,[90]=1, + [13816]=52,[13817]=58,[13818]=56,[13819]=59,[13820]=54,[13821]=57,[13822]=53,[13823]=51,[13824]=55,[13825]=57, + [88]=1,[58]=1,[54]=1,[50]=1,[46]=1,[42]=1,[41]=1,[17904]=60,[21120]=33,[21119]=33,[21118]=43,[19954]=65,[19953]=65, + [19952]=65,[19491]=65,[3440]=13,[13842]=25,[13843]=25,[13844]=25,[13845]=25,[13846]=25,[13847]=25,[13848]=25, + [13849]=25,[5286]=1,[23294]=68,[5303]=1,[5288]=1,[13854]=1,[13855]=1,[13856]=51,[13857]=52,[13858]=52,[13859]=1, + [13860]=53,[13861]=1,[13862]=1,[13863]=55,[13864]=56,[13865]=57,[13866]=59,[13867]=61,[13868]=51,[13869]=51,[13870]=53, + [13871]=56,[23663]=85,[2434]=37,[22470]=88,[2315]=20,[22423]=88,[2379]=5,[2467]=37,[21999]=60,[5293]=1,[23290]=66, + [13882]=45,[13883]=45,[13884]=45,[13885]=45,[13886]=45,[13887]=45,[3774]=1,[22856]=66,[2138]=7,[5289]=1,[2707]=1, + [5305]=1,[13894]=1,[13895]=60,[13896]=30,[13897]=10,[13898]=50,[13899]=20,[13900]=40,[13901]=55,[13902]=55,[13903]=55, + [13904]=55,[13905]=55,[13906]=55,[2718]=1,[19762]=1,[5262]=1,[2709]=1,[2715]=1,[2711]=1,[5300]=1,[13914]=55,[13915]=55, + [13916]=55,[13917]=55,[2201]=1,[13919]=1,[23293]=68,[22443]=88,[13922]=1,[13923]=1,[13924]=1,[13925]=1,[2183]=1, + [2182]=1,[2147]=1,[5301]=1,[2717]=1,[1910]=1,[6680]=1,[5281]=1,[1906]=1,[22442]=88,[13936]=62,[13937]=62,[13938]=62, + [2716]=1,[2023]=1,[18123]=1,[1899]=1,[4993]=1,[13944]=62,[5304]=1,[2706]=1,[5292]=1,[2703]=1,[4991]=1,[13950]=62, + [13951]=62,[13952]=62,[13953]=62,[13954]=61,[13955]=61,[13956]=61,[13957]=61,[13958]=60,[13959]=60,[13960]=61, + [13961]=60,[13962]=60,[13963]=60,[13964]=62,[13965]=63,[13966]=63,[13967]=61,[13968]=63,[13969]=61,[19404]=1, + [3494]=1,[2317]=20,[5285]=1,[21580]=1,[23289]=66,[2441]=22,[2202]=1,[1983]=1,[19015]=1,[23292]=68,[2376]=10,[13982]=63, + [13983]=62,[13984]=63,[3699]=1,[13986]=63,[18419]=1,[18596]=1,[1985]=1,[2463]=37,[1957]=1,[2053]=1,[18062]=1, + [2442]=27,[22341]=1,[22724]=1,[2081]=1,[4974]=12,[2017]=28,[18122]=1,[19980]=1,[14002]=63,[17282]=1,[19763]=1, + [22441]=88,[2443]=37,[21121]=1,[2327]=10,[2704]=1,[22326]=63,[5280]=1,[2714]=1,[21564]=1,[5284]=1,[18166]=1,[6088]=1, + [22150]=63,[2052]=1,[2014]=29,[5870]=1,[2705]=1,[14022]=62,[14023]=62,[14024]=61,[14025]=17,[21129]=1,[2051]=1, + [143]=1,[4044]=40,[1961]=1,[2465]=37,[2445]=22,[16443]=65,[19981]=1,[2464]=37,[1984]=1,[2199]=1,[6618]=1,[18167]=1, + [16419]=63,[6116]=1,[14042]=52,[14043]=54,[14044]=55,[14045]=56,[20184]=65,[20181]=63,[20177]=63,[20044]=63,[6836]=1, + [6366]=20,[23054]=89,[22812]=89,[22798]=89,[23048]=90,[23049]=90,[23047]=90,[23050]=90,[23037]=85,[23042]=85, + [23036]=83,[23025]=85,[22809]=83,[23071]=83,[22811]=83,[23053]=92,[23043]=90,[23073]=83,[22799]=89,[22800]=83, + [22801]=83,[22589]=90,[23065]=92,[23064]=92,[23062]=92,[23061]=92,[23668]=85,[23667]=85,[23666]=85,[23665]=85, + [23664]=85,[14082]=1,[14083]=4,[14084]=1,[14085]=1,[14086]=10,[14087]=8,[14088]=8,[14089]=10,[14090]=11,[14091]=11, + [14092]=1,[14093]=9,[14094]=11,[14095]=11,[14096]=16,[14097]=14,[14098]=10,[14099]=12,[14100]=54,[14101]=54,[14102]=13, + [14103]=55,[14104]=58,[14105]=1,[14106]=61,[14107]=55,[14108]=57,[14109]=16,[14110]=13,[14111]=58,[14112]=62, + [14113]=15,[14114]=16,[14115]=14,[14116]=14,[14117]=16,[14118]=1,[14119]=17,[14120]=20,[14121]=20,[14122]=18, + [14123]=17,[14124]=20,[14125]=21,[14126]=23,[14127]=24,[14128]=60,[14129]=20,[14130]=61,[14131]=19,[14132]=55, + [14133]=24,[14134]=55,[23288]=66,[14136]=57,[14137]=58,[14138]=60,[14139]=61,[14140]=62,[14141]=55,[14142]=54, + [14143]=53,[14144]=58,[14145]=18,[14146]=62,[14147]=18,[14148]=18,[14149]=18,[14150]=18,[14151]=18,[14152]=62, + [14153]=62,[14154]=62,[23286]=66,[23285]=66,[14157]=24,[14158]=26,[14159]=22,[14160]=19,[14161]=18,[14162]=23, + [14163]=26,[14164]=21,[14165]=25,[14166]=19,[14167]=19,[14168]=20,[14169]=21,[14170]=22,[14171]=22,[14172]=23, + [14173]=20,[14174]=19,[14175]=23,[14176]=26,[14177]=26,[14178]=31,[14179]=24,[14180]=30,[14181]=28,[14182]=28, + [14183]=30,[14184]=30,[14185]=27,[14186]=29,[14187]=28,[14188]=27,[14189]=32,[14190]=31,[14191]=30,[14192]=31, + [14193]=31,[14194]=28,[14195]=29,[14196]=32,[14197]=30,[14198]=31,[14199]=33,[14200]=35,[14201]=34,[14202]=36, + [14203]=35,[14204]=36,[14205]=32,[14206]=32,[14207]=36,[14208]=36,[14209]=33,[14210]=32,[14211]=34,[14212]=35, + [14213]=37,[14214]=34,[14215]=37,[14216]=41,[14217]=36,[14218]=37,[14219]=34,[14220]=40,[14221]=35,[14222]=37, + [14223]=38,[14224]=39,[14225]=41,[14226]=37,[23284]=66,[14228]=41,[14229]=36,[14230]=42,[14231]=38,[14232]=39, + [14233]=40,[14234]=42,[14235]=37,[14236]=38,[14237]=46,[14238]=41,[14239]=39,[14240]=40,[14241]=41,[14242]=43, + [14243]=43,[14244]=46,[14245]=41,[14246]=44,[14247]=44,[14248]=41,[14249]=47,[14250]=42,[14251]=40,[14252]=45, + [14253]=43,[14254]=47,[14255]=42,[23283]=66,[14257]=45,[14258]=45,[14259]=46,[14260]=44,[14261]=43,[14262]=45, + [14263]=48,[14264]=48,[14265]=51,[14266]=47,[14267]=51,[14268]=46,[14269]=47,[14270]=45,[14271]=49,[14272]=47, + [14273]=48,[14274]=51,[14275]=52,[14276]=47,[14277]=52,[14278]=50,[14279]=49,[14280]=48,[14281]=53,[14282]=50, + [14283]=54,[14284]=56,[14285]=50,[14286]=50,[14287]=56,[14288]=57,[14289]=51,[14290]=51,[14291]=50,[14292]=49, + [14293]=55,[14294]=51,[14295]=55,[14296]=52,[14297]=57,[14298]=56,[14299]=54,[14300]=52,[14301]=53,[14302]=56, + [14303]=60,[14304]=55,[14305]=57,[14306]=60,[14307]=59,[14308]=61,[14309]=56,[14310]=58,[14311]=55,[14312]=61, + [14313]=54,[14314]=58,[14315]=59,[14316]=59,[14317]=61,[14318]=63,[14319]=59,[14320]=57,[14321]=55,[14322]=62, + [14323]=60,[14324]=60,[14325]=61,[14326]=63,[14327]=58,[14328]=65,[14329]=62,[14330]=61,[14331]=58,[14332]=64, + [14333]=63,[14334]=63,[14335]=63,[14336]=65,[14337]=61,[22887]=68,[23177]=41,[14340]=62,[23173]=25,[23171]=25, + [23170]=35,[23169]=35,[23156]=62,[23132]=62,[23129]=62,[23128]=62,[23127]=63,[23126]=60,[23125]=60,[23124]=60, + [23092]=63,[23078]=63,[23075]=83,[23070]=85,[23069]=85,[23068]=83,[23051]=86,[23059]=92,[23014]=81,[23005]=83, + [14363]=16,[14364]=18,[14365]=15,[14366]=17,[14367]=19,[14368]=22,[14369]=23,[14370]=19,[14371]=23,[14372]=28, + [14373]=25,[14374]=24,[14375]=25,[14376]=22,[14377]=26,[14378]=27,[14379]=29,[14380]=28,[22994]=83,[14382]=1, + [14383]=1,[14384]=1,[14385]=1,[14386]=1,[14387]=1,[14388]=1,[14389]=1,[14390]=1,[14391]=1,[14392]=1,[14393]=1, + [14394]=1,[22939]=83,[22938]=83,[14397]=32,[14398]=33,[14399]=31,[14400]=29,[14401]=33,[14402]=29,[14403]=31, + [14404]=33,[14405]=33,[14406]=30,[14407]=39,[14408]=35,[14409]=33,[14410]=38,[14411]=35,[14412]=36,[14413]=39, + [14414]=34,[14415]=37,[14416]=34,[14417]=44,[14418]=39,[14419]=38,[14420]=38,[14421]=42,[14422]=40,[14423]=40, + [14424]=42,[14425]=44,[14426]=39,[14427]=49,[14428]=44,[14429]=43,[14430]=42,[14431]=44,[14432]=45,[14433]=46, + [14434]=49,[14435]=43,[14436]=46,[14437]=54,[14438]=48,[14439]=47,[14440]=46,[14441]=50,[14442]=49,[14443]=49, + [14444]=52,[14445]=54,[14446]=48,[14447]=53,[14448]=52,[14449]=57,[14450]=51,[14451]=53,[14452]=54,[14453]=59, + [14454]=53,[14455]=59,[14456]=64,[14457]=58,[14458]=60,[14459]=57,[14460]=63,[14461]=62,[14462]=62,[14463]=62, + [14464]=64,[14465]=60,[22937]=83,[22936]=83,[22935]=83,[22886]=68,[22885]=68,[22860]=66,[22865]=66,[22864]=66, + [22863]=66,[14475]=1,[22855]=66,[22852]=66,[22843]=66,[22816]=83,[22815]=81,[22813]=81,[22810]=81,[22808]=83, + [22807]=83,[22806]=81,[22804]=83,[14487]=62,[22803]=81,[22764]=70,[22763]=70,[22762]=70,[22761]=70,[22750]=65, + [22748]=65,[22747]=65,[22743]=1,[22720]=68,[22718]=68,[22716]=68,[22715]=68,[22714]=68,[14502]=62,[14503]=62, + [22707]=80,[22702]=80,[22701]=80,[22678]=60,[22665]=80,[22652]=80,[22651]=65,[22518]=88,[22512]=92,[22510]=88, + [22509]=88,[22507]=86,[22506]=88,[22505]=88,[22504]=92,[22502]=88,[22501]=88,[22481]=88,[14522]=62,[22478]=88, + [14524]=1,[14525]=62,[22476]=92,[14527]=1,[14528]=62,[22468]=86,[22467]=86,[14531]=59,[14532]=1,[14533]=1,[14534]=1, + [14535]=1,[14536]=61,[14537]=62,[14538]=62,[14539]=62,[22348]=65,[14541]=61,[22347]=65,[14543]=62,[22345]=62, + [14545]=62,[23060]=92,[22340]=63,[14548]=62,[14549]=45,[14550]=49,[14551]=49,[14552]=55,[14553]=61,[14554]=62, + [14555]=63,[22327]=63,[14557]=63,[14558]=64,[14559]=18,[14560]=19,[14561]=17,[14562]=23,[14563]=17,[14564]=19, + [14565]=21,[14566]=25,[14567]=23,[14568]=23,[14569]=22,[14570]=28,[14571]=21,[14572]=24,[14573]=27,[14574]=26, + [14575]=1,[14576]=59,[14577]=61,[14578]=29,[14579]=31,[14580]=27,[14581]=33,[14582]=28,[14583]=32,[14584]=35, + [14585]=32,[14586]=1,[14587]=32,[14588]=36,[14589]=37,[14590]=35,[14591]=40,[14592]=40,[14593]=35,[14594]=37, + [14595]=38,[14596]=38,[14597]=41,[14598]=40,[14599]=42,[14600]=40,[14601]=44,[14602]=39,[14603]=41,[14604]=45, + [14605]=43,[14606]=41,[14607]=37,[14608]=31,[14609]=17,[22197]=68,[14611]=61,[14612]=61,[22196]=72,[14614]=61, + [14615]=61,[14616]=61,[22195]=68,[14618]=1,[22149]=63,[14620]=61,[14621]=61,[14622]=61,[14623]=61,[14624]=61, + [22013]=60,[14626]=61,[22010]=65,[22009]=60,[14629]=61,[22007]=66,[14631]=61,[14632]=61,[14633]=61,[22005]=60, + [21994]=65,[14636]=61,[14637]=61,[14638]=61,[21996]=65,[14640]=61,[14641]=61,[14642]=1,[14643]=1,[22001]=65,[21997]=60, + [22000]=66,[21995]=60,[21809]=71,[21806]=71,[21805]=68,[21803]=68,[14652]=45,[14653]=46,[14654]=44,[14655]=49, + [14656]=44,[14657]=46,[14658]=49,[14659]=47,[14660]=47,[14661]=49,[14662]=51,[14663]=48,[14664]=54,[14665]=48, + [14666]=51,[14667]=53,[14668]=52,[14669]=51,[14670]=59,[14671]=56,[14672]=53,[14673]=52,[14674]=55,[14675]=56, + [14676]=58,[14677]=58,[14678]=57,[21802]=68,[14680]=64,[14681]=62,[14682]=59,[14683]=59,[14684]=60,[14685]=62, + [14686]=63,[14687]=62,[14688]=61,[14689]=12,[14690]=9,[14691]=11,[14692]=9,[14693]=10,[14694]=11,[14695]=12,[14696]=11, + [14697]=13,[14698]=18,[14699]=15,[14700]=12,[14701]=13,[14702]=14,[14703]=14,[14704]=16,[14705]=16,[14706]=1, + [14707]=1,[2020]=18,[2025]=20,[2030]=20,[2042]=24,[2044]=35,[2046]=24,[2047]=5,[2054]=4,[2057]=4,[2058]=27,[2064]=11, + [2065]=9,[2066]=8,[2072]=27,[14722]=17,[14723]=17,[14724]=16,[14725]=17,[14726]=18,[14727]=19,[14728]=22,[14729]=20, + [14730]=23,[2073]=15,[2074]=18,[2075]=12,[2077]=29,[19336]=76,[2079]=17,[2080]=34,[2084]=30,[2087]=13,[2088]=15, + [2089]=18,[14742]=24,[14743]=22,[14744]=28,[14745]=20,[14746]=22,[14747]=23,[14748]=25,[14749]=26,[14750]=28, + [14751]=33,[14752]=27,[14753]=33,[14754]=29,[14755]=28,[14756]=29,[14757]=32,[14758]=31,[14759]=34,[14760]=39, + [14761]=34,[14762]=37,[14763]=32,[14764]=35,[14765]=38,[14766]=37,[14767]=38,[14768]=44,[14769]=42,[14770]=40, + [14771]=39,[14772]=40,[14773]=39,[14774]=43,[14775]=43,[14776]=43,[14777]=44,[14778]=45,[14779]=49,[14780]=49, + [14781]=44,[14782]=45,[14783]=46,[14784]=46,[14785]=48,[14786]=47,[14787]=47,[14788]=49,[14789]=54,[14790]=54, + [14791]=48,[14792]=50,[14793]=50,[14794]=50,[14795]=53,[14796]=53,[14797]=51,[14798]=59,[14799]=58,[14800]=59, + [14801]=52,[14802]=55,[14803]=55,[14804]=58,[14805]=57,[14806]=57,[14807]=53,[14808]=59,[14809]=62,[14810]=59, + [14811]=64,[14812]=64,[14813]=57,[14814]=63,[14815]=62,[14816]=62,[14817]=62,[14818]=1,[14819]=1,[14820]=1,[14821]=43, + [14822]=1,[14823]=1,[14824]=1,[14825]=43,[14826]=41,[14827]=41,[14828]=42,[14829]=42,[14830]=42,[14831]=43,[14832]=41, + [14833]=44,[14834]=43,[14835]=48,[14836]=1,[14837]=1,[14838]=43,[14839]=44,[14840]=47,[14841]=44,[14842]=48,[14843]=46, + [14844]=54,[14845]=1,[14846]=50,[14847]=49,[14848]=50,[14849]=53,[14850]=52,[14851]=51,[14852]=54,[14853]=48, + [14854]=59,[14855]=55,[14856]=54,[14857]=54,[14858]=58,[14859]=57,[14860]=56,[14861]=52,[14862]=63,[14863]=60, + [14864]=59,[14865]=60,[14866]=62,[14867]=62,[14868]=61,[14869]=58,[14870]=1,[14871]=1,[2440]=50,[14873]=1,[14874]=1, + [14875]=1,[14876]=1,[14877]=1,[14878]=1,[14879]=1,[14880]=1,[14881]=1,[14882]=1,[14883]=5,[14884]=5,[14885]=5, + [14886]=5,[14887]=5,[14888]=5,[14889]=5,[14890]=5,[14891]=5,[14892]=5,[14893]=1,[4051]=30,[14895]=41,[14896]=40, + [14897]=40,[14898]=40,[14899]=41,[14900]=40,[14901]=41,[14902]=41,[14903]=40,[14904]=50,[14905]=45,[14906]=44, + [14907]=48,[14908]=48,[14909]=45,[14910]=44,[14911]=46,[14912]=50,[14913]=49,[14914]=46,[14915]=53,[14916]=53, + [14917]=48,[14918]=47,[14919]=52,[14920]=51,[14921]=49,[14922]=53,[14923]=50,[14924]=57,[14925]=57,[14926]=53, + [14927]=52,[14928]=55,[14929]=54,[14930]=57,[14931]=62,[14932]=58,[14933]=58,[14934]=57,[14935]=60,[14936]=61, + [14937]=59,[14938]=56,[14939]=46,[14940]=43,[14941]=42,[14942]=42,[14943]=42,[14944]=45,[14945]=45,[14946]=43, + [14947]=46,[14948]=51,[14949]=47,[14950]=46,[14951]=47,[14952]=50,[14953]=49,[14954]=51,[14955]=47,[14956]=45, + [14957]=51,[14958]=56,[14959]=52,[14960]=51,[14961]=55,[14962]=54,[14963]=53,[14964]=56,[14965]=49,[14966]=61, + [14967]=56,[14968]=55,[14969]=59,[14970]=58,[14971]=57,[14972]=56,[14973]=60,[14974]=55,[14975]=65,[14976]=61, + [14977]=60,[14978]=63,[14979]=64,[14980]=63,[14981]=62,[14982]=65,[14983]=59,[4058]=41,[1201]=10,[4068]=40,[18338]=59, + [4120]=40,[4121]=35,[4122]=37,[4129]=44,[4134]=46,[4138]=45,[18321]=59,[18313]=58,[18296]=56,[18204]=66,[18203]=66, + [17759]=60,[20580]=71,[17742]=51,[17686]=43,[15003]=8,[15004]=9,[15005]=9,[15006]=9,[15007]=8,[15008]=10,[15009]=11, + [15010]=11,[15011]=15,[15012]=16,[15013]=14,[15014]=17,[15015]=13,[15016]=16,[15017]=19,[15018]=20,[15019]=21, + [20622]=71,[4242]=15,[4243]=17,[20627]=71,[4246]=16,[4247]=29,[4248]=26,[4249]=25,[4250]=25,[4251]=26,[4252]=28, + [4314]=22,[4315]=24,[4316]=22,[4317]=25,[4318]=26,[4319]=29,[4322]=33,[4324]=30,[2432]=37,[16434]=63,[16430]=63, + [3442]=12,[3443]=10,[3444]=11,[15045]=52,[15046]=54,[15047]=61,[15048]=57,[15049]=59,[15050]=58,[15051]=60,[15052]=62, + [15053]=57,[15054]=54,[15055]=61,[15056]=57,[15057]=55,[15058]=59,[15059]=60,[15060]=57,[15061]=54,[15062]=60, + [15063]=58,[15064]=55,[15065]=57,[15066]=58,[15067]=54,[15068]=62,[15069]=57,[15070]=59,[15071]=55,[15072]=56, + [15073]=55,[15074]=53,[15075]=58,[15076]=53,[15077]=51,[15078]=55,[15079]=57,[15080]=59,[15081]=61,[15082]=56, + [15083]=52,[15084]=53,[15085]=61,[15086]=56,[15087]=58,[15088]=60,[15089]=44,[15090]=62,[15091]=54,[15092]=55, + [15093]=56,[15094]=58,[15095]=60,[15096]=62,[18168]=65,[1639]=49,[1218]=21,[1219]=16,[1220]=20,[3511]=15,[17578]=65, + [15104]=39,[15105]=40,[15106]=40,[15107]=40,[15108]=40,[15109]=25,[15110]=20,[15111]=21,[15112]=20,[15113]=23, + [15114]=19,[15115]=22,[15116]=26,[15117]=24,[15118]=26,[15119]=56,[15120]=26,[15121]=28,[15122]=25,[15123]=28, + [15124]=25,[15125]=29,[15126]=29,[15127]=30,[15128]=31,[15129]=31,[15130]=34,[15131]=32,[15132]=29,[15133]=33, + [15134]=37,[15135]=30,[15136]=31,[15137]=33,[15138]=60,[15139]=33,[15140]=34,[15141]=62,[15142]=35,[15143]=33, + [15144]=37,[15145]=36,[15146]=39,[15147]=33,[15148]=34,[15149]=36,[15150]=36,[15151]=36,[15152]=41,[15153]=37, + [15154]=38,[15155]=39,[15156]=43,[15157]=41,[15158]=40,[15159]=42,[15160]=39,[15161]=43,[15162]=45,[15163]=43, + [15164]=47,[15165]=42,[15166]=45,[15167]=48,[15168]=45,[15169]=44,[15170]=52,[15171]=50,[15172]=47,[15173]=46, + [15174]=50,[15175]=51,[15176]=50,[15177]=49,[15178]=47,[15179]=57,[15180]=53,[15181]=55,[15182]=51,[15183]=50, + [15184]=54,[15185]=57,[15186]=55,[15187]=54,[15188]=57,[15189]=60,[15190]=55,[15191]=57,[15192]=60,[15193]=62, + [15194]=61,[15195]=62,[3471]=10,[3474]=15,[3487]=19,[3488]=13,[15200]=35,[4327]=40,[15202]=18,[15203]=18,[15204]=18, + [15205]=20,[15206]=20,[15207]=20,[4732]=37,[4733]=46,[15210]=16,[15211]=22,[15212]=27,[15213]=36,[15214]=40,[15215]=45, + [15216]=51,[15217]=54,[15218]=57,[15219]=59,[15220]=62,[15221]=65,[15222]=19,[15223]=24,[15224]=25,[15225]=33, + [15226]=37,[15227]=49,[15228]=53,[15229]=55,[15230]=25,[15231]=31,[15232]=33,[15233]=39,[15234]=40,[15235]=48, + [15236]=52,[15237]=55,[15238]=58,[15239]=61,[15240]=64,[15241]=26,[15242]=30,[15243]=36,[15244]=42,[15245]=50, + [15246]=62,[15247]=64,[15248]=20,[15249]=26,[15250]=32,[15251]=43,[15252]=49,[15253]=52,[15254]=54,[15255]=57, + [15256]=59,[15257]=62,[15258]=65,[15259]=25,[15260]=38,[15261]=40,[15262]=46,[15263]=50,[15264]=56,[15265]=58, + [15266]=61,[15267]=63,[15268]=16,[15269]=24,[15270]=46,[15271]=56,[15272]=59,[15273]=63,[15274]=52,[15275]=54, + [15276]=58,[4734]=43,[15278]=60,[15279]=51,[15280]=53,[15281]=57,[15282]=60,[15283]=64,[15284]=29,[15285]=32, + [15286]=35,[15287]=45,[15288]=61,[15289]=65,[3484]=29,[15291]=51,[4743]=50,[4745]=40,[15294]=53,[15295]=55,[15296]=63, + [15297]=11,[15298]=13,[15299]=10,[15300]=14,[15301]=13,[15302]=11,[15303]=14,[15304]=16,[15305]=18,[15306]=16, + [15307]=19,[15308]=17,[15309]=15,[15310]=18,[15311]=22,[15312]=20,[15313]=24,[3311]=15,[3741]=24,[3650]=9,[3651]=15, + [3656]=27,[3732]=30,[4929]=9,[4935]=8,[15322]=39,[15323]=50,[15324]=56,[15325]=60,[15326]=40,[15327]=40,[4936]=8, + [15329]=24,[15330]=25,[15331]=23,[15332]=27,[15333]=22,[15334]=27,[15335]=14,[15336]=27,[15337]=29,[15338]=28, + [15339]=34,[15340]=27,[15341]=30,[15342]=30,[15343]=30,[15344]=31,[15345]=31,[15346]=32,[15347]=28,[15348]=26, + [15349]=33,[15350]=34,[15351]=30,[15352]=34,[15353]=38,[15354]=32,[15355]=34,[15356]=36,[15357]=35,[15358]=35, + [15359]=41,[15360]=38,[15361]=37,[15362]=39,[15363]=42,[15364]=36,[15365]=38,[15366]=40,[15367]=39,[15368]=39, + [15369]=42,[15370]=44,[15371]=41,[15372]=43,[15373]=47,[15374]=44,[15375]=43,[15376]=46,[15377]=42,[15378]=46, + [15379]=48,[15380]=46,[15381]=51,[15382]=45,[15383]=48,[15384]=50,[15385]=49,[15386]=48,[15387]=50,[15388]=52, + [15389]=53,[15390]=56,[15391]=56,[15392]=49,[15393]=52,[15394]=54,[15395]=53,[15396]=14,[15397]=14,[15398]=14, + [15399]=14,[15400]=14,[15401]=14,[15402]=14,[15403]=18,[15404]=18,[15405]=17,[15406]=17,[4937]=9,[4939]=11,[3778]=31, + [3779]=32,[15411]=63,[3780]=33,[15413]=63,[3781]=34,[4961]=10,[4962]=8,[4963]=8,[15418]=63,[21347]=81,[4967]=11, + [15421]=63,[4968]=11,[4969]=10,[15424]=18,[15425]=55,[15426]=58,[15427]=54,[15428]=56,[15429]=58,[15430]=60,[15431]=59, + [15432]=58,[15433]=61,[15434]=61,[15435]=63,[15436]=60,[15437]=61,[15438]=63,[15439]=64,[15440]=63,[15441]=63, + [15442]=65,[15443]=18,[15444]=18,[15445]=18,[4970]=9,[4971]=12,[4972]=10,[15449]=18,[15450]=18,[15451]=18,[15452]=18, + [15453]=18,[4973]=10,[15455]=37,[15456]=37,[15457]=28,[15458]=28,[15459]=28,[15460]=1,[15461]=25,[15462]=25,[15463]=25, + [15464]=28,[15465]=28,[15466]=28,[15467]=31,[15468]=29,[15469]=29,[15470]=29,[15471]=29,[15472]=9,[15473]=10, + [15474]=8,[15475]=8,[15476]=10,[15477]=11,[15478]=8,[15479]=11,[15480]=13,[15481]=13,[15482]=11,[15483]=10,[15484]=12, + [15485]=14,[15486]=12,[15487]=16,[15488]=21,[15489]=16,[15490]=14,[15491]=15,[15492]=15,[15493]=18,[15494]=18, + [15495]=15,[15496]=21,[15497]=19,[15498]=20,[15499]=18,[15500]=24,[15501]=17,[15502]=20,[15503]=22,[15504]=22, + [15505]=23,[15506]=21,[15507]=19,[15508]=19,[15509]=21,[15510]=20,[15511]=24,[15512]=24,[15513]=25,[15514]=26, + [15515]=25,[15516]=27,[15517]=25,[15518]=30,[15519]=23,[15520]=26,[15521]=27,[15522]=29,[15523]=27,[15524]=31, + [15525]=28,[15526]=24,[15527]=27,[15528]=26,[15529]=29,[15530]=31,[15531]=30,[15532]=26,[15533]=31,[15534]=31, + [15535]=29,[15536]=34,[15537]=28,[15538]=30,[15539]=30,[15540]=34,[15541]=33,[15542]=32,[15543]=34,[15544]=32, + [15545]=30,[15546]=36,[15547]=29,[15548]=32,[15549]=31,[15550]=35,[15551]=35,[15552]=36,[15553]=34,[15554]=33, + [15555]=33,[15556]=32,[15557]=37,[15558]=37,[15559]=31,[15560]=34,[15561]=36,[15562]=36,[15563]=37,[4979]=42, + [15565]=38,[15566]=35,[15567]=40,[15568]=33,[15569]=40,[15570]=36,[15571]=35,[15572]=39,[15573]=38,[15574]=40, + [15575]=36,[15576]=39,[15577]=36,[15578]=41,[15579]=35,[15580]=40,[15581]=38,[15582]=40,[15583]=41,[15584]=41, + [15585]=35,[4977]=41,[15587]=35,[15588]=35,[15589]=41,[15590]=37,[15591]=43,[15592]=43,[15593]=42,[15594]=37, + [15595]=39,[15596]=41,[15597]=42,[15598]=38,[15599]=44,[15600]=42,[15601]=46,[15602]=45,[15603]=41,[15604]=46, + [15605]=42,[15606]=41,[15607]=44,[15608]=44,[15609]=47,[15610]=43,[15611]=43,[15612]=44,[15613]=42,[15614]=45, + [15615]=46,[15616]=46,[15617]=45,[15618]=47,[15619]=48,[15620]=47,[15621]=51,[15622]=51,[15623]=50,[15624]=45, + [15625]=47,[15626]=47,[15627]=50,[15628]=48,[15629]=48,[15630]=49,[15631]=52,[15632]=46,[15633]=52,[15634]=52, + [15635]=48,[15636]=49,[15637]=51,[15638]=49,[15639]=50,[15640]=56,[15641]=51,[15642]=52,[15643]=49,[15644]=52, + [15645]=55,[15646]=55,[15647]=53,[15648]=56,[15649]=51,[15650]=57,[15651]=56,[15652]=51,[15653]=53,[15654]=54, + [15655]=56,[15656]=54,[15657]=57,[15658]=59,[15659]=55,[15660]=61,[15661]=54,[15662]=57,[15663]=56,[15664]=60, + [15665]=60,[15666]=59,[15667]=61,[15668]=58,[15669]=62,[15670]=61,[15671]=56,[15672]=60,[15673]=58,[15674]=60, + [15675]=62,[15676]=61,[15677]=61,[15678]=63,[15679]=61,[15680]=65,[15681]=58,[15682]=63,[15683]=60,[15684]=64, + [15685]=63,[15686]=63,[15687]=65,[4982]=38,[15689]=35,[15690]=41,[15691]=38,[15692]=38,[15693]=59,[15694]=54, + [15695]=38,[21367]=81,[15697]=38,[15698]=38,[4987]=45,[2219]=22,[21388]=78,[15702]=55,[15703]=55,[15704]=60,[15705]=57, + [15706]=57,[15707]=58,[15708]=58,[15709]=58,[5007]=31,[2141]=27,[5011]=40,[5016]=35,[5028]=47,[2000]=35,[1998]=33, + [1997]=34,[1992]=38,[1990]=36,[2041]=24,[1945]=18,[1720]=46,[1215]=22,[6419]=38,[5327]=18,[5326]=18,[5325]=16, + [5324]=16,[5323]=25,[5322]=26,[5321]=20,[5320]=16,[5319]=20,[5318]=20,[5317]=25,[5316]=25,[5315]=18,[5314]=20, + [5313]=25,[5312]=20,[5311]=21,[5310]=20,[5309]=20,[5306]=20,[21685]=76,[21682]=78,[21650]=77,[5256]=35,[5252]=21, + [5244]=30,[5243]=20,[5242]=16,[5241]=18,[5240]=21,[5239]=46,[5238]=45,[21619]=78,[5216]=45,[5215]=41,[5214]=32, + [5213]=35,[5202]=24,[5200]=22,[5199]=21,[5198]=22,[5196]=22,[5183]=20,[5182]=20,[5180]=34,[21495]=71,[5111]=15, + [5110]=18,[5109]=17,[5094]=24,[5093]=21,[5092]=23,[21462]=72,[21454]=72,[5069]=12,[1200]=5,[21412]=67,[15782]=60, + [15783]=60,[15784]=59,[21392]=70,[15786]=59,[15787]=59,[2024]=21,[15789]=56,[2227]=27,[15791]=58,[15792]=58,[4983]=42, + [15794]=10,[15795]=58,[15796]=59,[15797]=59,[4978]=36,[15799]=58,[15800]=58,[15801]=58,[15802]=56,[4976]=40,[15804]=56, + [15805]=61,[15806]=61,[15807]=8,[15808]=21,[15809]=34,[15810]=25,[15811]=35,[15812]=56,[15813]=56,[15814]=60, + [15815]=60,[4954]=5,[4951]=7,[4949]=21,[4948]=11,[4947]=11,[4946]=10,[15822]=55,[15823]=55,[15824]=59,[15825]=59, + [4933]=9,[15827]=59,[4928]=8,[2308]=15,[2309]=15,[2311]=13,[3785]=38,[4861]=10,[3784]=37,[4827]=28,[4826]=26, + [4825]=29,[4824]=27,[4822]=23,[4821]=23,[4820]=25,[4818]=24,[4817]=22,[4816]=24,[4800]=23,[4799]=23,[4798]=25, + [4797]=25,[4796]=25,[4795]=25,[3742]=28,[4771]=15,[15853]=60,[15854]=60,[15855]=60,[15856]=60,[15857]=60,[15858]=59, + [15859]=59,[15860]=60,[15861]=60,[15862]=54,[15863]=54,[15864]=39,[15865]=39,[15866]=15,[15867]=60,[16422]=63, + [16426]=63,[16442]=65,[16462]=65,[16536]=65,[15873]=60,[2028]=21,[4323]=34,[4321]=28,[4320]=25,[4313]=20,[4312]=16, + [4311]=21,[4310]=17,[4309]=14,[4308]=12,[4307]=10,[20686]=68,[4302]=10,[15887]=62,[15888]=60,[15889]=57,[15890]=59, + [15891]=26,[15892]=32,[15893]=21,[15894]=25,[15895]=8,[1213]=14,[2645]=7,[2078]=18,[18535]=59,[1560]=21,[17102]=74, + [16418]=63,[15903]=25,[15904]=35,[15905]=15,[15906]=15,[15907]=25,[16440]=71,[15909]=35,[15910]=1,[16444]=65, + [15912]=23,[16463]=65,[16468]=65,[16503]=63,[16504]=63,[16522]=63,[15918]=38,[16577]=65,[16668]=61,[16669]=60, + [20714]=63,[20712]=63,[4328]=36,[15925]=10,[15926]=17,[15927]=27,[15928]=31,[15929]=37,[15930]=56,[15931]=61, + [15932]=12,[15933]=15,[15934]=32,[15935]=34,[15936]=55,[15937]=51,[15938]=58,[15939]=59,[15940]=62,[15941]=64, + [15942]=65,[15943]=61,[15944]=12,[15945]=18,[15946]=23,[15947]=28,[17580]=65,[17581]=65,[20673]=65,[20647]=59, + [4263]=10,[4262]=37,[4260]=39,[4259]=36,[4258]=34,[4257]=32,[4256]=35,[4255]=31,[4254]=30,[4253]=27,[15962]=33, + [15963]=39,[15964]=44,[15965]=49,[15966]=54,[15967]=59,[15968]=64,[15969]=10,[15970]=15,[15971]=20,[15972]=24, + [15973]=30,[15974]=26,[15975]=31,[15976]=36,[15977]=37,[15978]=41,[15979]=42,[15980]=46,[15981]=47,[15982]=51, + [15983]=52,[15984]=56,[15985]=57,[15986]=60,[15987]=61,[15988]=63,[15989]=65,[15990]=39,[15991]=63,[4061]=42, + [4060]=40,[4059]=37,[15995]=52,[4057]=36,[4055]=34,[4054]=35,[15999]=54,[4048]=31,[4047]=43,[4046]=45,[4045]=42, + [16004]=55,[4043]=38,[4042]=39,[16007]=61,[16008]=58,[16009]=58,[4024]=47,[4023]=44,[3997]=56,[3986]=48,[18394]=62, + [18398]=63,[18404]=74,[18409]=62,[18410]=57,[18420]=63,[18442]=35,[3837]=38,[16022]=60,[3835]=33,[3834]=8,[3833]=8, + [16026]=60,[16027]=60,[16028]=60,[16029]=60,[16030]=60,[16031]=60,[3812]=36,[16033]=60,[16034]=60,[16035]=60, + [16036]=60,[16037]=60,[16038]=60,[16039]=57,[3804]=36,[3803]=38,[3793]=32,[3792]=34,[3787]=40,[3786]=39,[3751]=30, + [3747]=30,[3743]=28,[3733]=23,[3719]=30,[18502]=62,[18503]=62,[18504]=62,[18505]=62,[3655]=21,[3654]=14,[3653]=15, + [16058]=63,[3649]=11,[18520]=63,[16061]=35,[16062]=35,[16063]=35,[16064]=35,[16065]=35,[16066]=35,[16067]=61, + [18532]=62,[18533]=63,[19990]=52,[18541]=70,[18542]=68,[3599]=5,[3589]=17,[3587]=50,[3586]=16,[3585]=22,[18546]=69, + [3582]=18,[3581]=18,[19961]=68,[3572]=17,[19950]=68,[3566]=29,[3565]=20,[3563]=20,[3562]=27,[3561]=26,[18586]=35, + [18587]=53,[18646]=71,[18674]=59,[18682]=61,[18757]=62,[18758]=62,[3493]=30,[3492]=30,[3491]=25,[3490]=25,[3483]=27, + [3482]=26,[3481]=25,[3480]=22,[18807]=62,[3473]=13,[3472]=12,[19852]=68,[18809]=71,[19846]=61,[3462]=24,[19841]=68, + [3457]=18,[19838]=65,[3453]=12,[3452]=22,[16116]=35,[16117]=35,[16118]=35,[16119]=35,[16120]=35,[16121]=35,[16122]=35, + [16123]=35,[16124]=35,[16125]=35,[16126]=35,[16127]=35,[16128]=35,[16129]=35,[16130]=35,[16131]=35,[16132]=35, + [16133]=35,[16134]=35,[16135]=35,[16136]=35,[16137]=35,[16138]=35,[16139]=35,[16140]=35,[16141]=35,[16142]=35, + [16143]=35,[16144]=35,[16145]=35,[16146]=35,[16147]=35,[16148]=35,[16149]=35,[16150]=35,[16151]=35,[16152]=35, + [16153]=35,[16154]=35,[16155]=35,[16156]=35,[16157]=35,[16158]=35,[16159]=35,[16160]=40,[16161]=40,[16162]=40, + [16163]=35,[16164]=35,[16165]=35,[19337]=76,[19340]=76,[19341]=76,[19342]=76,[19343]=76,[19344]=76,[16172]=40, + [19346]=74,[19347]=77,[19348]=74,[19349]=77,[19350]=75,[19351]=75,[19352]=77,[19353]=75,[19354]=71,[19355]=75, + [19618]=60,[19614]=60,[3230]=26,[3229]=23,[3228]=26,[3227]=23,[19608]=68,[3224]=10,[3223]=11,[19600]=68,[3216]=10, + [19597]=45,[3213]=13,[3212]=26,[3211]=19,[3210]=30,[3209]=32,[3208]=48,[3207]=14,[3206]=28,[3205]=17,[3204]=26, + [3203]=28,[3202]=24,[3201]=28,[3200]=8,[3199]=22,[3198]=23,[16211]=60,[16212]=60,[16213]=60,[3194]=21,[3193]=21, + [3192]=12,[3191]=26,[3190]=8,[3189]=8,[3188]=15,[3187]=44,[3186]=30,[3185]=34,[3184]=20,[19549]=33,[19544]=43, + [3160]=15,[19541]=33,[19537]=33,[3153]=9,[3152]=9,[3151]=10,[19520]=43,[19518]=63,[19514]=63,[19439]=71,[19438]=71, + [19431]=75,[19430]=75,[19407]=75,[19406]=75,[19405]=75,[19403]=75,[19402]=75,[19401]=75,[19383]=83,[19374]=75, + [19436]=70,[19432]=75,[19373]=75,[19372]=74,[19371]=74,[19370]=73,[19394]=75,[19391]=77,[19375]=83,[2986]=20, + [2985]=21,[2984]=18,[2983]=17,[2982]=20,[2981]=21,[2980]=15,[2979]=14,[2978]=15,[2977]=16,[2975]=14,[2974]=16, + [2973]=17,[19334]=73,[2912]=32,[2910]=25,[18814]=78,[19170]=70,[19166]=66,[18810]=71,[18808]=70,[19157]=70,[19149]=66, + [19137]=78,[18806]=70,[18805]=70,[19104]=65,[18803]=70,[18756]=62,[18755]=62,[18754]=62,[18745]=57,[18744]=58, + [18709]=50,[18699]=57,[18697]=55,[18693]=62,[18690]=62,[18665]=71,[18639]=60,[18609]=75,[18863]=0,[18858]=0,[18608]=75, + [18834]=0,[18831]=78,[18812]=71,[2428]=50,[18760]=62,[18547]=71,[18686]=62,[18683]=61,[16309]=63,[18534]=63,[18637]=55, + [18543]=66,[18536]=59,[18529]=61,[16315]=30,[2126]=5,[2125]=5,[2124]=5,[2123]=5,[18500]=61,[18497]=60,[18495]=63, + [18493]=60,[18483]=61,[2099]=58,[18475]=60,[2069]=12,[2067]=10,[1994]=46,[1926]=15,[1925]=16,[1825]=28,[1822]=23, + [16334]=45,[16335]=63,[16336]=45,[16337]=60,[1522]=36,[1396]=1,[16340]=45,[16341]=50,[16342]=63,[17772]=42,[1387]=19, + [16345]=78,[1383]=5,[17755]=50,[17753]=53,[1369]=5,[1368]=4,[1367]=3,[1366]=2,[17743]=53,[17738]=52,[17734]=53, + [17687]=43,[20165]=53,[20166]=43,[1211]=15,[17590]=65,[1203]=54,[1194]=4,[1193]=17,[1190]=20,[1189]=20,[1183]=10, + [16367]=60,[17192]=24,[16369]=63,[16370]=60,[17182]=80,[17110]=65,[17103]=71,[16670]=59,[16622]=57,[16578]=65, + [16530]=63,[16523]=63,[16435]=63,[16431]=63,[16427]=63,[16423]=63,[16420]=63, +} + + +RelationshipsDashboardDB_TurtleItems = { + [10]=6,[61439]=64,[61440]=64,[61443]=66,[61447]=50,[61448]=78,[61449]=68,[61450]=68,[26]=2,[27]=2,[28]=2,[61454]=72, + [61455]=78,[61456]=64,[61465]=65,[61467]=44,[61468]=44,[61471]=45,[61472]=45,[61475]=43,[61476]=43,[61478]=43, + [61481]=43,[16437]=71,[61483]=43,[16441]=74,[16442]=71,[16443]=74,[16444]=74,[61490]=45,[41016]=5,[61492]=43, + [61493]=43,[41019]=5,[41020]=5,[41021]=5,[61497]=47,[61498]=47,[61499]=47,[61500]=19,[61501]=19,[61502]=19,[61503]=19, + [61504]=26,[61505]=26,[61506]=37,[16462]=71,[16463]=71,[61509]=58,[16465]=74,[16466]=74,[16467]=71,[16468]=74, + [61514]=48,[61515]=57,[61516]=57,[61517]=53,[61518]=60,[61519]=60,[61520]=60,[61521]=57,[61522]=81,[61523]=81, + [61524]=81,[61525]=81,[61526]=81,[20577]=76,[20578]=76,[20579]=75,[20580]=75,[20581]=75,[20582]=75,[61533]=57, + [61534]=57,[61535]=54,[61536]=53,[61537]=53,[61538]=53,[61539]=53,[61540]=53,[61541]=57,[61542]=57,[61543]=57, + [61544]=57,[61545]=63,[61546]=63,[61547]=63,[61548]=63,[20599]=76,[20600]=76,[61551]=62,[61552]=36,[61553]=35, + [61554]=36,[61555]=35,[41081]=10,[41082]=10,[41083]=10,[41084]=10,[41085]=10,[41086]=10,[61562]=63,[61563]=63, + [61564]=64,[20615]=75,[20616]=75,[20617]=75,[20618]=75,[20619]=75,[61570]=63,[20621]=76,[20622]=76,[20623]=76, + [20624]=76,[20625]=76,[20626]=76,[20627]=76,[16533]=74,[20629]=76,[20630]=76,[16536]=74,[20632]=76,[20633]=76, + [16539]=71,[16540]=71,[20636]=76,[20637]=76,[20638]=76,[20639]=76,[61590]=63,[61591]=63,[61592]=63,[61593]=63, + [16549]=74,[16550]=74,[16551]=74,[16552]=71,[61598]=48,[16554]=71,[16555]=71,[61601]=46,[61602]=46,[16558]=71, + [61604]=46,[16560]=71,[16561]=74,[16562]=74,[16563]=74,[16564]=71,[16565]=74,[16566]=74,[16567]=71,[16568]=74, + [16569]=71,[61615]=58,[16571]=71,[61617]=45,[16573]=71,[16574]=71,[61620]=50,[61621]=50,[16577]=74,[16578]=74, + [16579]=71,[16580]=74,[41151]=8,[61627]=46,[61628]=46,[61629]=46,[61630]=46,[41156]=8,[20682]=68,[61633]=45,[61634]=45, + [20685]=68,[20688]=68,[20691]=68,[61645]=65,[61646]=65,[61647]=65,[61648]=58,[61649]=64,[61650]=74,[61651]=74, + [41182]=12,[41183]=12,[41184]=12,[61660]=45,[61661]=45,[61662]=45,[41188]=12,[41189]=12,[41190]=13,[41191]=13, + [61667]=50,[61668]=48,[61669]=49,[61670]=50,[61671]=49,[61672]=49,[61677]=43,[61678]=43,[61679]=43,[41205]=10, + [41206]=10,[41207]=10,[61683]=45,[41210]=1,[41211]=1,[61687]=45,[61688]=44,[41214]=1,[61690]=49,[41216]=1,[41217]=1, + [41218]=1,[41219]=1,[41220]=0,[41221]=0,[41222]=0,[61698]=65,[61699]=66,[61700]=66,[61701]=66,[41227]=0,[61703]=65, + [41229]=0,[61705]=65,[41231]=0,[41232]=0,[61708]=65,[61709]=65,[61710]=65,[41236]=0,[41237]=0,[41238]=0,[41239]=0, + [41240]=0,[41241]=0,[61717]=64,[41243]=0,[41244]=0,[41245]=0,[41246]=0,[41247]=0,[61723]=44,[41249]=0,[61725]=43, + [61726]=43,[61727]=43,[41253]=0,[61729]=44,[61730]=44,[41256]=0,[41257]=0,[41258]=0,[61734]=49,[61735]=49,[61736]=49, + [61737]=49,[41263]=0,[41264]=0,[61740]=74,[61751]=1,[61752]=1,[61753]=64,[61754]=64,[61755]=64,[61756]=64,[61757]=64, + [61758]=64,[61762]=51,[61765]=51,[61767]=53,[61773]=1,[70003]=30,[70004]=30,[70005]=30,[70006]=30,[70008]=29, + [70009]=30,[70010]=30,[70011]=30,[70012]=33,[70013]=33,[70014]=30,[20891]=1,[70032]=8,[20893]=1,[70034]=17,[20895]=1, + [20896]=1,[70037]=30,[20898]=1,[20899]=1,[20900]=1,[70045]=30,[70046]=30,[70047]=32,[70048]=32,[70049]=2,[70050]=63, + [70051]=63,[70052]=63,[70053]=63,[70054]=63,[70055]=63,[70056]=63,[70057]=65,[70058]=63,[70059]=63,[70060]=63, + [70062]=63,[70063]=63,[70064]=63,[70070]=23,[12752]=65,[12756]=65,[12757]=65,[62008]=53,[16979]=63,[16980]=66, + [16982]=63,[16983]=63,[16984]=66,[16988]=70,[16989]=66,[12895]=65,[12903]=65,[17013]=70,[17014]=63,[12945]=65, + [12953]=60,[17065]=68,[17066]=67,[17073]=66,[17075]=74,[17078]=72,[17105]=69,[17110]=70,[21325]=58,[4950]=16, + [50024]=49,[50025]=49,[50028]=37,[50029]=0,[50030]=1,[50031]=1,[50032]=0,[50033]=0,[50034]=0,[50035]=0,[50036]=0, + [50037]=0,[50039]=0,[50040]=0,[50041]=0,[50042]=0,[50043]=0,[50046]=0,[50047]=0,[50048]=0,[50049]=0,[50056]=60, + [21392]=74,[13204]=60,[21395]=74,[50061]=0,[50062]=8,[21398]=74,[21401]=74,[21404]=74,[21407]=74,[21410]=74,[21413]=74, + [21416]=74,[50094]=65,[50095]=0,[50096]=0,[50097]=0,[50098]=0,[50099]=0,[50100]=0,[50102]=0,[50103]=0,[50104]=0, + [13284]=58,[50186]=10,[50187]=10,[50188]=65,[50189]=65,[50190]=65,[50191]=65,[50192]=65,[50193]=65,[82954]=25, + [82955]=25,[50236]=0,[50243]=5,[50244]=99,[50245]=99,[50246]=99,[83007]=1,[50248]=99,[83009]=1,[5218]=15,[83025]=0, + [83026]=0,[83027]=0,[83028]=0,[83029]=0,[83030]=0,[83036]=0,[83037]=0,[83038]=0,[83039]=0,[83040]=0,[83041]=0, + [83042]=0,[83043]=0,[83044]=0,[83045]=0,[83046]=0,[83047]=0,[83048]=0,[83049]=0,[83050]=0,[83051]=0,[83052]=0, + [83053]=0,[83054]=0,[83055]=0,[83056]=0,[83060]=62,[83061]=62,[83062]=62,[50303]=0,[50304]=0,[50305]=0,[50306]=0, + [50307]=0,[50308]=0,[83069]=55,[50310]=0,[83071]=55,[83072]=55,[50313]=0,[50314]=0,[50315]=0,[83076]=55,[50317]=0, + [50318]=0,[50319]=0,[50320]=0,[50321]=0,[50322]=0,[50323]=0,[50324]=0,[50325]=0,[50326]=0,[50327]=0,[50328]=0, + [50329]=0,[50330]=0,[50331]=0,[50332]=0,[83093]=63,[83094]=7,[50335]=0,[50336]=0,[50337]=0,[17578]=74,[17579]=71, + [17580]=74,[17581]=74,[50342]=0,[50343]=0,[50344]=0,[50345]=0,[17586]=71,[50347]=0,[17588]=71,[50349]=0,[17590]=74, + [17591]=74,[50352]=0,[13498]=60,[50354]=0,[50355]=0,[50356]=0,[50357]=0,[50358]=0,[50359]=0,[50360]=0,[50361]=0, + [17602]=74,[17603]=71,[17604]=74,[17605]=74,[50366]=0,[17607]=71,[17608]=71,[50369]=0,[50370]=0,[50371]=0,[50372]=0, + [50373]=0,[50374]=0,[5332]=25,[17618]=71,[50379]=0,[17620]=71,[17622]=74,[17623]=74,[17624]=74,[17625]=71,[50392]=0, + [50393]=0,[50394]=0,[50395]=0,[50396]=0,[50397]=0,[50398]=0,[50409]=0,[50410]=0,[50411]=0,[50412]=0,[50413]=0, + [50414]=0,[50415]=0,[50417]=70,[50418]=70,[50420]=0,[50421]=0,[50422]=0,[50423]=0,[50424]=0,[50427]=66,[50428]=66, + [50429]=66,[50430]=66,[50431]=66,[50432]=65,[50433]=0,[50440]=0,[83201]=35,[83202]=35,[83203]=34,[83204]=36,[83205]=36, + [83206]=34,[83207]=36,[83208]=38,[83209]=38,[83210]=38,[83211]=38,[83212]=39,[83213]=39,[83214]=39,[83215]=39, + [83216]=40,[13602]=48,[83218]=40,[83219]=40,[83220]=45,[83221]=40,[83222]=40,[83223]=40,[83224]=40,[9515]=31, + [9516]=31,[83227]=40,[83228]=41,[83229]=40,[83230]=40,[83231]=40,[83232]=40,[83233]=65,[83234]=65,[83237]=65, + [83238]=65,[83239]=65,[83240]=65,[83241]=56,[83242]=56,[83243]=56,[83244]=56,[83250]=43,[83251]=42,[83253]=42, + [83254]=40,[83255]=40,[83256]=25,[83257]=62,[83258]=61,[83259]=61,[50500]=0,[50501]=0,[50502]=0,[50503]=0,[83264]=65, + [50505]=0,[50506]=0,[83267]=62,[83268]=61,[83269]=63,[50512]=0,[83273]=55,[83274]=56,[50515]=0,[50516]=0,[50517]=0, + [50518]=0,[83279]=54,[83280]=47,[83281]=49,[83282]=47,[83283]=46,[50524]=50,[50525]=50,[83286]=42,[50527]=36, + [50528]=36,[50529]=36,[83290]=41,[50531]=36,[83292]=55,[83293]=55,[83294]=53,[83295]=54,[83296]=53,[83297]=54, + [50545]=68,[5522]=36,[50614]=36,[50615]=36,[50616]=36,[50618]=36,[50619]=36,[50620]=36,[50621]=36,[50622]=36, + [50623]=36,[50624]=36,[50625]=36,[50626]=36,[50627]=36,[50628]=36,[50629]=36,[50630]=36,[50631]=36,[83400]=43, + [83401]=42,[83402]=41,[83403]=42,[83404]=40,[83405]=40,[83406]=19,[83407]=22,[83408]=18,[83409]=21,[83410]=48, + [83411]=49,[83412]=50,[83413]=50,[83414]=52,[83415]=50,[83416]=65,[83417]=65,[21994]=60,[83420]=66,[83421]=66, + [83423]=68,[83424]=68,[83425]=68,[83426]=66,[83427]=66,[83428]=66,[83429]=66,[83430]=66,[83431]=68,[22007]=60, + [22008]=60,[83434]=68,[22010]=60,[22011]=60,[22015]=60,[22016]=60,[22017]=60,[83443]=65,[83444]=65,[83445]=65, + [83446]=65,[83447]=65,[83448]=65,[83449]=65,[83450]=65,[83451]=65,[83452]=65,[83453]=65,[83454]=65,[46600]=20, + [83456]=65,[83457]=65,[83458]=65,[83459]=65,[83460]=65,[83461]=65,[83462]=65,[83463]=65,[83464]=65,[83465]=65, + [83466]=65,[83467]=65,[83468]=65,[83469]=65,[83470]=65,[83471]=65,[83472]=65,[83478]=1,[83479]=1,[83480]=75,[83481]=75, + [83482]=75,[83483]=75,[83484]=75,[83485]=75,[83486]=75,[83487]=75,[83488]=75,[83490]=50,[83491]=50,[83492]=50, + [22068]=60,[83494]=47,[83495]=48,[83496]=48,[22072]=60,[22073]=60,[22077]=60,[22078]=60,[50744]=51,[22081]=60, + [22082]=60,[22085]=60,[22086]=60,[22088]=60,[83514]=58,[22090]=60,[22092]=60,[22093]=60,[22095]=60,[22098]=60, + [22099]=60,[22100]=60,[22101]=60,[83530]=75,[83531]=75,[83532]=75,[22108]=60,[22110]=60,[22111]=60,[22112]=60, + [83540]=22,[83541]=22,[83542]=22,[83543]=22,[83562]=68,[83563]=68,[83564]=68,[83565]=68,[18048]=60,[91761]=15, + [91765]=36,[91777]=68,[51008]=0,[51013]=0,[51014]=0,[51015]=0,[51016]=0,[51017]=0,[51018]=0,[51019]=0,[18263]=65, + [51024]=52,[51025]=55,[51030]=0,[51031]=0,[51032]=0,[51033]=0,[51034]=0,[51035]=0,[51036]=0,[51037]=0,[51038]=0, + [51039]=0,[51040]=0,[51041]=0,[51042]=0,[51045]=59,[51046]=59,[51047]=59,[51048]=59,[51050]=0,[51051]=0,[51052]=0, + [51061]=0,[51062]=0,[51219]=8,[51224]=10,[84000]=73,[84001]=83,[84002]=83,[84003]=83,[84004]=83,[84005]=83,[84006]=0, + [51256]=15,[84017]=1,[51264]=15,[84030]=88,[84031]=88,[84032]=88,[84033]=88,[84034]=88,[84035]=88,[84036]=88, + [84037]=24,[84039]=50,[51284]=15,[51300]=50,[51301]=0,[22656]=63,[22657]=63,[22659]=63,[51332]=8,[22668]=63,[22678]=63, + [10400]=21,[10401]=21,[10402]=21,[10413]=21,[51400]=10,[51401]=10,[51403]=15,[80101]=4,[80102]=4,[80105]=6,[80106]=6, + [80107]=6,[80108]=9,[80109]=9,[80110]=9,[80111]=9,[80113]=9,[80115]=9,[80116]=9,[80117]=9,[80118]=9,[80120]=10, + [80121]=10,[80122]=10,[80123]=10,[80124]=10,[80125]=10,[80126]=11,[80127]=11,[80128]=11,[80129]=11,[80131]=11, + [80132]=11,[22803]=83,[22806]=83,[22809]=86,[22810]=83,[22811]=86,[22813]=83,[22815]=83,[80175]=0,[80180]=0,[80181]=0, + [80182]=0,[80183]=0,[80184]=0,[80185]=0,[80186]=0,[80202]=4,[80203]=4,[80204]=9,[80205]=9,[80206]=6,[80207]=6, + [80208]=6,[80211]=9,[80212]=9,[80213]=9,[80214]=9,[80215]=9,[80217]=9,[80218]=9,[80219]=10,[80220]=10,[80221]=0, + [80222]=20,[80223]=23,[41265]=0,[41262]=0,[41261]=0,[41260]=0,[41259]=0,[41255]=0,[41254]=0,[41252]=0,[41251]=0, + [80234]=3,[41250]=0,[41248]=0,[41242]=0,[41235]=0,[41234]=0,[41233]=0,[41230]=0,[41228]=0,[41226]=0,[41225]=0, + [41224]=0,[41223]=0,[41215]=1,[41213]=1,[41212]=1,[41204]=10,[69165]=1,[69164]=1,[69163]=1,[69162]=1,[60294]=47, + [69160]=1,[81276]=1,[81272]=35,[81271]=35,[81270]=37,[50316]=0,[80767]=63,[80766]=63,[80765]=63,[50333]=0,[69150]=1, + [80761]=63,[80758]=61,[80754]=51,[80753]=52,[50059]=0,[22942]=83,[81218]=60,[69143]=1,[69142]=1,[69141]=1,[69140]=1, + [81214]=25,[50507]=0,[69137]=1,[69136]=1,[50504]=0,[69134]=1,[69133]=1,[69132]=1,[69131]=1,[69130]=1,[69129]=1, + [69128]=1,[7510]=20,[69126]=1,[69125]=1,[69124]=1,[69123]=1,[69122]=1,[69121]=1,[69120]=1,[69119]=1,[69118]=1, + [69117]=1,[69116]=1,[69115]=1,[69114]=1,[81199]=50,[41195]=13,[41194]=13,[41193]=13,[41192]=13,[41187]=12,[41186]=12, + [41185]=12,[41159]=8,[41158]=8,[41157]=8,[41155]=8,[41154]=8,[41153]=8,[41152]=8,[41150]=22,[41149]=22,[41148]=22, + [41128]=56,[41127]=56,[41126]=56,[41125]=56,[41117]=5,[41116]=5,[41115]=5,[41114]=5,[41113]=5,[41112]=5,[41111]=5, + [41110]=5,[41109]=5,[41108]=5,[41107]=5,[41106]=5,[41105]=5,[41104]=5,[41103]=5,[41136]=15,[41135]=15,[41134]=15, + [23014]=83,[2540]=62,[2541]=62,[41102]=10,[2543]=60,[41101]=10,[41100]=10,[41099]=10,[41098]=10,[41097]=10,[41096]=10, + [41095]=10,[41094]=10,[41093]=10,[41091]=10,[41092]=10,[41090]=10,[41089]=10,[41088]=10,[41087]=10,[41080]=10, + [41079]=10,[41078]=10,[41077]=88,[41076]=78,[41075]=12,[41074]=12,[41070]=12,[41063]=61,[41062]=61,[23044]=78, + [41061]=61,[41060]=61,[41056]=13,[41055]=13,[41054]=13,[41051]=12,[41050]=12,[41049]=10,[41048]=10,[51719]=25, + [41047]=10,[41046]=10,[41045]=12,[41044]=1,[41043]=10,[41042]=10,[41041]=10,[41040]=10,[41035]=8,[41034]=8,[51730]=75, + [51731]=75,[51732]=75,[51733]=75,[23069]=78,[80400]=15,[51736]=75,[51737]=75,[51738]=75,[40080]=55,[51740]=75, + [51741]=62,[51742]=62,[51743]=62,[51744]=62,[51745]=62,[51746]=62,[51747]=62,[51748]=62,[51749]=62,[41029]=5, + [41026]=5,[51752]=39,[51753]=65,[51754]=28,[51755]=51,[51756]=51,[51757]=51,[51758]=42,[51759]=42,[51760]=42, + [51761]=42,[51762]=49,[51763]=49,[51764]=53,[51765]=53,[51766]=49,[51767]=49,[51768]=49,[51769]=66,[51770]=66, + [51771]=66,[51772]=66,[10823]=44,[51774]=66,[51775]=66,[51776]=66,[51777]=66,[51778]=66,[51779]=66,[51780]=66, + [51781]=66,[51782]=66,[51783]=66,[51784]=66,[51785]=66,[51786]=66,[51787]=66,[51788]=66,[51789]=66,[51790]=30, + [51791]=31,[51792]=19,[51793]=52,[51794]=52,[51795]=25,[51796]=66,[51797]=66,[51798]=66,[51799]=66,[51800]=66, + [41025]=5,[51802]=51,[59993]=12,[51804]=44,[51805]=29,[41024]=5,[41023]=5,[41018]=5,[41017]=5,[51810]=13,[41014]=5, + [51812]=17,[60003]=84,[60004]=68,[60005]=68,[51816]=7,[51817]=9,[51818]=14,[51819]=15,[51820]=7,[41013]=5,[41011]=44, + [61816]=68,[51824]=15,[51825]=14,[84604]=65,[51827]=5,[51828]=10,[51829]=6,[84603]=68,[84602]=68,[51832]=32,[51833]=32, + [51834]=32,[80500]=16,[80501]=16,[80502]=16,[80503]=16,[80504]=36,[51840]=60,[80506]=65,[51842]=41,[80508]=65, + [51844]=41,[80510]=65,[80511]=65,[80512]=65,[80513]=65,[80514]=65,[51850]=23,[51851]=23,[80517]=65,[80518]=65, + [80519]=65,[51855]=0,[51856]=10,[80522]=65,[80523]=65,[80524]=65,[80525]=65,[51861]=0,[51862]=20,[80528]=65,[51864]=44, + [51865]=44,[80531]=65,[80532]=65,[80533]=65,[80534]=65,[80535]=65,[80536]=65,[80537]=65,[80538]=65,[80539]=65, + [51875]=5,[51876]=5,[51877]=5,[80543]=65,[80544]=65,[80545]=65,[80546]=65,[51882]=9,[84601]=68,[84600]=65,[51885]=9, + [51886]=9,[51887]=5,[51888]=5,[60010]=66,[60009]=66,[23226]=78,[51892]=59,[60008]=66,[60007]=66,[60006]=68,[51896]=47, + [51897]=47,[50247]=99,[84507]=60,[51900]=1,[84509]=71,[23237]=78,[23238]=78,[84506]=72,[84505]=71,[84504]=72, + [84503]=72,[84502]=72,[60099]=40,[84501]=71,[84500]=72,[7512]=31,[65038]=70,[65037]=70,[65036]=70,[7511]=31,[61623]=43, + [61622]=50,[61619]=45,[61616]=45,[61614]=58,[60112]=27,[61613]=58,[61612]=46,[61611]=46,[60116]=57,[60117]=58, + [60118]=57,[61610]=46,[61609]=43,[15076]=58,[15077]=55,[15078]=60,[60124]=35,[80600]=16,[60126]=53,[80602]=16, + [80603]=16,[60129]=43,[80605]=35,[80606]=65,[80607]=65,[80608]=65,[80609]=65,[80610]=65,[80611]=65,[80612]=65, + [80613]=65,[80614]=65,[80615]=65,[80616]=65,[80617]=65,[80618]=65,[80619]=65,[80620]=65,[80621]=65,[80622]=65, + [80623]=65,[80624]=65,[80625]=65,[80626]=65,[80627]=50,[80628]=65,[80629]=65,[80630]=65,[80631]=65,[80632]=65, + [80633]=65,[80634]=65,[80635]=65,[80636]=65,[80637]=65,[80638]=65,[80639]=65,[80640]=65,[80641]=65,[80642]=65, + [80643]=65,[80644]=65,[80645]=65,[80646]=65,[61608]=43,[60173]=25,[80649]=37,[60175]=25,[61605]=45,[61603]=46, + [61597]=48,[60179]=36,[23325]=1,[60181]=40,[60182]=40,[60183]=40,[61596]=47,[61588]=57,[61587]=57,[60187]=57, + [61586]=57,[61585]=46,[61584]=46,[61583]=46,[61582]=42,[61581]=42,[61580]=42,[80670]=53,[80671]=53,[80672]=54, + [60198]=25,[60199]=25,[60200]=25,[60201]=25,[61579]=47,[61578]=47,[61577]=47,[61576]=42,[61575]=42,[61589]=42, + [61574]=45,[60209]=59,[60210]=59,[60211]=59,[61573]=45,[60213]=40,[60214]=40,[60215]=40,[60216]=40,[61572]=45, + [61571]=64,[61569]=64,[60220]=59,[60221]=58,[61568]=63,[60223]=57,[60224]=58,[80700]=18,[80701]=18,[80702]=18, + [60228]=58,[60229]=58,[80705]=18,[80706]=21,[80707]=22,[80708]=23,[60234]=59,[80710]=20,[80711]=23,[80712]=23, + [80713]=23,[80714]=23,[80715]=26,[80716]=28,[80717]=27,[80718]=25,[80719]=28,[80720]=28,[80721]=28,[80722]=28, + [80723]=28,[80724]=30,[80725]=30,[80726]=30,[80727]=30,[80728]=30,[80729]=28,[80730]=20,[80731]=30,[80732]=34, + [60258]=48,[80734]=34,[80735]=34,[80736]=34,[80737]=34,[80738]=34,[80739]=20,[80740]=34,[80741]=34,[80742]=34, + [80743]=35,[80744]=39,[80745]=42,[80746]=45,[80747]=48,[80748]=52,[60274]=59,[60275]=59,[80751]=50,[80752]=52, + [60278]=16,[60279]=20,[80755]=54,[80756]=51,[61567]=64,[60283]=47,[80759]=60,[60285]=45,[60286]=46,[60287]=62, + [60288]=63,[60289]=63,[60290]=63,[60291]=63,[60292]=63,[60293]=63,[80769]=63,[80770]=63,[80771]=63,[80772]=63, + [80773]=63,[80774]=63,[80775]=63,[80776]=63,[80777]=63,[80778]=31,[80779]=63,[80780]=63,[80781]=63,[60307]=40, + [80783]=63,[80784]=36,[80785]=40,[80786]=43,[80787]=43,[61566]=64,[80789]=30,[80790]=38,[60316]=47,[60317]=45, + [60318]=45,[80794]=34,[80795]=56,[80796]=30,[80797]=40,[80798]=30,[80799]=41,[61565]=63,[80801]=47,[80802]=22, + [80803]=22,[80804]=35,[80805]=49,[80806]=41,[80807]=23,[60333]=62,[80809]=34,[80810]=46,[80811]=21,[80812]=51, + [80813]=10,[60339]=15,[61595]=63,[80816]=13,[80817]=13,[80818]=13,[80819]=13,[80820]=13,[80821]=13,[80822]=40, + [60348]=59,[80824]=47,[60350]=66,[60351]=66,[60352]=68,[60353]=68,[60354]=68,[60355]=66,[60356]=66,[80832]=33, + [60358]=66,[60359]=66,[60360]=68,[60361]=68,[60362]=68,[80838]=37,[80839]=40,[80840]=39,[60366]=65,[60367]=65, + [80843]=61,[80844]=61,[80845]=50,[60371]=24,[80847]=50,[80848]=50,[80849]=61,[80850]=61,[80851]=61,[80852]=61, + [80853]=61,[80854]=61,[60380]=25,[61594]=63,[61550]=62,[60383]=65,[60384]=65,[60385]=65,[60386]=65,[60387]=65, + [60388]=65,[60389]=66,[60390]=66,[61532]=57,[60392]=25,[60393]=25,[60394]=61,[60395]=61,[61531]=57,[61530]=56, + [61529]=56,[61528]=56,[60400]=57,[80876]=2,[61527]=81,[61489]=45,[61487]=44,[60405]=57,[60406]=57,[60407]=57, + [60408]=65,[60409]=63,[60410]=65,[23556]=1,[60412]=65,[60413]=65,[60414]=65,[60415]=65,[60416]=65,[60417]=63, + [60418]=65,[60419]=65,[60420]=65,[60421]=65,[60422]=65,[60423]=65,[60424]=65,[60425]=65,[60426]=65,[11287]=15, + [11288]=23,[60429]=65,[60430]=65,[60431]=65,[60432]=65,[60433]=65,[60434]=65,[60435]=63,[60436]=63,[60437]=65, + [60438]=50,[60439]=50,[60440]=50,[60441]=50,[60442]=50,[61486]=44,[61513]=48,[61512]=48,[61511]=58,[61510]=58, + [61508]=37,[61507]=37,[61453]=72,[60451]=59,[60452]=59,[60453]=59,[61452]=68,[61451]=68,[81019]=61,[81056]=62, + [50367]=0,[60459]=65,[60460]=65,[60461]=65,[50378]=0,[60463]=65,[60464]=65,[60465]=15,[60379]=25,[60369]=24,[50338]=0, + [81055]=62,[60470]=50,[81140]=1,[81021]=23,[81095]=1,[81020]=23,[60475]=42,[81051]=62,[50363]=0,[40003]=65,[81052]=62, + [60480]=42,[60481]=42,[81125]=61,[50341]=0,[17592]=74,[50368]=0,[60486]=65,[60487]=65,[60488]=65,[60489]=65,[60490]=65, + [81114]=0,[60492]=21,[60493]=21,[81050]=62,[60495]=10,[60277]=16,[60497]=65,[60498]=65,[60499]=65,[60500]=65, + [60501]=65,[60502]=65,[60503]=65,[60504]=65,[60505]=65,[60506]=65,[60338]=15,[50340]=0,[50362]=0,[50339]=0,[81053]=62, + [81054]=62,[50353]=0,[50364]=0,[81131]=62,[60370]=24,[81057]=62,[23663]=80,[23664]=80,[23665]=80,[23666]=80,[23667]=80, + [23668]=80,[60524]=13,[60525]=39,[50365]=0,[60527]=47,[60528]=47,[60529]=47,[60530]=47,[60531]=47,[81007]=21, + [81111]=0,[81123]=61,[60368]=65,[60536]=57,[81122]=61,[81124]=62,[60539]=56,[40065]=20,[60541]=56,[60542]=56, + [60543]=56,[60544]=56,[60545]=56,[60546]=64,[60547]=60,[60548]=59,[60549]=59,[60550]=59,[60551]=59,[60552]=54, + [60553]=54,[60554]=54,[60555]=64,[60556]=65,[60557]=63,[60558]=62,[60559]=57,[60560]=57,[60561]=57,[60562]=57, + [60563]=57,[60564]=57,[60565]=56,[60566]=56,[60567]=56,[60568]=56,[60569]=56,[36000]=0,[36001]=0,[60572]=54,[60573]=58, + [60574]=58,[60575]=58,[60576]=55,[60577]=57,[36008]=0,[36009]=0,[36010]=0,[36011]=0,[60582]=54,[36013]=0,[36014]=0, + [81060]=66,[81061]=54,[60587]=35,[81063]=55,[81064]=56,[60590]=44,[81066]=57,[20628]=76,[65100]=76,[80133]=11, + [60746]=30,[60596]=42,[60745]=12,[65026]=66,[65015]=58,[65024]=66,[60601]=45,[51734]=75,[51837]=1,[51841]=1,[81080]=20, + [51843]=41,[51849]=23,[60608]=58,[60609]=58,[60610]=58,[60611]=54,[60612]=54,[60613]=54,[60614]=54,[60615]=54, + [60616]=54,[60617]=54,[60618]=54,[80516]=65,[60620]=1,[80521]=65,[60622]=65,[80529]=65,[60624]=65,[60625]=65, + [60626]=65,[80530]=65,[23221]=78,[60629]=58,[51880]=5,[60631]=58,[60632]=58,[80547]=65,[60591]=44,[81110]=27, + [60636]=57,[81112]=0,[81113]=27,[60639]=57,[81115]=0,[1187]=30,[50300]=0,[50301]=0,[50302]=0,[50311]=0,[60646]=63, + [60647]=63,[60648]=63,[60649]=63,[60650]=10,[50312]=0,[50346]=0,[50348]=0,[60654]=15,[50350]=0,[60656]=36,[60657]=40, + [50351]=0,[60659]=40,[50377]=0,[60581]=63,[60580]=64,[60579]=65,[60540]=56,[60665]=58,[60666]=58,[60667]=58,[60668]=58, + [80601]=16,[80604]=36,[60180]=40,[60672]=58,[60673]=57,[60571]=54,[60675]=58,[81222]=54,[81223]=64,[60678]=18, + [60679]=18,[80674]=53,[23379]=58,[80703]=18,[80704]=18,[60684]=20,[60685]=20,[60686]=20,[80709]=21,[80733]=34, + [80749]=53,[60690]=25,[60691]=25,[60692]=25,[80750]=52,[60694]=60,[60695]=60,[60696]=60,[80760]=61,[80763]=63, + [60699]=58,[60700]=59,[60701]=59,[50060]=0,[81500]=68,[80782]=63,[80791]=34,[80792]=43,[50309]=0,[10824]=44,[80825]=47, + [80826]=47,[80828]=32,[80829]=33,[80831]=33,[80836]=35,[60715]=63,[80837]=37,[60717]=60,[60718]=60,[60719]=60, + [80841]=61,[80842]=61,[80846]=50,[80860]=24,[60724]=70,[60725]=70,[60726]=65,[60727]=65,[60728]=65,[60729]=65, + [60730]=65,[80861]=24,[60272]=42,[81025]=10,[60734]=62,[60735]=62,[81211]=29,[81212]=30,[81213]=34,[60739]=63, + [81215]=35,[81216]=30,[81217]=30,[60743]=61,[7509]=20,[81220]=46,[81221]=60,[60747]=30,[60748]=30,[60749]=30, + [60750]=30,[60751]=30,[60752]=45,[81024]=10,[40061]=60,[60755]=13,[60411]=65,[60757]=13,[60427]=65,[60759]=52, + [60428]=63,[82950]=63,[60762]=48,[82951]=63,[60764]=54,[60765]=54,[60766]=54,[82952]=63,[82953]=63,[81062]=56, + [65000]=59,[60771]=58,[60772]=58,[60773]=58,[60774]=58,[65002]=59,[65004]=68,[65012]=25,[65011]=18,[65010]=10, + [65005]=50,[65003]=66,[60782]=61,[60783]=41,[60784]=58,[81260]=65,[81261]=65,[60787]=47,[60788]=41,[60789]=43, + [60790]=65,[60791]=65,[60792]=65,[60793]=65,[60794]=65,[60795]=65,[60796]=63,[60797]=63,[60798]=63,[60799]=63, + [60800]=63,[60801]=63,[60802]=63,[60803]=63,[60804]=63,[60805]=63,[60806]=63,[60807]=63,[60808]=63,[60809]=63, + [60268]=59,[60518]=45,[60522]=13,[81288]=63,[60523]=13,[81290]=33,[81003]=68,[81004]=68,[60818]=47,[60819]=47, + [60820]=47,[60821]=47,[81005]=25,[15778]=58,[81006]=27,[81014]=46,[60826]=25,[60827]=25,[60828]=25,[81304]=0, + [81305]=35,[81306]=35,[81307]=26,[81308]=28,[81309]=36,[60835]=51,[81311]=30,[60837]=50,[81015]=46,[15794]=2, + [81016]=61,[81316]=23,[81317]=23,[60843]=25,[60844]=25,[60845]=25,[81321]=49,[60847]=51,[81017]=61,[81018]=61, + [81325]=53,[80509]=65,[16535]=74,[60853]=42,[60854]=42,[60855]=42,[17583]=71,[50514]=0,[17584]=71,[60859]=42, + [60860]=42,[13182]=57,[16534]=71,[60863]=24,[60864]=24,[60865]=24,[81341]=29,[81342]=43,[51023]=55,[60364]=66, + [60363]=66,[83217]=40,[60872]=26,[60873]=25,[83225]=40,[81350]=47,[60876]=25,[81352]=52,[81353]=52,[60879]=43, + [60880]=43,[60881]=43,[60882]=53,[60883]=53,[60884]=53,[60885]=53,[81361]=61,[60887]=40,[60888]=40,[60889]=40, + [81365]=64,[81366]=64,[81367]=64,[81368]=64,[81369]=64,[81370]=58,[60896]=44,[81372]=58,[81373]=58,[60899]=43, + [60900]=43,[60901]=43,[60902]=53,[60903]=53,[60904]=53,[60905]=53,[65001]=61,[60907]=65,[60908]=65,[60909]=65, + [60910]=65,[65006]=66,[65007]=53,[65008]=66,[65009]=41,[60915]=25,[60916]=25,[60917]=25,[65013]=36,[65014]=63, + [60920]=36,[60921]=36,[83226]=40,[69113]=1,[65019]=49,[60925]=25,[65021]=68,[60927]=46,[60928]=44,[60929]=44, + [65025]=66,[60931]=25,[65027]=66,[60933]=25,[60934]=25,[65030]=35,[81411]=34,[69127]=1,[60938]=25,[60939]=25, + [65035]=70,[81416]=30,[81417]=30,[81418]=30,[65039]=70,[69135]=1,[60946]=46,[60947]=46,[69138]=1,[69139]=1,[60950]=47, + [60951]=47,[60952]=47,[60953]=47,[69144]=1,[69145]=1,[69146]=1,[69147]=1,[69148]=1,[69149]=1,[60960]=58,[69151]=1, + [69152]=1,[69153]=1,[69154]=1,[69155]=1,[69156]=1,[69157]=1,[69158]=1,[69159]=1,[60970]=58,[69161]=1,[60972]=58, + [60973]=58,[60974]=58,[60975]=58,[60300]=60,[60308]=40,[60309]=40,[81294]=15,[81295]=15,[81310]=35,[60982]=45, + [81339]=51,[81364]=61,[60985]=10,[81363]=61,[21996]=60,[60988]=55,[81360]=61,[21998]=60,[22004]=60,[22006]=60, + [81375]=63,[81376]=63,[81319]=36,[60996]=62,[60997]=62,[81320]=36,[81328]=55,[24145]=1,[61001]=68,[61002]=68, + [61003]=65,[61004]=65,[61005]=65,[65101]=76,[61007]=65,[65103]=76,[65104]=76,[65105]=76,[61011]=65,[61012]=65, + [61013]=68,[61014]=65,[61015]=66,[61016]=66,[61017]=66,[61018]=66,[61019]=66,[61020]=66,[61021]=66,[61022]=65, + [61023]=66,[61024]=66,[61025]=66,[81501]=68,[81502]=68,[81503]=68,[61029]=66,[61030]=66,[61031]=66,[61032]=66, + [61033]=66,[61034]=66,[61035]=66,[61036]=66,[61037]=66,[61038]=66,[61039]=66,[61040]=66,[61041]=66,[61042]=66, + [61043]=66,[61044]=66,[61045]=66,[61046]=66,[61047]=66,[61048]=66,[61049]=65,[61050]=66,[61051]=66,[61052]=65, + [61053]=66,[61054]=66,[61055]=66,[61056]=65,[61057]=66,[61058]=66,[61059]=66,[61060]=66,[61061]=66,[61062]=66, + [61063]=66,[61064]=59,[61065]=57,[81329]=55,[81330]=55,[61068]=65,[61069]=59,[61070]=59,[81357]=31,[81371]=58, + [81374]=58,[61074]=60,[81378]=63,[61076]=60,[61077]=60,[81379]=62,[61079]=60,[61080]=60,[81380]=52,[61082]=60, + [22066]=60,[22067]=60,[22070]=60,[61086]=60,[61087]=60,[61088]=60,[22071]=60,[36002]=0,[61091]=62,[61092]=62, + [36003]=0,[36004]=0,[61095]=60,[36005]=0,[36006]=0,[36007]=0,[22106]=60,[61100]=25,[83517]=16,[61006]=65,[65102]=76, + [36012]=0,[36015]=0,[36016]=0,[36017]=44,[36018]=44,[36019]=45,[60131]=45,[60132]=42,[60138]=57,[60152]=59,[60153]=59, + [83063]=62,[83064]=35,[83065]=55,[83066]=55,[83067]=55,[83068]=55,[83070]=55,[83073]=55,[83074]=55,[83075]=55, + [83077]=55,[83078]=55,[83079]=62,[83080]=62,[83081]=30,[83082]=45,[60161]=59,[60164]=59,[60165]=60,[83200]=36, + [81167]=63,[83260]=61,[83261]=66,[83262]=65,[83263]=65,[83265]=62,[60169]=43,[83266]=62,[83276]=54,[83277]=54, + [83289]=40,[60237]=57,[60233]=59,[60239]=57,[61028]=66,[61027]=66,[61010]=65,[61009]=65,[61153]=1,[61154]=30, + [61155]=32,[61156]=32,[83515]=58,[83513]=58,[24146]=1,[60269]=59,[83493]=50,[22079]=60,[61163]=34,[61164]=34, + [61165]=34,[61166]=34,[60284]=47,[22063]=60,[22062]=60,[83455]=65,[81402]=31,[83442]=65,[83441]=65,[83440]=65, + [60334]=62,[83436]=68,[83435]=68,[83433]=68,[83432]=68,[81384]=54,[81383]=52,[81382]=52,[81381]=52,[81377]=62, + [61185]=65,[61186]=65,[61187]=65,[61188]=65,[22002]=60,[22001]=60,[22000]=60,[81362]=61,[61193]=76,[61194]=76, + [61195]=76,[81356]=44,[81355]=58,[81354]=30,[81351]=56,[81065]=54,[60346]=59,[60347]=59,[61203]=78,[61204]=78, + [61205]=78,[61206]=78,[61207]=78,[61208]=78,[61209]=78,[61210]=78,[61211]=78,[61212]=78,[61213]=78,[61214]=78, + [81269]=37,[81268]=29,[81267]=29,[81266]=29,[81265]=65,[81264]=65,[81263]=65,[81262]=65,[81257]=30,[60786]=40, + [60785]=44,[60357]=66,[83291]=41,[3456]=30,[83288]=40,[83287]=43,[83285]=46,[83284]=46,[83278]=54,[83275]=54, + [50519]=0,[81219]=56,[61237]=78,[61238]=78,[61239]=78,[61240]=5,[61241]=5,[61242]=1,[61243]=66,[61244]=68,[61245]=68, + [61246]=66,[61247]=68,[61248]=66,[61249]=66,[61250]=68,[61251]=66,[61252]=68,[61253]=66,[61254]=68,[61255]=68, + [61256]=71,[61257]=72,[60365]=66,[61259]=44,[61260]=66,[61261]=68,[61262]=66,[61263]=68,[61264]=71,[61265]=72, + [61266]=66,[61267]=68,[61268]=66,[61269]=68,[61270]=66,[61271]=68,[61272]=68,[61273]=66,[61274]=68,[61275]=72, + [61276]=60,[61277]=71,[61278]=68,[61279]=68,[61280]=68,[61281]=66,[61282]=68,[61283]=68,[61284]=72,[61285]=68, + [61286]=68,[61287]=68,[61288]=68,[61289]=68,[61290]=68,[61291]=66,[61292]=66,[61293]=66,[61294]=68,[61295]=68, + [50334]=0,[61297]=68,[61298]=68,[61299]=72,[61300]=46,[61301]=46,[61302]=46,[61303]=46,[61304]=46,[61305]=46, + [61306]=46,[61307]=46,[61308]=48,[61309]=48,[61310]=48,[61311]=48,[61312]=48,[61313]=49,[61314]=49,[61315]=49, + [61316]=49,[61317]=49,[61318]=49,[61319]=49,[61320]=49,[61321]=49,[61322]=49,[61323]=51,[61324]=51,[61325]=51, + [61326]=51,[61327]=51,[61328]=51,[61329]=51,[61330]=48,[61331]=48,[61332]=48,[61333]=48,[61334]=48,[61335]=47, + [61336]=48,[61337]=47,[61338]=47,[61339]=47,[80835]=35,[80834]=33,[80833]=33,[61343]=40,[80830]=33,[61345]=40, + [61346]=40,[80827]=32,[61348]=47,[61349]=47,[80823]=40,[80814]=9,[80793]=63,[61353]=47,[61354]=47,[61355]=47, + [61356]=76,[61357]=66,[61358]=66,[61359]=66,[61360]=76,[61361]=66,[61362]=66,[61363]=66,[61364]=76,[61365]=66, + [61366]=66,[61367]=66,[80673]=53,[60570]=56,[61370]=10,[61371]=10,[61372]=10,[61373]=10,[61374]=10,[61375]=10, + [61376]=45,[61377]=47,[61378]=45,[61379]=47,[80541]=65,[80540]=65,[51881]=9,[61383]=37,[61384]=37,[61385]=37, + [61386]=14,[80527]=50,[80526]=65,[61389]=13,[80520]=65,[61391]=44,[80515]=65,[61393]=30,[51848]=24,[80505]=35, + [61396]=13,[2714]=8,[61398]=13,[61399]=13,[59994]=11,[51803]=47,[51773]=66,[51735]=75,[61404]=15,[61405]=15,[61406]=51, + [60736]=62,[60742]=61,[65028]=20,[61410]=62,[61411]=62,[20635]=76,[20634]=76,[70036]=30,[70033]=17,[60578]=55, + [65022]=49,[65023]=47,[61419]=42,[61420]=42,[20631]=76,[61422]=45,[22667]=63,[80542]=65,[80507]=65, +} + +-- Merge Turtle WoW custom items into main database +for item, level in pairs(RelationshipsDashboardDB_TurtleItems) do RelationshipsDashboardDB_ItemLevels[item] = level end diff --git a/RelationshipsDashboard.lua b/RelationshipsDashboard.lua new file mode 100644 index 0000000..e96ee7a --- /dev/null +++ b/RelationshipsDashboard.lua @@ -0,0 +1,4249 @@ +------------------------------------------------------------------------------- +-- RelationshipsDashboard - Character Stats, GearScore & Repair Cost for Turtle WoW / OctoWoW +-- Compatible with WoW 1.12.1 (Interface 11200) / Lua 5.0 +-- By NinjaTech +------------------------------------------------------------------------------- + +-- Constants +local RELATIONSHIPS_DASHBOARD_VERSION = "1.0.0"; + +-- Current unit being displayed. Defaults to "player"; switched to "target" +-- when the InspectFrame opens on another player. +RD_UNIT = "player"; + +-- Equipment slot IDs (vanilla 1.12) +local EQUIPMENT_SLOTS = { + 1, -- HeadSlot + 2, -- NeckSlot + 3, -- ShoulderSlot + 5, -- ChestSlot + 6, -- WaistSlot + 7, -- LegsSlot + 8, -- FeetSlot + 9, -- WristSlot + 10, -- HandsSlot + 11, -- Finger0Slot + 12, -- Finger1Slot + 13, -- Trinket0Slot + 14, -- Trinket1Slot + 15, -- BackSlot + 16, -- MainHandSlot + 17, -- OffHandSlot + 18, -- RangedSlot +}; + +-- Slot names for display +local SLOT_NAMES = { + [1] = "Head", + [2] = "Neck", + [3] = "Shoulder", + [5] = "Chest", + [6] = "Waist", + [7] = "Legs", + [8] = "Feet", + [9] = "Wrist", + [10] = "Hands", + [11] = "Ring 1", + [12] = "Ring 2", + [13] = "Trinket 1", + [14] = "Trinket 2", + [15] = "Back", + [16] = "Main Hand", + [17] = "Off Hand", + [18] = "Ranged", +}; + +-- Note: The GearScore formula (rarity * itemLevel) does not use slot weights or quality multipliers. +-- These constants are kept for potential future use in advanced scoring modes. +-- Current GearScore formula: score = rarity * itemLevel * (twoHand ? 2 : 1) + +-- Resistance indices in vanilla WoW +-- 1=Holy, 2=Fire, 3=Nature, 4=Frost, 5=Shadow, 6=Arcane +local RESISTANCE_INDICES = { + arcane = 6, + fire = 2, + nature = 3, + frost = 4, + shadow = 5, +}; + +-- School indices for spell crit/hit (vanilla 1.12) +-- 1=Physical, 2=Holy, 3=Fire, 4=Nature, 5=Frost, 6=Shadow, 7=Arcane +local SPELL_SCHOOL_INDEX = 6; -- Use Arcane as representative for generic spell stats + +-- Tooltip scanner for item info +local RelationshipsDashboardTooltip = nil; + +------------------------------------------------------------------------------- +-- Durability persistence system: Tracks durability loss from deaths, combat +-- hits, and repair events. When GetInventoryItemDurability() fails (which is +-- common on Turtle WoW / OctoWoW outside repair NPCs), we use these stored +-- estimates as a fallback so the dashboard always shows meaningful values. +-- +-- How it works: +-- 1. On PLAYER_ENTERING_WORLD and after each update, try to read actual +-- durability via GetInventoryItemDurability or tooltip scanning. +-- 2. When actual values are available, store them in RD_SavedDurability. +-- 3. When a player dies (PLAYER_DEAD), reduce all items' estimated +-- durability by 10% (standard WoW death penalty = 10% of max dur). +-- 4. While in combat, increment hit counters. On UNIT_HEALTH damage taken, +-- apply small durability decay proportional to hits received. +-- 5. At repair NPCs, use GetRepairAllCost() as exact ground truth. +-- 6. When displaying, use actual if available, else use saved estimates. +------------------------------------------------------------------------------- +-- NOTE: RD_SavedDurability is intentionally GLOBAL (no `local`) so that it +-- can be persisted through the SavedVariable RelationshipsDashboardDB_SavedDurability +-- across /reload and sessions. Rebound in OnLoad after saved vars load. +RD_SavedDurability = {}; -- [slotId] = { cur = X, max = Y } +local RD_InCombat = false; +local RD_CombatHitCount = 0; +local RD_LastHealth = 0; +local RD_InBattleground = false; -- True while in a BG (no durability loss in BGs) +local RD_InDuel = false; -- True during a duel (no durability loss in duels) + +-- Track ghost state so we can detect spirit-healer resurrection +-- (25% durability loss to all equipped + inventory items). +RD_WasGhost = false; +RD_PendingSpiritRez = false; +RD_LastMoney = 0; -- Track for detecting non-merchant repair (e.g. guild bank repair) +-- True while a repair-CAPABLE merchant window is open. Used to decide when a +-- durability reading of "full" can be trusted (see CalculateDurabilityAndRepair). +RD_AtRepairMerchant = false; +-- Per-character multiplier that scales our away-from-merchant repair estimate so +-- it matches the exact cost the game charges. Learned automatically the first +-- time the player opens a repair merchant with damaged gear. Persisted in +-- RelationshipsDashboardDB.repairCalibration. +RD_RepairCalibration = 1.0; +local RD_REPAIR_CALIBRATION_VERSION = 2; + +-- Battleground zone names for vanilla WoW 1.12 (English only — these match GetRealZoneText()) +local RD_BATTLEGROUND_ZONES = { + -- Blizzard vanilla battlegrounds + ["Alterac Valley"] = true, + ["Warsong Gulch"] = true, + ["Arathi Basin"] = true, + -- Turtle WoW / OctoWoW custom or renamed battlegrounds + ["Gurubashi Arena"] = true, + ["Silithus"] = false, -- world PvP zone, NOT a real BG; do not skip durability here + ["Warsong Battleground"] = true, + ["Sunnyglade Valley"] = true, -- Turtle WoW custom BG + ["Blackrock Depths (Arena)"] = true, + ["Lower Blackrock Spire"] = false, -- not a BG (guard against false positives) +}; + +-- Extra localized BG names Turtle/OctoWoW clients ship with. Kept separate +-- so the vanilla table above stays authoritative; both are consulted. +local RD_BATTLEGROUND_ZONES_EXTRA = { + -- German + ["Alteractal"] = true, + ["Kriegshymnenschlucht"] = true, + ["Arathibecken"] = true, + -- French + ["Vallee d'Alterac"] = true, + ["Vall\195\169e d'Alterac"] = true, + ["Goulet des Chanteguerres"] = true, + ["Bassin d'Arathi"] = true, + -- Spanish / Portuguese + ["Valle de Alterac"] = true, + ["Garganta Grito de Guerra"] = true, + ["Cuenca de Arathi"] = true, + -- Russian + [chr and chr(1040) or "\208\144"] = false, -- placeholder, real names below + ["\208\144\208\187\209\140\209\130\208\181\209\128\208\176\208\186\209\129\208\186\208\176\209\143 \208\180\208\190\208\187\208\184\208\189\208\176"] = true, +}; + +-- Slots that can have durability (armor + weapons, NOT accessories) +local RD_DURABILITY_SLOTS = { + [1] = true, -- HeadSlot + [3] = true, -- ShoulderSlot + [5] = true, -- ChestSlot + [7] = true, -- LegsSlot + [8] = true, -- FeetSlot + [9] = true, -- WristSlot + [10] = true, -- HandsSlot + [15] = true, -- BackSlot (some cloaks have durability) + [16] = true, -- MainHandSlot + [17] = true, -- OffHandSlot + [18] = true, -- RangedSlot +}; + +-- Default max durability for items when we can't read it +-- Vanilla WoW items typically have 35-165 max durability based on slot +local RD_DEFAULT_MAX_DURABILITY = { + [1] = 85, -- HeadSlot + [3] = 85, -- ShoulderSlot + [5] = 135, -- ChestSlot + [7] = 105, -- LegsSlot + [8] = 85, -- FeetSlot + [9] = 55, -- WristSlot + [10] = 85, -- HandsSlot + [15] = 55, -- BackSlot + [16] = 105, -- MainHandSlot + [17] = 105, -- OffHandSlot + [18] = 85, -- RangedSlot +}; + +-- Helper: Reset tooltip for fresh scan +-- In vanilla 1.12, tooltips can get "stuck" with stale data +-- Always call this before SetInventoryItem or SetHyperlink +local function RelationshipsDashboard_ResetTooltip() + if RelationshipsDashboardTooltip then + RelationshipsDashboardTooltip:SetOwner(WorldFrame, "ANCHOR_NONE"); + RelationshipsDashboardTooltip:ClearLines(); + end +end + +-- Player class cached on login +local RelationshipsDashboard_PlayerClass = nil; + +------------------------------------------------------------------------------- +-- Helper: Check if the player is currently in a battleground +-- In vanilla WoW 1.12, players do NOT take durability loss from death or +-- combat while in a battleground. We check using zone name and also +-- MiniMapBattlefieldFrame visibility as a fallback. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_IsInBattleground() + -- Method 1: Zone name check (English + a few localized variants) + local zone = GetRealZoneText and GetRealZoneText() or nil; + if zone and (RD_BATTLEGROUND_ZONES[zone] or RD_BATTLEGROUND_ZONES_EXTRA[zone]) then + return true; + end + local subZone = GetSubZoneText and GetSubZoneText() or nil; + if subZone and (RD_BATTLEGROUND_ZONES[subZone] or RD_BATTLEGROUND_ZONES_EXTRA[subZone]) then + return true; + end + -- Method 2: PvP zone info reports "combat" for active battlefields + if GetZonePVPInfo then + local pvpType = GetZonePVPInfo(); + if pvpType == "combat" then + return true; + end + end + -- Method 3: Ask the battlefield queue system directly. In 1.12 there are + -- up to MAX_BATTLEFIELD_QUEUES (3) slots. A status of "active" means the + -- player is currently inside that battleground. This is the most reliable + -- signal on Turtle WoW / OctoWoW even when zone strings do not match. + if GetBattlefieldStatus then + local maxQueues = MAX_BATTLEFIELD_QUEUES or 3; + for i = 1, maxQueues do + local status = GetBattlefieldStatus(i); + if status == "active" then + return true; + end + end + end + -- Method 4: MiniMapBattlefieldFrame is shown when inside a BG (fallback) + if MiniMapBattlefieldFrame and MiniMapBattlefieldFrame:IsVisible() then + local status = MiniMapBattlefieldFrame.status; + if status == "active" then + return true; + end + end + return false; +end + +-- Snapshot of equipped durability captured on BG entry so we can restore +-- exactly if any event mutates our tracker mid-BG (deaths, spirit rez, etc). +RD_BG_DurabilitySnapshot = nil; + +local function RelationshipsDashboard_SnapshotDurabilityForBG() + RD_BG_DurabilitySnapshot = {}; + for slotId, _ in pairs(RD_DURABILITY_SLOTS) do + local saved = RD_SavedDurability and RD_SavedDurability[slotId]; + if saved and saved.max then + RD_BG_DurabilitySnapshot[slotId] = { cur = saved.cur, max = saved.max }; + end + end +end + +local function RelationshipsDashboard_RestoreDurabilityFromBGSnapshot() + if not RD_BG_DurabilitySnapshot then return; end + for slotId, snap in pairs(RD_BG_DurabilitySnapshot) do + local saved = RD_SavedDurability and RD_SavedDurability[slotId]; + if saved then + saved.cur = snap.cur; + saved.max = snap.max; + end + end +end +-- Tracked mana values for when druid shifts to feral forms +-- In vanilla 1.12, UnitMana(RD_UNIT) returns the current form's power only +-- We store the caster-form mana to display it alongside Energy/Rage +local RelationshipsDashboard_LastKnownMana = 0; +local RelationshipsDashboard_LastKnownMaxMana = 0; + +------------------------------------------------------------------------------- +-- Helper: Check if player's class uses mana (has a mana pool regardless of form) +-- This is class-based, not form-based, so druids in feral forms still return true +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetUnitClass() + -- Get class for RD_UNIT (defaults to "player", switches to "target" during inspect) + local _, class = UnitClass(RD_UNIT); + if not class or class == "" then + if RD_UNIT == "player" then + if not RelationshipsDashboard_PlayerClass then + _, RelationshipsDashboard_PlayerClass = UnitClass("player"); + end + class = RelationshipsDashboard_PlayerClass; + end + end + -- Cache player class when we can + if RD_UNIT == "player" and class and class ~= "" then + RelationshipsDashboard_PlayerClass = class; + end + return class; +end + +local function RelationshipsDashboard_ClassUsesMana() + local class = RelationshipsDashboard_GetUnitClass(); + return class == "MAGE" + or class == "WARLOCK" + or class == "PRIEST" + or class == "DRUID" + or class == "SHAMAN" + or class == "PALADIN" + or class == "HUNTER"; +end + +------------------------------------------------------------------------------- +-- Helper: Check if unit is currently displaying mana (powerType == 0) +------------------------------------------------------------------------------- +local function RelationshipsDashboard_IsManaUser() + local powerType = UnitPowerType(RD_UNIT); + return powerType == 0; +end + +------------------------------------------------------------------------------- +-- Helper: Check if unit uses spell power (caster class) +------------------------------------------------------------------------------- +local function RelationshipsDashboard_IsCaster() + local class = RelationshipsDashboard_GetUnitClass(); + return class == "MAGE" + or class == "WARLOCK" + or class == "PRIEST" + or class == "DRUID" + or class == "SHAMAN" + or class == "PALADIN"; +end + +------------------------------------------------------------------------------- +-- Helper: Check if unit uses ranged weapons (Hunter primarily) +------------------------------------------------------------------------------- +local function RelationshipsDashboard_HasRanged() + local class = RelationshipsDashboard_GetUnitClass(); + return class == "HUNTER" + or class == "WARRIOR" + or class == "ROGUE"; +end + +------------------------------------------------------------------------------- +-- Dynamic layout system: Re-anchors all visible rows sequentially after +-- class visibility is applied. This eliminates gaps from hidden rows +-- (e.g., hidden Ranged stats in Enhancements, hidden Block in Defenses). +-- +-- Layout order definition: +-- Each section = { headerName, { row1, row2, ... } } +-- Rows are re-anchored TOPLEFT to the previous visible element's BOTTOMLEFT. +-- Section headers get a -4 spacing gap from the previous row. +------------------------------------------------------------------------------- +local RelationshipsDashboard_LayoutSections = { + { "", { + "RelationshipsDashboardGearScoreRow", + "RelationshipsDashboardAvgILvlRow", + }}, + { "RDHeaderGeneral", { + "RelationshipsDashboardHealthRow", + "RelationshipsDashboardPowerRow", + "RelationshipsDashboardManaRow", + "RelationshipsDashboardArmorRow", + "RelationshipsDashboardMovementRow", + "RelationshipsDashboardDurabilityRow", + "RelationshipsDashboardRepairCostRow", + }}, + { "RDHeaderAttributes", { + "RelationshipsDashboardStrengthRow", + "RelationshipsDashboardAgilityRow", + "RelationshipsDashboardStaminaRow", + "RelationshipsDashboardIntellectRow", + "RelationshipsDashboardSpiritRow", + }}, + { "RDHeaderOffense", { + "RelationshipsDashboardMeleeDmgRow", + "RelationshipsDashboardMeleeAPRow", + "RelationshipsDashboardMeleeSpeedRow", + "RelationshipsDashboardWeaponDPSRow", + "RelationshipsDashboardWeaponSkillRow", + "RelationshipsDashboardMeleeHitRow", + "RelationshipsDashboardMeleeCritRow", + }}, + { "RDHeaderEnhancements", { + "RelationshipsDashboardRangedAPRow", + "RelationshipsDashboardRangedCritRow", + "RelationshipsDashboardRangedSpeedRow", + "RelationshipsDashboardRangedDmgRow", + "RelationshipsDashboardSpellPowerRow", + "RelationshipsDashboardHealingPowerRow", + "RelationshipsDashboardSpellHitRow", + "RelationshipsDashboardSpellCritRow", + "RelationshipsDashboardManaRegenRow", + }}, + { "RDHeaderDefenses", { + "RelationshipsDashboardDefenseRow", + "RelationshipsDashboardDodgeRow", + "RelationshipsDashboardParryRow", + "RelationshipsDashboardBlockRow", + "RelationshipsDashboardAvoidanceRow", + }}, + { "RDHeaderResistances", { + "RelationshipsDashboardArcaneResRow", + "RelationshipsDashboardFireResRow", + "RelationshipsDashboardNatureResRow", + "RelationshipsDashboardFrostResRow", + "RelationshipsDashboardShadowResRow", + }}, +}; + +------------------------------------------------------------------------------- +-- Helper: iterate every frame that lives inside the scrollable stat content. +-- Vanilla 1.12 ScrollFrames do not clip nested child Frames reliably, so these +-- frames need explicit level management and viewport culling. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ForEachScrollElement(callback) + for secIdx = 1, table.getn(RelationshipsDashboard_LayoutSections) do + local section = RelationshipsDashboard_LayoutSections[secIdx]; + local headerName = section[1]; + local rowNames = section[2]; + + if headerName and headerName ~= "" then + local header = getglobal(headerName); + if header then + callback(header); + end + end + + for rowIdx = 1, table.getn(rowNames) do + local row = getglobal(rowNames[rowIdx]); + if row then + callback(row); + end + end + end +end + +local function RelationshipsDashboard_SetLayoutShown(element, shown) + if not element then return; end + + -- rdLayoutShown is the real layout intent. Do NOT infer layout from + -- IsShown(), because viewport clipping also uses Hide()/Show() and can + -- temporarily hide otherwise-valid rows while they are scrolled out. + element.rdLayoutShown = shown; + element.rdIntendedShown = shown; + + if shown then + if not element:IsShown() then element:Show(); end + else + if element:IsShown() then element:Hide(); end + end +end + +------------------------------------------------------------------------------- +-- Hard clip workaround for Vanilla/Turtle clients. +-- The ScrollFrame viewport clips the ScrollChild's own regions, but child Frames +-- inside that ScrollChild can still draw outside the viewport. We hide any row +-- or header that is not fully inside the scroll viewport, preventing text from +-- drawing above the title bar or below the panel. +------------------------------------------------------------------------------- +function RelationshipsDashboard_UpdateViewportClip() + if not RelationshipsDashboardScrollFrame then return; end + + local viewTop = RelationshipsDashboardScrollFrame:GetTop(); + local viewBottom = RelationshipsDashboardScrollFrame:GetBottom(); + if not viewTop or not viewBottom then return; end + + -- Vanilla/Turtle 1.12: SetAlpha(0) does NOT cascade to child FontStrings + -- inside a Frame, so alpha-clipping leaves overlapping labels visible when + -- rows scroll out of the viewport. We must Hide()/Show() the actual row + -- frames instead. To avoid re-showing rows that ApplyClassVisibility + -- intentionally hid (e.g. Ranged stats for casters), we consult the + -- `rdIntendedShown` flag set at the end of ApplyClassVisibility. + RelationshipsDashboard_ForEachScrollElement(function(element) + -- Never override an intentional class-based hide. + if element.rdIntendedShown == false then + if element:IsShown() then element:Hide(); end + return; + end + + local elemTop = element:GetTop(); + local elemBottom = element:GetBottom(); + local inView = elemTop and elemBottom + and elemTop <= (viewTop + 0.5) + and elemBottom >= (viewBottom - 0.5); + + if inView then + if not element:IsShown() then element:Show(); end + element:SetAlpha(1); + else + if element:IsShown() then element:Hide(); end + end + end); +end + +------------------------------------------------------------------------------- +-- Show/Hide stats based on class role, then re-anchor all visible rows +-- so hidden rows don't leave gaps in the layout. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ApplyClassVisibility() + local class = RelationshipsDashboard_GetUnitClass(); + local isCaster = RelationshipsDashboard_IsCaster(); + local hasRanged = RelationshipsDashboard_HasRanged(); + local isManaUser = RelationshipsDashboard_IsManaUser(); + local classUsesMana = RelationshipsDashboard_ClassUsesMana(); + + -- Reset every header/row to its normal layout state before applying + -- class-specific hides. This deliberately undoes viewport clipping hides; + -- clipping is re-applied after the rows are re-anchored below. + RelationshipsDashboard_ForEachScrollElement(function(element) + RelationshipsDashboard_SetLayoutShown(element, true); + end); + + -- ManaRow: Show for classes that have a mana pool, but only when + -- the current power type is NOT mana (druid in feral form shows + -- Energy/Rage on PowerRow + Mana on separate ManaRow). + -- When already showing mana on PowerRow, hide the duplicate ManaRow. + if classUsesMana and not isManaUser then + -- Class has mana but current form shows different power (e.g., druid bear/cat) + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardManaRow, true); + else + -- Either already showing mana on PowerRow, or class doesn't use mana at all + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardManaRow, false); + end + + -- Ranged stats: show for Hunter/Warrior/Rogue, hide for others + if hasRanged then + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedAPRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedCritRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedSpeedRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedDmgRow, true); + else + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedAPRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedCritRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedSpeedRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardRangedDmgRow, false); + end + + -- Spell stats: show for mana users/casters, hide for pure melee + if isCaster or classUsesMana then + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardSpellPowerRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardHealingPowerRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardSpellHitRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardSpellCritRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardManaRegenRow, true); + else + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardSpellPowerRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardHealingPowerRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardSpellHitRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardSpellCritRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardManaRegenRow, false); + end + + -- Melee stats: hide for pure casters (Mage, Warlock, Priest) + if class == "MAGE" or class == "WARLOCK" or class == "PRIEST" then + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeDmgRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeAPRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeSpeedRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardWeaponDPSRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardWeaponSkillRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeHitRow, false); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeCritRow, false); + else + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeDmgRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeAPRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeSpeedRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardWeaponDPSRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardWeaponSkillRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeHitRow, true); + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardMeleeCritRow, true); + end + + -- Block: only show for Warrior/Paladin/Shaman (classes that can use shields) + if class == "WARRIOR" or class == "PALADIN" or class == "SHAMAN" then + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardBlockRow, true); + else + RelationshipsDashboard_SetLayoutShown(RelationshipsDashboardBlockRow, false); + end + + -- ==== Dynamic re-anchoring: eliminate gaps from hidden rows ==== + -- Walk through all sections and rows, re-anchor each visible element + -- to the bottom of the previous visible element. + local prevElement = nil; -- last visible frame we anchored to + local stripeOn = false; -- alternating row stripe state + + for secIdx = 1, table.getn(RelationshipsDashboard_LayoutSections) do + local section = RelationshipsDashboard_LayoutSections[secIdx]; + local headerName = section[1]; + local rowNames = section[2]; + local header = getglobal(headerName); + + -- Count visible rows in this section BEFORE deciding whether to show its header. + -- Without this, class-hidden sections still render a title bar that visually + -- collides with rows from adjacent sections after re-anchoring. + local sectionHasVisibleRow = false; + for rowIdx = 1, table.getn(rowNames) do + local r = getglobal(rowNames[rowIdx]); + if r and r.rdLayoutShown ~= false then + sectionHasVisibleRow = true; + break; + end + end + + if header and sectionHasVisibleRow then + if prevElement then + -- Section header: anchor below previous visible element with gap + header:ClearAllPoints(); + header:SetPoint("TOPLEFT", prevElement, "BOTTOMLEFT", 0, -4); + else + -- First section: anchor to content top + header:ClearAllPoints(); + header:SetPoint("TOPLEFT", RelationshipsDashboardContent, "TOPLEFT", 0, 0); + end + RelationshipsDashboard_SetLayoutShown(header, true); + prevElement = header; + elseif header then + -- Every row in this section is class-hidden — hide the title too. + RelationshipsDashboard_SetLayoutShown(header, false); + end + + for rowIdx = 1, table.getn(rowNames) do + local rowName = rowNames[rowIdx]; + local row = getglobal(rowName); + if row and row.rdLayoutShown ~= false then + row:ClearAllPoints(); + if prevElement then + row:SetPoint("TOPLEFT", prevElement, "BOTTOMLEFT", 0, 0); + else + -- No previous element (first row, no section header): anchor to content top + row:SetPoint("TOPLEFT", RelationshipsDashboardContent, "TOPLEFT", 0, 0); + end + prevElement = row; + + -- Apply alternating row stripes + local bg = getglobal(rowName .. "BG"); + if bg then + if stripeOn then + bg:Show(); + bg:SetAlpha(0.04); + row.stripeOn = true; + else + bg:Hide(); + row.stripeOn = false; + end + end + stripeOn = not stripeOn; + end + end + end + + -- Update scroll child height based on last visible element. + -- IMPORTANT: do NOT clamp tall content down to the visible viewport. If the + -- ScrollChild is shorter than the actual rows, Vanilla lets nested row Frames + -- bleed outside the frame while the ScrollFrame has the wrong scroll range. + if prevElement then + local scrollFrame = RelationshipsDashboardScrollFrame; + local scrollVisibleHeight = scrollFrame:GetHeight() or 400; + local contentTop = RelationshipsDashboardContent:GetTop() or 0; + local elemBottom = prevElement:GetBottom() or 0; + local usedHeight = math.ceil(contentTop - elemBottom) + 10; + if usedHeight < 100 then + usedHeight = 100; + end + if usedHeight < scrollVisibleHeight then + usedHeight = scrollVisibleHeight; + end + RelationshipsDashboardContent:SetHeight(usedHeight); + + if scrollFrame.UpdateScrollChildRect then + scrollFrame:UpdateScrollChildRect(); + end + + local scrollBar = getglobal("RelationshipsDashboardScrollFrameScrollBar"); + if scrollBar then + local minVal, maxVal = scrollBar:GetMinMaxValues(); + if scrollBar:GetValue() > maxVal then + scrollBar:SetValue(maxVal); + elseif scrollBar:GetValue() < minVal then + scrollBar:SetValue(minVal); + end + end + end + + -- Snapshot which elements are legitimately shown right now (post class-filter + -- + relayout). UpdateViewportClip uses this to decide which rows may be + -- Show()n back into the viewport during scrolling, and which must stay + -- hidden because a class role rule hid them. + RelationshipsDashboard_ForEachScrollElement(function(element) + element.rdIntendedShown = (element.rdLayoutShown ~= false); + end); + + RelationshipsDashboard_BoostMaskLevels(); + RelationshipsDashboard_UpdateViewportClip(); +end + +------------------------------------------------------------------------------- +-- Helper: Extract item ID from an item link string +-- Vanilla 1.12 item link format: |cffXXXXXX|Hitem:itemId:enchantId:suffixId:uniqueId|h[Name]|h|r +-- We need to parse out the numeric item ID for database lookup +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ExtractItemID(itemLink) + if not itemLink then return nil; end + local _, _, itemID = strfind(itemLink, "item:(%d+):%d+:%d+:%d+"); + if itemID then + return tonumber(itemID); + end + return nil; +end + +------------------------------------------------------------------------------- +-- Helper: Safe wrapper for SetInventoryItem that catches errors +------------------------------------------------------------------------------- +local function RelationshipsDashboardTooltip_SetInventoryItemSafe(unit, slot) + if not RelationshipsDashboardTooltip then return false; end + local ok, err = pcall(function() RelationshipsDashboardTooltip:SetInventoryItem(unit, slot); end); + return ok; +end + +------------------------------------------------------------------------------- +-- Helper: Format money (copper) to gold/silver/copper string +------------------------------------------------------------------------------- +local function RelationshipsDashboard_FormatMoney(copper) + if copper <= 0 then + return "|cff00ff000g 0s 0c|r"; + end + local gold = floor(copper / 10000); + local silver = floor(mod(copper, 10000) / 100); + local copperRem = mod(copper, 100); + local result = ""; + if gold > 0 then + result = result .. "|cffffff00" .. gold .. "g|r "; + end + if silver > 0 or gold > 0 then + result = result .. "|cffc0c0c0" .. silver .. "s|r "; + end + result = result .. "|cffcc8844" .. copperRem .. "c|r"; + return result; +end + +------------------------------------------------------------------------------- +-- Helper: Format percentage +------------------------------------------------------------------------------- +local function RelationshipsDashboard_FormatPercent(value) + return string.format("%.2f%%", value); +end + +------------------------------------------------------------------------------- +-- Helper: Format decimal +------------------------------------------------------------------------------- +local function RelationshipsDashboard_FormatDecimal(value) + return string.format("%.2f", value); +end + +------------------------------------------------------------------------------- +-- Helper: Get item quality from item link +-- Item links in vanilla: |Hitem:itemId:enchantId:suffixId:uniqueId|h[name]|h[qualityCode] +-- Actually in 1.12: |cffXXXXXX|Hitem:itemId:enchant:suffix:unique|h[Name]|h|r +-- The color code maps to quality: +-- |cff9d9d9d = 0 (Poor), |cffffffff = 1 (Common), |cff1eff00 = 2 (Uncommon) +-- |cff0070dd = 3 (Rare), |cffa335ee = 4 (Epic), |cffff8000 = 5 (Legendary) +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetItemQualityFromLink(itemLink) + if not itemLink then return 0; end + -- Match the color prefix to determine quality + local quality = 0; + if strfind(itemLink, "|cff9d9d9d") then + quality = 0; + elseif strfind(itemLink, "|cffffffff") then + quality = 1; + elseif strfind(itemLink, "|cff1eff00") then + quality = 2; + elseif strfind(itemLink, "|cff0070dd") then + quality = 3; + elseif strfind(itemLink, "|cffa335ee") then + quality = 4; + elseif strfind(itemLink, "|cffff8000") then + quality = 5; + else + -- Fallback: try to use GetItemQualityColor if we can parse itemId + -- This shouldn't normally happen + quality = 1; + end + return quality; +end + +------------------------------------------------------------------------------- +-- Helper: Get item level using the built-in item database +-- Primary method: Look up itemID in RelationshipsDashboardDB_ItemLevels +-- Fallback method: Try GetItemInfo (works for cached items) +-- Last resort: Tooltip scanning +-- This is the proven approach for vanilla 1.12 where GetItemInfo is unreliable +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetItemLevel(itemLink) + if not itemLink then return 0; end + + -- Method 1: Extract itemID and look up in our database (most reliable) + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + if itemID and RelationshipsDashboardDB_ItemLevels then + local dbLevel = RelationshipsDashboardDB_ItemLevels[itemID]; + if dbLevel and dbLevel > 0 then + return dbLevel; + end + end + + -- Method 2: Try GetItemInfo (works for items cached in current session) + local _, _, _, itemLevel = GetItemInfo(itemLink); + if itemLevel and itemLevel > 0 then + return itemLevel; + end + + -- Method 3: Tooltip scanning as last resort + if RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + local ok, err = pcall(function() RelationshipsDashboardTooltip:SetHyperlink(itemLink); end); + if ok then + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, iLvl = strfind(text, "Item Level (%d+)"); + if iLvl then + return tonumber(iLvl); + end + end + end + end + end + end + + return 0; +end + +------------------------------------------------------------------------------- +-- Helper: Check if an item is a two-handed weapon +-- Uses itemEquipLoc from GetItemInfo (equipped items are always cached) +-- INVTYPE_2HWEAPON is the equip location for two-hand weapons +------------------------------------------------------------------------------- +local function RelationshipsDashboard_IsTwoHandWeapon(itemLink) + if not itemLink then return false; end + -- Vanilla 1.12 GetItemInfo returns: name(1), link(2), quality(3), iLevel(4), + -- minLevel(5), type(6), subType(7), stackCount(8), equipLoc(9), texture(10). + -- The equipLoc is the 9th return, not the 8th. + local _, _, _, _, _, _, _, _, itemEquipLoc = GetItemInfo(itemLink); + if itemEquipLoc == "INVTYPE_2HWEAPON" then + return true; + end + return false; +end + +------------------------------------------------------------------------------- +-- Calculate GearScore based on equipped items +-- Formula: score = rarity * itemLevel per item, x2 bonus for two-hand weapons +-- Also calculates average item level from the database +------------------------------------------------------------------------------- +local function RelationshipsDashboard_CalculateGearScore() + local totalScore = 0; + local totalILvl = 0; + local equippedCount = 0; -- items with a known item level (for avg ilvl) + local slotCount = 0; -- items equipped at all + + -- GearScoreLite-style quality scalar (rewards higher rarities much more, + -- so a low-level player in white/green gear can't out-score a mid-level + -- character in blue/purple gear like on real WoW). + local qualityScalar = { + [0] = 0.00, + [1] = 0.005, -- Common (white) + [2] = 0.25, -- Uncommon (green) + [3] = 0.50, -- Rare (blue) + [4] = 0.75, -- Epic (purple) + [5] = 1.00, -- Legendary (orange) + }; + + -- Slot weights approximate the TBC / WotLK GearScore standard + local slotWeight = { + [1] = 1.0000, [2] = 0.5625, [3] = 0.7500, [5] = 1.0000, + [6] = 0.7500, [7] = 1.0000, [8] = 0.7500, [9] = 0.5625, + [10] = 0.7500, [11] = 0.5625, [12] = 0.5625, [13] = 0.5625, + [14] = 0.5625, [15] = 0.5625, [16] = 1.0000, [17] = 1.0000, + [18] = 0.3164, + }; + + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink then + slotCount = slotCount + 1; + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + local itemLevel = 0; + if itemID and RelationshipsDashboardDB_ItemLevels then + itemLevel = RelationshipsDashboardDB_ItemLevels[itemID] or 0; + end + if itemLevel == 0 then + local _, _, _, giItemLevel = GetItemInfo(itemLink); + if giItemLevel and giItemLevel > 0 then + itemLevel = giItemLevel; + end + end + + -- Fallback for items missing from the DB and uncached from + -- GetItemInfo (common on Turtle WoW custom items, ESPECIALLY the + -- 2H weapon the player just equipped). Approximate from the + -- wearer's level so the score still reflects the equip/unequip. + if itemLevel == 0 then + local plvl = UnitLevel(RD_UNIT) or 1; + if plvl < 1 then plvl = 1; end + itemLevel = plvl; + end + + local quality = RelationshipsDashboard_GetItemQualityFromLink(itemLink); + local qf = qualityScalar[quality] or 0.005; + local sw = slotWeight[slotId] or 0.5625; + + -- Discount very low ilvl items (matches retail formula behavior) + local ilvlBase = itemLevel - 4; + if ilvlBase < 0 then ilvlBase = 0; end + + -- 9th return of GetItemInfo is equipLoc in vanilla 1.12. + local _, _, _, _, _, _, _, _, itemEquipLoc = GetItemInfo(itemLink); + local twoHandMult = 1; + if itemEquipLoc == "INVTYPE_2HWEAPON" then + twoHandMult = 2; + end + + -- Scale factor tuned so a full T2 (ilvl 76 epic) player lands + -- around ~2800 GearScore, a full BiS pre-raid ~2000, greens + -- at level 60 ~800-1000, and level 20 greens ~150. + local itemScore = ilvlBase * qf * sw * twoHandMult * 8; + + totalScore = totalScore + itemScore; + totalILvl = totalILvl + itemLevel; + equippedCount = equippedCount + 1; + end + end + + local avgILvl = 0; + if equippedCount > 0 then + avgILvl = totalILvl / equippedCount; + end + + return floor(totalScore), avgILvl, equippedCount; +end + +------------------------------------------------------------------------------- +-- Calculate durability and repair costs +-- Primary method: GetInventoryItemDurability (vanilla 1.12 API, works without repair NPC) +-- Fallback: Tooltip scanning for "Durability: XX / XX" pattern +-- Repair cost is estimated from durability ratio, item quality, item level, and slot type +-- When a repair merchant is open, GetRepairAllCost() provides the exact cost +------------------------------------------------------------------------------- + +-- Slots that never have durability in vanilla WoW (accessories) +local SLOTS_NO_DURABILITY = { + [2] = true, -- NeckSlot + [11] = true, -- Finger0Slot + [12] = true, -- Finger1Slot + [13] = true, -- Trinket0Slot + [14] = true, -- Trinket1Slot +}; + +-- Slot type multipliers for repair cost estimation +-- These represent the relative cost weight of each armor slot +-- Based on vanilla WoW's internal repair cost distribution +local SLOT_REPAIR_MULTIPLIER = { + [1] = 0.88, -- HeadSlot + [3] = 0.75, -- ShoulderSlot + [5] = 1.00, -- ChestSlot (highest) + [6] = 0.50, -- WaistSlot (no durability in vanilla, but just in case) + [7] = 0.88, -- LegsSlot + [8] = 0.75, -- FeetSlot + [9] = 0.50, -- WristSlot + [10] = 0.75, -- HandsSlot + [15] = 0.50, -- BackSlot (usually no durability, but some cloaks do) + [16] = 0.38, -- MainHandSlot + [17] = 0.38, -- OffHandSlot + [18] = 0.38, -- RangedSlot +}; + +-- DBC-backed repair multipliers from modern Classic Era DurabilityCosts.dbc. +-- Server formula used by newer cores: +-- repairCopper = lostDurability * DurabilityCosts[itemLevel][class/subclass] +-- * DurabilityQuality[(quality + 1) * 2] +-- This is much closer to WoW/Turtle/OctoWoW repair totals than a generic +-- ilvl/slot approximation, and it naturally takes the equipped gear type, +-- quality, and item level into account. +local RD_DBC_REPAIR_ARMOR = { + 1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5, + 5,5,5,6,6,6,7,7,7,8,8,9,9,10,11,12,13,14,15,16, + 17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55, + 57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95, + 97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135, +}; + +local RD_DBC_REPAIR_SHIELD = { + 1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6, + 6,6,7,7,7,8,8,9,9,10,11,12,13,14,15,16,17,19,21,23, + 25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63, + 65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103, + 105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,42,43, +}; + +local RD_DBC_REPAIR_WEAPON = { + 1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5, + 5,6,6,6,7,7,7,8,8,9,9,10,11,12,13,14,15,16,17,19, + 21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59, + 61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99, + 101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139, +}; + +local RD_DBC_REPAIR_WEAPON_2H = { + 1,1,1,1,1,3,3,3,3,4,4,4,4,6,6,6,6,7,7,7, + 7,9,9,9,10,10,10,12,12,13,13,15,16,18,19,21,22,24,25,28, + 31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79,82,85,88, + 91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136,139,142,145,148, + 151,154,157,160,163,166,169,172,175,178,181,184,187,190,193,196,199,202,205,208, +}; + +local RD_DBC_REPAIR_WEAPON_SMALL = { + 1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3,3, + 3,4,4,4,5,5,5,6,6,6,6,7,8,9,9,10,11,12,12,14, + 15,17,18,20,21,23,24,26,27,29,30,32,33,35,36,38,39,41,42,44, + 45,47,48,50,51,53,54,56,57,59,60,62,63,65,66,68,69,71,72,74, + 75,77,78,80,81,83,84,86,87,89,90,92,93,95,96,98,99,101,102,104, +}; + +local RD_DBC_REPAIR_FISHING = { + 1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4, + 4,4,4,4,5,5,5,6,6,6,7,7,8,8,8,9,9,9,9,9, + 9,10,10,10,11,11,11,12,12,12,13,13,13,14,14,14,14,14,14,15, + 15,15,16,16,16,17,17,17,18,18,18,18,18,18,19,19,19,20,20,20, + 21,21,21,22,22,22,23,23,23,23,23,23,24,24,24,25,25,25,26,26, +}; + +local RD_DBC_REPAIR_QUALITY = { + [0] = 0.60, -- Poor + [1] = 0.80, -- Common + [2] = 1.00, -- Uncommon + [3] = 1.25, -- Rare + [4] = 2.50, -- Epic + [5] = 3.00, -- Legendary +}; + +local function RelationshipsDashboard_GetRepairMultiplier(slotId, itemLink, itemLevel) + local ilvl = itemLevel or 1; + if ilvl < 1 then ilvl = 1; end + if ilvl > 100 then ilvl = 100; end + ilvl = floor(ilvl + 0.5); + + local _, _, _, _, _, itemType, itemSubType, _, itemEquipLoc = GetItemInfo(itemLink); + local subTypeLower = itemSubType and strlower(itemSubType) or ""; + + if itemEquipLoc == "INVTYPE_SHIELD" or strfind(subTypeLower, "shield") then + return RD_DBC_REPAIR_SHIELD[ilvl] or 0; + end + + if itemType == "Armor" + or itemEquipLoc == "INVTYPE_HEAD" + or itemEquipLoc == "INVTYPE_SHOULDER" + or itemEquipLoc == "INVTYPE_CHEST" + or itemEquipLoc == "INVTYPE_ROBE" + or itemEquipLoc == "INVTYPE_WAIST" + or itemEquipLoc == "INVTYPE_LEGS" + or itemEquipLoc == "INVTYPE_FEET" + or itemEquipLoc == "INVTYPE_WRIST" + or itemEquipLoc == "INVTYPE_HAND" + or itemEquipLoc == "INVTYPE_CLOAK" + or (slotId ~= 16 and slotId ~= 17 and slotId ~= 18) then + return RD_DBC_REPAIR_ARMOR[ilvl] or 0; + end + + if strfind(subTypeLower, "fishing") then + return RD_DBC_REPAIR_FISHING[ilvl] or 0; + end + if strfind(subTypeLower, "dagger") or strfind(subTypeLower, "wand") then + return RD_DBC_REPAIR_WEAPON_SMALL[ilvl] or 0; + end + if itemEquipLoc == "INVTYPE_2HWEAPON" + or strfind(subTypeLower, "two%-hand") + or strfind(subTypeLower, "staff") + or strfind(subTypeLower, "staves") + or strfind(subTypeLower, "polearm") + or strfind(subTypeLower, "crossbow") then + return RD_DBC_REPAIR_WEAPON_2H[ilvl] or 0; + end + + return RD_DBC_REPAIR_WEAPON[ilvl] or 0; +end + +local RelationshipsDashboard_CalculateInventoryRepairCost; + +local function RelationshipsDashboard_CalculateDurabilityAndRepair() + local totalCurrentDur = 0; + local totalMaxDur = 0; + local repairCost = 0; + local slotsWithDurability = 0; + + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local hasDurability = false; + local curDur, maxDur; + + -- Skip slots that never have durability + if SLOTS_NO_DURABILITY[slotId] then + -- Skip accessory slots entirely + elseif not RD_DURABILITY_SLOTS[slotId] then + -- Skip slots we don't track (e.g. waist in vanilla has no dur) + else + local itemLink = GetInventoryItemLink("player", slotId); + if itemLink then + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + local existingSaved = RD_SavedDurability[slotId]; + if existingSaved and existingSaved.itemID and itemID and existingSaved.itemID ~= itemID then + RD_SavedDurability[slotId] = nil; + end + -- Method 1: GetInventoryItemDurability (vanilla 1.12 API) + -- Returns currentDurability, maxDurability for the slot. + -- This is the most reliable method and works without a repair NPC. + if GetInventoryItemDurability then + curDur, maxDur = GetInventoryItemDurability(slotId); + if curDur and maxDur and maxDur > 0 then + -- Only TRUST this reading when it reports actual damage + -- (curDur < maxDur) or when a repair merchant is open. + -- On Turtle/OctoWoW the API frequently reports FULL + -- durability outside a merchant (notably right after a + -- /reload or login). Trusting a bogus "full" reading + -- would wipe our tracked estimate and falsely snap the + -- dashboard back to 100%. When it looks full and we are + -- not at a merchant, fall through to the saved estimate. + if curDur < maxDur or RD_AtRepairMerchant then + hasDurability = true; + RD_SavedDurability[slotId] = { cur = curDur, max = maxDur, itemID = itemID }; + end + end + end + + -- Method 2: Tooltip scanning for durability (fallback) + if not hasDurability and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe("player", slotId); + + for j = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. j); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, dCur, dMax = strfind(text, "Durability:%s*(%d+)%s*/%s*(%d+)"); + if dCur and dMax then + curDur = tonumber(dCur); + maxDur = tonumber(dMax); + -- Same trust rule as the API path: a "full" + -- reading outside a repair merchant may be a + -- server quirk, so keep the saved estimate + -- instead of resetting to 100%. + if maxDur and maxDur > 0 + and (curDur < maxDur or RD_AtRepairMerchant) then + hasDurability = true; + RD_SavedDurability[slotId] = { cur = curDur, max = maxDur, itemID = itemID }; + end + break; + end + end + end + end + end + + -- Method 3: Use saved/estimated durability (fallback when API fails) + -- This ensures we always show a meaningful value even when not + -- at a repair NPC and the vanilla API returns nothing. + if not hasDurability then + local saved = RD_SavedDurability[slotId]; + if saved and saved.max and saved.max > 0 then + -- Use the saved estimate + curDur = saved.cur; + maxDur = saved.max; + saved.itemID = itemID; + hasDurability = true; + else + -- No saved data: item is likely at full durability + -- (newly equipped or first time reading) + -- Use default max durability for the slot + local defaultMax = RD_DEFAULT_MAX_DURABILITY[slotId] or 85; + maxDur = defaultMax; + curDur = defaultMax; -- Assume full when unknown + hasDurability = true; + -- Save for future tracking + RD_SavedDurability[slotId] = { cur = curDur, max = maxDur, itemID = itemID }; + end + end + else + -- No item in this slot — clear saved data + RD_SavedDurability[slotId] = nil; + end + end + + if hasDurability and maxDur > 0 then + totalCurrentDur = totalCurrentDur + curDur; + totalMaxDur = totalMaxDur + maxDur; + slotsWithDurability = slotsWithDurability + 1; + + -- Estimate repair cost for this item when merchant is not open + -- Vanilla WoW repair formula is approximately: + -- cost = (maxDur - curDur) * slotMultiplier * qualityFactor * (itemLevel / 50) + -- where qualityFactor depends on item quality and slotMultiplier varies by slot + local itemLink = GetInventoryItemLink("player", slotId); + if itemLink then + local quality = RelationshipsDashboard_GetItemQualityFromLink(itemLink); + local itemLevel = RelationshipsDashboard_GetItemLevel(itemLink); + local durLost = maxDur - curDur; + + if durLost > 0 then + local dmultiplier = RelationshipsDashboard_GetRepairMultiplier(slotId, itemLink, itemLevel); + local qFactor = RD_DBC_REPAIR_QUALITY[quality] or 1.0; + local slotRepairCost = floor((durLost * dmultiplier * qFactor) + 0.5); + repairCost = repairCost + slotRepairCost; + end + end + end + end + + repairCost = repairCost + RelationshipsDashboard_CalculateInventoryRepairCost(); + + -- If a repair merchant is open, GetRepairAllCost() gives the exact cost. + -- This is handled separately in RelationshipsDashboard_UpdateRepairFromMerchant + -- and applied in UpdateStats when RelationshipsDashboard_MerchantRepairCost > 0. + + local avgDurability = 100; + if totalMaxDur > 0 then + avgDurability = (totalCurrentDur / totalMaxDur) * 100; + end + + return avgDurability, repairCost, slotsWithDurability; +end + +-- Ensure RD_SavedDurability[slotId] exists for an equipped durability item so +-- that death / spirit-healer / combat penalties can decrement it even when the +-- character panel has never been opened yet (in which case CalculateDurability +-- would not have populated saved state yet). +local function RelationshipsDashboard_EnsureSavedDurability(slotId) + local saved = RD_SavedDurability[slotId]; + local itemLink = GetInventoryItemLink("player", slotId); + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + if saved and saved.max and saved.max > 0 and (not itemID or not saved.itemID or saved.itemID == itemID) then + saved.itemID = itemID; + return saved; + end + if saved and itemID and saved.itemID and saved.itemID ~= itemID then + RD_SavedDurability[slotId] = nil; + end + local curDur, maxDur; + if GetInventoryItemDurability then + curDur, maxDur = GetInventoryItemDurability(slotId); + end + if not (curDur and maxDur and maxDur > 0) and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe("player", slotId); + for j = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. j); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, dCur, dMax = strfind(text, "Durability:%s*(%d+)%s*/%s*(%d+)"); + if dCur and dMax then + curDur = tonumber(dCur); + maxDur = tonumber(dMax); + break; + end + end + end + end + end + if not (curDur and maxDur and maxDur > 0) then + maxDur = RD_DEFAULT_MAX_DURABILITY[slotId] or 85; + curDur = maxDur; + end + RD_SavedDurability[slotId] = { cur = curDur, max = maxDur, itemID = itemID }; + return RD_SavedDurability[slotId]; +end + +local function RelationshipsDashboard_ReadContainerDurability(bag, slot) + local curDur, maxDur; + if GetContainerItemDurability then + local ok, c, m = pcall(function() return GetContainerItemDurability(bag, slot); end); + if ok then + curDur = c; + maxDur = m; + end + end + if not (curDur and maxDur and maxDur > 0) and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + local ok = pcall(function() RelationshipsDashboardTooltip:SetBagItem(bag, slot); end); + if ok then + for j = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. j); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, dCur, dMax = strfind(text, "Durability:%s*(%d+)%s*/%s*(%d+)"); + if dCur and dMax then + curDur = tonumber(dCur); + maxDur = tonumber(dMax); + break; + end + end + end + end + end + end + return curDur, maxDur; +end + +local function RelationshipsDashboard_GetSavedBagKey(bag, slot) + return "bag" .. bag .. ":" .. slot; +end + +local function RelationshipsDashboard_GetDefaultMaxForItemLink(itemLink) + local _, _, _, _, _, _, itemSubType, _, itemEquipLoc = GetItemInfo(itemLink); + local subTypeLower = itemSubType and strlower(itemSubType) or ""; + if itemEquipLoc == "INVTYPE_CHEST" or itemEquipLoc == "INVTYPE_ROBE" then return RD_DEFAULT_MAX_DURABILITY[5]; end + if itemEquipLoc == "INVTYPE_LEGS" then return RD_DEFAULT_MAX_DURABILITY[7]; end + if itemEquipLoc == "INVTYPE_HEAD" then return RD_DEFAULT_MAX_DURABILITY[1]; end + if itemEquipLoc == "INVTYPE_SHOULDER" then return RD_DEFAULT_MAX_DURABILITY[3]; end + if itemEquipLoc == "INVTYPE_FEET" then return RD_DEFAULT_MAX_DURABILITY[8]; end + if itemEquipLoc == "INVTYPE_WRIST" then return RD_DEFAULT_MAX_DURABILITY[9]; end + if itemEquipLoc == "INVTYPE_HAND" then return RD_DEFAULT_MAX_DURABILITY[10]; end + if itemEquipLoc == "INVTYPE_CLOAK" then return RD_DEFAULT_MAX_DURABILITY[15]; end + if itemEquipLoc == "INVTYPE_WEAPON" or itemEquipLoc == "INVTYPE_WEAPONMAINHAND" or itemEquipLoc == "INVTYPE_WEAPONOFFHAND" then return 90; end + if itemEquipLoc == "INVTYPE_2HWEAPON" or itemEquipLoc == "INVTYPE_RANGED" or itemEquipLoc == "INVTYPE_RANGEDRIGHT" or itemEquipLoc == "INVTYPE_SHIELD" then return 100; end + if strfind(subTypeLower, "shield") then return 100; end + return nil; +end + +local function RelationshipsDashboard_EstimateSingleRepairCost(slotId, itemLink, curDur, maxDur) + if not itemLink or not curDur or not maxDur or maxDur <= 0 then return 0; end + local durLost = maxDur - curDur; + if durLost <= 0 then return 0; end + local quality = RelationshipsDashboard_GetItemQualityFromLink(itemLink); + local itemLevel = RelationshipsDashboard_GetItemLevel(itemLink); + if not itemLevel or itemLevel <= 0 then + itemLevel = UnitLevel("player") or 1; + end + local dmultiplier = RelationshipsDashboard_GetRepairMultiplier(slotId, itemLink, itemLevel); + local qFactor = RD_DBC_REPAIR_QUALITY[quality] or 1.0; + return floor((durLost * dmultiplier * qFactor) + 0.5); +end + +RelationshipsDashboard_CalculateInventoryRepairCost = function() + local repairCost = 0; + if not GetContainerNumSlots or not GetContainerItemLink then return 0; end + + for bag = 0, 4 do + local numSlots = GetContainerNumSlots(bag) or 0; + for slot = 1, numSlots do + local itemLink = GetContainerItemLink(bag, slot); + if itemLink then + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + local key = RelationshipsDashboard_GetSavedBagKey(bag, slot); + local saved = RD_SavedDurability[key]; + if saved and itemID and saved.itemID and saved.itemID ~= itemID then + saved = nil; + RD_SavedDurability[key] = nil; + end + + local curDur, maxDur = RelationshipsDashboard_ReadContainerDurability(bag, slot); + if curDur and maxDur and maxDur > 0 then + if curDur < maxDur or RD_AtRepairMerchant then + RD_SavedDurability[key] = { cur = curDur, max = maxDur, itemID = itemID }; + saved = RD_SavedDurability[key]; + end + end + + if saved and saved.max and saved.max > 0 then + saved.itemID = itemID; + repairCost = repairCost + RelationshipsDashboard_EstimateSingleRepairCost(16, itemLink, saved.cur, saved.max); + end + else + RD_SavedDurability[RelationshipsDashboard_GetSavedBagKey(bag, slot)] = nil; + end + end + end + + return repairCost; +end + +local function RelationshipsDashboard_SyncEquippedDurabilityFromGame(allowFull) + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + if RD_DURABILITY_SLOTS[slotId] and not SLOTS_NO_DURABILITY[slotId] then + local itemLink = GetInventoryItemLink("player", slotId); + if itemLink then + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + local curDur, maxDur; + if GetInventoryItemDurability then + curDur, maxDur = GetInventoryItemDurability(slotId); + end + if curDur and maxDur and maxDur > 0 and (allowFull or curDur < maxDur) then + RD_SavedDurability[slotId] = { cur = curDur, max = maxDur, itemID = itemID }; + elseif RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe("player", slotId); + for j = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. j); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, dCur, dMax = strfind(text, "Durability:%s*(%d+)%s*/%s*(%d+)"); + if dCur and dMax then + curDur = tonumber(dCur); + maxDur = tonumber(dMax); + if maxDur and maxDur > 0 and (allowFull or curDur < maxDur) then + RD_SavedDurability[slotId] = { cur = curDur, max = maxDur, itemID = itemID }; + end + break; + end + end + end + end + end + else + RD_SavedDurability[slotId] = nil; + end + end + end +end + +------------------------------------------------------------------------------- +-- Apply death penalty: Reduce all equipped items' estimated durability by 10% +-- In vanilla WoW, dying costs 10% durability on all equipped items. +-- This is applied even to items that already have 0 durability (they go negative +-- in the internal representation, but we clamp to 0 for display). +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ApplyDeathPenalty() + -- No durability loss in battlegrounds or duels. Re-check live BG status + -- here in case ZONE_CHANGED has not yet updated the cached flag (some + -- Turtle WoW / OctoWoW builds fire PLAYER_DEAD before ZONE_CHANGED on + -- battleground entries that kill on-arrival). + if not RD_InBattleground then + RD_InBattleground = RelationshipsDashboard_IsInBattleground(); + end + if RD_InBattleground then + -- Belt-and-suspenders: if we somehow had already applied wear before + -- realizing we were in a BG, restore the snapshot taken on entry. + RelationshipsDashboard_RestoreDurabilityFromBGSnapshot(); + return; + end + if RD_InDuel then return; end + for i = 1, table.getn(EQUIPMENT_SLOTS) do + + local slotId = EQUIPMENT_SLOTS[i]; + if RD_DURABILITY_SLOTS[slotId] and not SLOTS_NO_DURABILITY[slotId] then + local itemLink = GetInventoryItemLink("player", slotId); + if itemLink then + -- Make sure we have a baseline for this slot even if the + -- character panel has never been opened this session. + local saved = RelationshipsDashboard_EnsureSavedDurability(slotId); + if saved and saved.max and saved.max > 0 then + -- Death penalty: lose 10% of max durability + local loss = floor(saved.max * 0.10); + if loss < 1 then loss = 1; end + saved.cur = saved.cur - loss; + if saved.cur < 0 then saved.cur = 0; end + end + end + end + end +end + +------------------------------------------------------------------------------- +-- Apply combat wear: Small durability loss from taking hits in combat. +-- Each time the player takes damage while in combat, there's a chance +-- of durability loss on armor pieces. In vanilla WoW, durability loss from +-- combat hits is approximately 0.1-0.5 durability per hit depending on damage. +-- We use a simplified model: every N damage events, lose 1 durability point +-- distributed across armor slots. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ApplyCombatWear(damageAmount) + if not RD_InCombat then return; end + -- No durability loss in battlegrounds or duels + if not RD_InBattleground then + RD_InBattleground = RelationshipsDashboard_IsInBattleground(); + end + if RD_InBattleground then return; end + if RD_InDuel then return; end + + if not damageAmount or damageAmount <= 0 then return; end + + RD_CombatHitCount = RD_CombatHitCount + 1; + + -- Every 20 combat hits, apply 1 durability point loss to a random armor slot + -- This approximates vanilla WoW's combat durability wear rate + -- (roughly 0.05-0.1 dur per hit depending on damage magnitude) + if RD_CombatHitCount >= 20 then + RD_CombatHitCount = 0; + + -- Pick armor slots to lose durability (not weapons, those don't decay from hits) + local armorSlots = { 1, 3, 5, 7, 8, 9, 10, 15 }; -- Head, Shoulder, Chest, Legs, Feet, Wrist, Hands, Back + -- Pick a random slot + local slotIdx = random(1, table.getn(armorSlots)); + local slotId = armorSlots[slotIdx]; + + local itemLink = GetInventoryItemLink("player", slotId); + if itemLink then + local saved = RelationshipsDashboard_EnsureSavedDurability(slotId); + if saved and saved.max and saved.max > 0 then + saved.cur = saved.cur - 1; + if saved.cur < 0 then saved.cur = 0; end + end + end + end +end + +------------------------------------------------------------------------------- +-- Reset all saved durability to full (used when player repairs at a merchant) +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ResetDurabilityToFull() + for key, saved in pairs(RD_SavedDurability) do + if saved and saved.max and saved.max > 0 then + saved.cur = saved.max; -- Fully repaired + end + end +end + +------------------------------------------------------------------------------- +-- Apply spirit-healer resurrection penalty. +-- Spirit Healers resurrect a dead player at the cost of 25% durability loss +-- to ALL items (equipped + inventory). We can only reliably estimate the +-- equipped portion; inventory durability isn't cheaply readable in 1.12. +-- Characters level 10 and under do NOT lose durability from spirit rez. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ApplySpiritHealerPenalty() + -- No durability loss in battlegrounds or duels (duels never trigger a + -- spirit-healer rez, but guard defensively in case the state races). + if not RD_InBattleground then + RD_InBattleground = RelationshipsDashboard_IsInBattleground(); + end + if RD_InBattleground then + RelationshipsDashboard_RestoreDurabilityFromBGSnapshot(); + return; + end + if RD_InDuel then return; end + if UnitLevel("player") <= 10 then return; end + + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + if RD_DURABILITY_SLOTS[slotId] and not SLOTS_NO_DURABILITY[slotId] then + local itemLink = GetInventoryItemLink("player", slotId); + if itemLink then + local saved = RelationshipsDashboard_EnsureSavedDurability(slotId); + if saved and saved.max and saved.max > 0 then + -- Spirit healer: lose 25% of max durability on top of the + -- 10% death penalty already applied by PLAYER_DEAD. + local loss = floor(saved.max * 0.25); + if loss < 1 then loss = 1; end + saved.cur = saved.cur - loss; + if saved.cur < 0 then saved.cur = 0; end + end + end + end + end + + -- Spirit healer repair bills include durability loss on damaged items in + -- bags as well. Track the equipped part exactly and bag items when the + -- client exposes their durability; otherwise seed a reasonable max from + -- equip type so the repair total does not ignore inventory damage. + if GetContainerNumSlots and GetContainerItemLink then + for bag = 0, 4 do + local numSlots = GetContainerNumSlots(bag) or 0; + for slot = 1, numSlots do + local itemLink = GetContainerItemLink(bag, slot); + if itemLink then + local itemID = RelationshipsDashboard_ExtractItemID(itemLink); + local key = RelationshipsDashboard_GetSavedBagKey(bag, slot); + local curDur, maxDur = RelationshipsDashboard_ReadContainerDurability(bag, slot); + if not (curDur and maxDur and maxDur > 0) then + maxDur = RelationshipsDashboard_GetDefaultMaxForItemLink(itemLink); + curDur = maxDur; + end + if curDur and maxDur and maxDur > 0 then + local saved = RD_SavedDurability[key]; + if not saved or not saved.max or saved.max <= 0 or (itemID and saved.itemID and saved.itemID ~= itemID) then + saved = { cur = curDur, max = maxDur, itemID = itemID }; + RD_SavedDurability[key] = saved; + end + local loss = floor(saved.max * 0.25); + if loss < 1 then loss = 1; end + saved.cur = saved.cur - loss; + if saved.cur < 0 then saved.cur = 0; end + end + end + end + end + end +end + +------------------------------------------------------------------------------- +-- Try to get actual repair cost from an open merchant +-- This is called when MERCHANT_SHOW / MERCHANT_UPDATE events fire +-- Uses GetRepairAllCost() - the correct vanilla 1.12 API +-- Returns repairAllCost, canRepair (only works at a repair-capable merchant) +------------------------------------------------------------------------------- +local RelationshipsDashboard_MerchantRepairCost = 0; + +-- Tracks the previous non-zero repair cost while a repair merchant is open. +-- When the reported cost transitions from >0 to 0, or the player's gold drops +-- by approximately that amount, we know a repair just happened and can safely +-- reset saved durability to full WITHOUT needing a /reload. +RD_PrevMerchantRepairCost = 0; + +local function RelationshipsDashboard_UpdateRepairFromMerchant() + -- GetRepairAllCost is the correct vanilla 1.12 API function name + -- It only returns a value when a repair-capable merchant window is open + if not GetRepairAllCost then return; end + + local cost, canRepair = GetRepairAllCost(); + -- Track whether a repair-capable merchant is currently open so the rest + -- of the addon knows it can trust "full" durability readings. + if canRepair then + RD_AtRepairMerchant = true; + else + RD_AtRepairMerchant = false; + end + + if not canRepair then + -- Merchant can't repair at all. Clear the transient state so a later + -- MERCHANT_UPDATE at a real repair NPC starts from a clean slate. + RelationshipsDashboard_MerchantRepairCost = 0; + RD_PrevMerchantRepairCost = 0; + return; + end + + -- CRITICAL: refresh actual durability from the API BEFORE we do anything + -- else. At a repair merchant GetInventoryItemDurability is reliable, so we + -- want RD_SavedDurability to reflect ground truth before we (a) calibrate + -- against the reported cost, or (b) decide the player just repaired. + RelationshipsDashboard_SyncEquippedDurabilityFromGame(true); + + if cost and cost > 0 then + RelationshipsDashboard_MerchantRepairCost = cost; + RD_PrevMerchantRepairCost = cost; + -- Calibrate our away-from-merchant estimate against the exact cost + -- the game reports. We recompute our DBC-based estimate for the CURRENT + -- (freshly-updated) damaged gear and store a narrow ratio, so future + -- estimates match this server while still staying grounded in gear data. + local _, rawEstimate = RelationshipsDashboard_CalculateDurabilityAndRepair(); + if rawEstimate and rawEstimate > 0 then + local factor = cost / rawEstimate; + if factor < 0.5 then factor = 0.5; end + if factor > 2.0 then factor = 2.0; end + RD_RepairCalibration = factor; + if RelationshipsDashboardDB then + RelationshipsDashboardDB.repairCalibration = factor; + RelationshipsDashboardDB.repairCalibrationVersion = RD_REPAIR_CALIBRATION_VERSION; + end + end + else + -- Repair cost is 0 at a repair-capable merchant. Two possibilities: + -- (a) Player just clicked Repair All / repaired every item. + -- (b) All gear was already at full durability when they opened + -- the merchant. + -- Either way the correct visible state is "everything full". Reset. + RelationshipsDashboard_MerchantRepairCost = 0; + RD_PrevMerchantRepairCost = 0; + RelationshipsDashboard_ResetDurabilityToFull(); + end +end + +------------------------------------------------------------------------------- +-- Get melee hit chance +-- In vanilla 1.12, melee hit rating doesn't exist as a rating. +-- Hit chance comes from gear bonuses (+X% hit) and the base 5% against same level. +-- We scan the paper doll tooltip for hit chance, or use GetCombatRatingBonus if available. +-- For vanilla: scan tooltip of CharacterDamageFrame or use stat bonus calculations. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetMeleeHitChance() + -- In vanilla 1.12, there's no direct API for hit chance from gear + -- The best approach is to calculate from hit rating on gear if available, + -- or scan the character's melee hit bonus from tooltip + + -- Try using GetCombatRating / GetCombatRatingBonus if available (Turtle WoW extension) + if GetCombatRating and GetCombatRatingBonus then + -- CR_HIT_MELEE = 6 in later patches, may not exist in 1.12 + local hitRating = GetCombatRating(6); + if hitRating then + local hitBonus = GetCombatRatingBonus(6); + if hitBonus then + return 5.0 + hitBonus; -- Base 5% + gear bonus + end + end + end + + -- Fallback: try scanning the paper doll melee tooltip + -- In vanilla, hovering over the melee damage stat shows hit chance + if RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + -- Set to the melee damage tooltip + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, 16); -- Main hand + + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + -- Look for hit chance modifiers on weapon tooltip + local _, _, hitVal = strfind(text, "improves your chance to hit by (%d+)%%"); + if hitVal then + return 5.0 + tonumber(hitVal); + end + local _, _, hitVal2 = strfind(text, "%+(%d+)%% Hit"); + if hitVal2 then + return 5.0 + tonumber(hitVal2); + end + end + end + end + end + + -- Final fallback: base hit chance is 5% for melee against same-level target + -- We'll try to accumulate +hit from equipment via tooltip scanning + local hitBonus = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "%+(%d+)%% chance to hit"); + if val then hitBonus = hitBonus + tonumber(val); end + local _, _, val2 = strfind(text, "Equip: Increases your chance to hit by (%d+)%%"); + if val2 then hitBonus = hitBonus + tonumber(val2); end + end + end + end + end + end + return 5.0 + hitBonus; +end + +------------------------------------------------------------------------------- +-- Get spell hit chance +-- Similar approach to melee hit - scan gear for +spell hit bonuses +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetSpellHitChance() + -- Try GetCombatRatingBonus if available + if GetCombatRating and GetCombatRatingBonus then + -- CR_HIT_SPELL = 8 + local hitRating = GetCombatRating(8); + if hitRating then + local hitBonus = GetCombatRatingBonus(8); + if hitBonus then + return 5.0 + hitBonus; -- Base 5% + gear bonus + end + end + end + + -- Fallback: scan equipment for +spell hit + local hitBonus = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "chance to hit with spells by (%d+)%%"); + if val then hitBonus = hitBonus + tonumber(val); end + local _, _, val2 = strfind(text, "%+(%d+)%% Spell Hit"); + if val2 then hitBonus = hitBonus + tonumber(val2); end + local _, _, val3 = strfind(text, "Increases your chance to hit with spells by (%d+)%%"); + if val3 then hitBonus = hitBonus + tonumber(val3); end + end + end + end + end + end + return 5.0 + hitBonus; +end + +------------------------------------------------------------------------------- +-- Get spell crit chance +-- In vanilla 1.12, there's GetSpellCritChance() available as a global +-- Or we can use UnitStat-based formulas and intellect contribution +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetSpellCritChance() + -- Method 1: Try GetSpellCritChance (may be available in Turtle WoW's extended API) + if GetSpellCritChance then + local crit = GetSpellCritChance(SPELL_SCHOOL_INDEX); + if crit and crit > 0 then + return crit; + end + end + + -- Method 2: Base spell crit + Intellect contribution + -- Base spell crit by class: + local _, class = UnitClass(RD_UNIT); + local baseSpellCrit = 0; + if class == "MAGE" then baseSpellCrit = 3.2; + elseif class == "WARLOCK" then baseSpellCrit = 2.6; + elseif class == "PRIEST" then baseSpellCrit = 2.4; + elseif class == "DRUID" then baseSpellCrit = 2.4; + elseif class == "SHAMAN" then baseSpellCrit = 2.4; + elseif class == "PALADIN" then baseSpellCrit = 2.4; + else baseSpellCrit = 0; end + + -- Intellect contribution: roughly 1% crit per 59.5 intellect at level 60 + local level = UnitLevel(RD_UNIT); + local intStat = UnitStat(RD_UNIT, 4); -- Intellect + local intPerCrit = 59.5; + if level < 60 then + intPerCrit = 59.5 * (level / 60); + end + local intCritBonus = intStat / intPerCrit; + + -- Scan gear for +spell crit + local gearCritBonus = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "critical strike chance with spells by (%d+)%%"); + if val then gearCritBonus = gearCritBonus + tonumber(val); end + local _, _, val2 = strfind(text, "%+(%d+)%% Spell Crit"); + if val2 then gearCritBonus = gearCritBonus + tonumber(val2); end + local _, _, val3 = strfind(text, "Improves your chance to get a critical strike with spells by (%d+)%%"); + if val3 then gearCritBonus = gearCritBonus + tonumber(val3); end + end + end + end + end + end + + return baseSpellCrit + intCritBonus + gearCritBonus; +end + +------------------------------------------------------------------------------- +-- Get melee crit chance +-- In vanilla 1.12: base melee crit + agility contribution + gear bonuses +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetMeleeCritChance() + -- Method 1: Try GetCritChance (may be available in Turtle WoW) + if GetCritChance then + local crit = GetCritChance(); + if crit and crit > 0 then + return crit; + end + end + + -- Method 2: Calculate from base + agility + gear + local _, class = UnitClass(RD_UNIT); + local level = UnitLevel(RD_UNIT); + + -- Base crit rate by class (approximate) + local baseCrit = 5.0; -- All classes have 5% base melee crit in vanilla + + -- Agility per crit varies by class and level + -- At level 60: Warrior=20, Rogue=~29, Hunter=~53, Paladin=~20, etc. + local agiPerCrit = 20; + if class == "WARRIOR" then agiPerCrit = 20; + elseif class == "ROGUE" then agiPerCrit = 29; + elseif class == "HUNTER" then agiPerCrit = 53; + elseif class == "PALADIN" then agiPerCrit = 20; + elseif class == "DRUID" then agiPerCrit = 20; + elseif class == "SHAMAN" then agiPerCrit = 20; + end + + -- Scale for level (these values are for level 60) + if level > 0 and level < 60 then + agiPerCrit = agiPerCrit * (level / 60); + if agiPerCrit < 1 then agiPerCrit = 1; end + end + + local agiStat = UnitStat(RD_UNIT, 2); -- Agility + local agiCritBonus = agiStat / agiPerCrit; + + -- Scan gear for +melee crit + local gearCritBonus = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "critical strike chance by (%d+)%%"); + if val then gearCritBonus = gearCritBonus + tonumber(val); end + local _, _, val2 = strfind(text, "%+(%d+)%% Crit"); + if val2 then gearCritBonus = gearCritBonus + tonumber(val2); end + local _, _, val3 = strfind(text, "Improves your chance to get a critical strike by (%d+)%%"); + if val3 then gearCritBonus = gearCritBonus + tonumber(val3); end + end + end + end + end + end + + return baseCrit + agiCritBonus + gearCritBonus; +end + +------------------------------------------------------------------------------- +-- Get ranged crit chance +-- For Hunters primarily - based on agility + gear +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetRangedCritChance() + -- Method 1: Try GetRangedCritChance (Turtle WoW extension) + if GetRangedCritChance then + local crit = GetRangedCritChance(); + if crit and crit > 0 then + return crit; + end + end + + -- Method 2: Similar to melee crit but with ranged-specific agi ratios + local _, class = UnitClass(RD_UNIT); + local level = UnitLevel(RD_UNIT); + local baseCrit = 5.0; + + -- Ranged crit from agility (Hunter-focused) + local agiPerCrit = 53; -- Hunter value + if class ~= "HUNTER" then + agiPerCrit = 40; -- Other classes + end + if level > 0 and level < 60 then + agiPerCrit = agiPerCrit * (level / 60); + if agiPerCrit < 1 then agiPerCrit = 1; end + end + + local agiStat = UnitStat(RD_UNIT, 2); + local agiCritBonus = agiStat / agiPerCrit; + + -- Scan gear for +ranged crit + local gearCritBonus = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "critical strike chance with ranged by (%d+)%%"); + if val then gearCritBonus = gearCritBonus + tonumber(val); end + local _, _, val2 = strfind(text, "%+(%d+)%% Ranged Crit"); + if val2 then gearCritBonus = gearCritBonus + tonumber(val2); end + end + end + end + end + end + + return baseCrit + agiCritBonus + gearCritBonus; +end + +------------------------------------------------------------------------------- +-- Get spell power (highest school bonus) +-- In vanilla 1.12, spell power is per-school. We show the highest. +-- Uses GetSpellBonusDamage if available, or scans gear. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetSpellPower() + -- Method 1: Try GetSpellBonusDamage (Turtle WoW extension) + if GetSpellBonusDamage then + local maxPower = 0; + -- School indices: 2=Holy, 3=Fire, 4=Nature, 5=Frost, 6=Shadow, 7=Arcane + for school = 2, 7 do + local power = GetSpellBonusDamage(school); + if power and power > maxPower then + maxPower = power; + end + end + return maxPower; + end + + -- Method 2: Scan gear for +spell damage + local spellPower = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "%+(%d+) Spell Damage"); + if val then spellPower = spellPower + tonumber(val); end + local _, _, val2 = strfind(text, "up to (%d+) additional spell damage"); + if val2 then spellPower = spellPower + tonumber(val2); end + local _, _, val3 = strfind(text, "Increases damage done by magical spells and effects by up to (%d+)"); + if val3 then spellPower = spellPower + tonumber(val3); end + local _, _, val4 = strfind(text, "%+(%d+) Fire Damage"); + if val4 then spellPower = spellPower + tonumber(val4); end + local _, _, val5 = strfind(text, "%+(%d+) Frost Damage"); + if val5 then spellPower = spellPower + tonumber(val5); end + local _, _, val6 = strfind(text, "%+(%d+) Arcane Damage"); + if val6 then spellPower = spellPower + tonumber(val6); end + local _, _, val7 = strfind(text, "%+(%d+) Shadow Damage"); + if val7 then spellPower = spellPower + tonumber(val7); end + local _, _, val8 = strfind(text, "%+(%d+) Nature Damage"); + if val8 then spellPower = spellPower + tonumber(val8); end + local _, _, val9 = strfind(text, "%+(%d+) Holy Damage"); + if val9 then spellPower = spellPower + tonumber(val9); end + end + end + end + end + end + return spellPower; +end + +------------------------------------------------------------------------------- +-- Get healing power +-- In vanilla 1.12, healing power is separate from spell damage +-- Uses GetSpellBonusHealing if available, or scans gear. +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetHealingPower() + -- Method 1: Try GetSpellBonusHealing (Turtle WoW extension) + if GetSpellBonusHealing then + local healing = GetSpellBonusHealing(); + if healing then + return healing; + end + end + + -- Method 2: Scan gear for +healing + local healingPower = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "healing spells by up to (%d+)"); + if val then healingPower = healingPower + tonumber(val); end + local _, _, val2 = strfind(text, "%+(%d+) Healing"); + if val2 then healingPower = healingPower + tonumber(val2); end + local _, _, val3 = strfind(text, "Increases healing done by spells and effects by up to (%d+)"); + if val3 then healingPower = healingPower + tonumber(val3); end + end + end + end + end + end + return healingPower; +end + +------------------------------------------------------------------------------- +-- Get mana regeneration (spirit-based formula) +-- In vanilla 1.12, mana regen comes from spirit (out of FSR) and gear bonuses +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetManaRegen() + -- Method 1: Try GetManaRegen (Turtle WoW extension) + if GetManaRegen then + local base, casting = GetManaRegen(); + if base then + return base; + end + end + + -- Method 2: Calculate from spirit + -- Spirit-based mana regen formula (out of combat, not casting): + -- Regen per tick (2 seconds) varies by class: + -- Priest: Spirit * 0.125 + -- Mage: Spirit * 0.125 + -- Warlock: Spirit * 0.1 + -- Druid: Spirit * 0.125 + -- Shaman: Spirit * 0.1 + -- Paladin: Spirit * 0.1 + -- Per second = tickRegen / 2 + local _, class = UnitClass(RD_UNIT); + local spirit = UnitStat(RD_UNIT, 5); + + -- Only show for mana classes + local powerType = UnitPowerType(RD_UNIT); + if powerType ~= 0 then + return 0; -- Not a mana user + end + + local spiritFactor = 0; + if class == "PRIEST" then spiritFactor = 0.125; + elseif class == "MAGE" then spiritFactor = 0.125; + elseif class == "WARLOCK" then spiritFactor = 0.1; + elseif class == "DRUID" then spiritFactor = 0.125; + elseif class == "SHAMAN" then spiritFactor = 0.1; + elseif class == "PALADIN" then spiritFactor = 0.1; + else return 0; end + + local baseRegen = spirit * spiritFactor / 2; -- per second + + -- Scan gear for +mana regen + local gearRegen = 0; + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, val = strfind(text, "mana every (%d+) sec"); + if val then + gearRegen = gearRegen + (tonumber(val) / 5); -- Convert per-5sec to per-second + end + local _, _, val2 = strfind(text, "%+(%d+) mana per 5 sec"); + if val2 then + gearRegen = gearRegen + (tonumber(val2) / 5); + end + local _, _, val3 = strfind(text, "Allows (%d+) mana per 5 sec"); + if val3 then + gearRegen = gearRegen + (tonumber(val3) / 5); + end + end + end + end + end + end + + return baseRegen + gearRegen; +end + +------------------------------------------------------------------------------- +-- Get weapon skill for current weapon +-- In vanilla 1.12, weapon skill affects hit/miss/glancing blow calculations +-- We show the skill for the currently equipped main hand weapon type +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetWeaponSkill() + local itemLink = GetInventoryItemLink(RD_UNIT, 16); -- Main hand + if not itemLink then return "--"; end + + local _, _, _, _, _, itemType, itemSubType = GetItemInfo(itemLink); + if not itemSubType then return "--"; end + + -- Map weapon subtypes to skill line indices + -- In vanilla, skill lines are accessed by name + -- The skill value = min(level * 5, baseSkill + racialBonus + gearBonus) + local skillName = nil; + if itemSubType == "Axes" or itemSubType == "One-Handed Axes" then skillName = "Axes"; + elseif itemSubType == "Two-Handed Axes" then skillName = "Two-Handed Axes"; + elseif itemSubType == "Maces" or itemSubType == "One-Handed Maces" then skillName = "Maces"; + elseif itemSubType == "Two-Handed Maces" then skillName = "Two-Handed Maces"; + elseif itemSubType == "Swords" or itemSubType == "One-Handed Swords" then skillName = "Swords"; + elseif itemSubType == "Two-Handed Swords" then skillName = "Two-Handed Swords"; + elseif itemSubType == "Daggers" then skillName = "Daggers"; + elseif itemSubType == "Fist Weapons" then skillName = "Unarmed"; + elseif itemSubType == "Polearms" then skillName = "Polearms"; + elseif itemSubType == "Staves" then skillName = "Staves"; + elseif itemSubType == "Bows" then skillName = "Bows"; + elseif itemSubType == "Crossbows" then skillName = "Crossbows"; + elseif itemSubType == "Guns" then skillName = "Guns"; + elseif itemSubType == "Thrown" then skillName = "Thrown"; + end + + if not skillName then return "--"; end + + -- Try to get skill value from the skills API + -- In vanilla 1.12, we iterate skill lines + local numSkills = GetNumSkillLines(); + if numSkills then + for i = 1, numSkills do + local skillName2, _, _, skillRank = GetSkillLineInfo(i); + if skillName2 == skillName then + return skillRank or "--"; + end + end + end + + -- Fallback: max skill for level = level * 5 + local level = UnitLevel(RD_UNIT); + return level * 5 .. " (max)"; +end + +------------------------------------------------------------------------------- +-- Get defense skill +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetDefense() + -- Method 1: Try GetDefense (Turtle WoW) + if GetDefense then + local base, mod = GetDefense("player"); + if base then + return (base + (mod or 0)); + end + end + + -- Method 2: From skill lines + local numSkills = GetNumSkillLines(); + if numSkills then + for i = 1, numSkills do + local skillName, _, _, skillRank = GetSkillLineInfo(i); + if skillName == "Defense" then + return skillRank or 0; + end + end + end + + return 0; +end + +------------------------------------------------------------------------------- +-- Get block chance and value +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetBlockChance() + if GetBlockChance then + return GetBlockChance(); + end + -- Only warriors and paladins can block (with shield equipped) + return 0; +end + +------------------------------------------------------------------------------- +-- Get parry chance +------------------------------------------------------------------------------- +local function RelationshipsDashboard_GetParryChance() + if GetParryChance then + return GetParryChance(); + end + -- Base parry is 5% for most melee classes + local _, class = UnitClass(RD_UNIT); + if class == "WARRIOR" or class == "PALADIN" or class == "ROGUE" or class == "HUNTER" or class == "DRUID" then + return 5.0; + end + return 0; +end + +------------------------------------------------------------------------------- +-- Main Stats Update Function +-- Called on show and on relevant events +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- INSPECT ESTIMATION +-- In vanilla 1.12 the client does NOT expose another player's computed stats +-- (UnitStat/UnitArmor/UnitAttackPower/UnitResistance/GetDodgeChance etc. all +-- return the *player's* own values for a target). The only reliable target +-- data available while inspecting is the equipped item set (item links + +-- tooltips) plus level and class. So when inspecting we ESTIMATE every stat +-- from the target's gear and level. Values are approximate. +------------------------------------------------------------------------------- + +-- Approximate un-geared primary stats at level 60, tuned to real vanilla +-- values (roughly the human baseline). Race adjustments applied below. +-- Index: 1=STR 2=AGI 3=STA 4=INT 5=SPI +local RD_BASE_STATS_60 = { + WARRIOR = { 105, 75, 105, 30, 45 }, + PALADIN = { 100, 60, 95, 65, 75 }, + HUNTER = { 60, 115, 90, 60, 65 }, + ROGUE = { 85, 115, 85, 35, 50 }, + PRIEST = { 40, 50, 70, 115, 125 }, + SHAMAN = { 80, 60, 90, 85, 90 }, + MAGE = { 35, 50, 65, 120, 115 }, + WARLOCK = { 50, 55, 80, 105, 105 }, + DRUID = { 70, 60, 80, 95, 95 }, +}; + +-- Per-race stat modifiers at level 60 relative to the human baseline above. +-- Values are typical vanilla deltas; missing entries default to 0. +-- Index: 1=STR 2=AGI 3=STA 4=INT 5=SPI +local RD_RACE_MODS_60 = { + Human = { 0, 0, 0, 0, 0 }, + Dwarf = { 5, -4, 1, -1, -1 }, + Gnome = { -5, 2, -1, 3, 0 }, + NightElf = { -4, 4, 0, 0, 0 }, + Orc = { 3, -3, 1, -3, 2 }, + Undead = { -1, -2, 0, -2, 5 }, + Tauren = { 5, -4, 1, -3, -2 }, + Troll = { 1, 2, 0, -4, 1 }, + Scourge = { -1, -2, 0, -2, 5 }, -- alt name for Undead + Goblin = { -3, 3, -1, 3, 0 }, + HighElf = { -4, 4, 0, 1, -1 }, +}; + +-- Rough Agility-per-1%-crit (and used for dodge) by class. +local RD_AGI_PER_CRIT = { + WARRIOR = 20, PALADIN = 20, DRUID = 20, SHAMAN = 20, + ROGUE = 29, HUNTER = 53, MAGE = 20, PRIEST = 20, WARLOCK = 20, +}; + +-- Classes that can parry in vanilla. +local RD_CAN_PARRY = { + WARRIOR = true, PALADIN = true, HUNTER = true, ROGUE = true, SHAMAN = true, +}; + +-- Passive racial resistances (vanilla / Turtle / OctoWoW). +-- Applied on top of gear resistances during inspect. Keys must match the +-- normalized race name (spaces stripped) produced in UpdateStatsInspect. +local RD_RACE_RES = { + Dwarf = { frost = 10 }, + Gnome = { arcane = 10 }, + NightElf = { nature = 10 }, + Tauren = { nature = 10 }, + Troll = { nature = 10 }, + Undead = { shadow = 10 }, + Scourge = { shadow = 10 }, + HighElf = { arcane = 10 }, + Goblin = { fire = 5 }, +}; + +-- Passive racial dodge (% points) — Night Elf Quickness. +local RD_RACE_DODGE = { + NightElf = 1, +}; + +-- Passive racial health multiplier — Tauren Endurance (+5% base health). +-- Not applied to Stamina directly because health is read from UnitHealthMax, +-- but kept here for completeness / future use. +local RD_RACE_HEALTH_MULT = { + Tauren = 1.05, +}; + +-- Parse a buff/racial tooltip line and add any recognized primary-stat, +-- resistance, spell-power, AP, crit, hit, or mp5 bonuses into `est`. +-- Mirrors the item parser but omits weapon-slot specific fields. +-- Also handles the two common buff phrasings: +-- "+X to Strength" (Mark of the Wild, Blessing of Kings post-scaling, etc.) +-- "Increases Strength by X" +-- "+X Strength" (item-style, same as gear) +local function RD_ParseBuffLineInto(est, text) + if not text then return; end + local v; + + local function addPrimary(stat, amt) + if not amt then return; end + amt = tonumber(amt); if not amt then return; end + if stat == "str" then est.str = est.str + amt; + elseif stat == "agi" then est.agi = est.agi + amt; + elseif stat == "sta" then est.sta = est.sta + amt; + elseif stat == "int" then est.int = est.int + amt; + elseif stat == "spi" then est.spi = est.spi + amt; + elseif stat == "all" then est.allStats = est.allStats + amt; end + end + + -- "+X " (Blessing of Might reads "+X Attack Power", Fortitude + -- reads "+X Stamina" on Turtle, etc.) + _,_,v = strfind(text, "%+(%d+) Strength"); addPrimary("str", v); + _,_,v = strfind(text, "%+(%d+) Agility"); addPrimary("agi", v); + _,_,v = strfind(text, "%+(%d+) Stamina"); addPrimary("sta", v); + _,_,v = strfind(text, "%+(%d+) Intellect"); addPrimary("int", v); + _,_,v = strfind(text, "%+(%d+) Spirit"); addPrimary("spi", v); + _,_,v = strfind(text, "%+(%d+) to All Stats"); addPrimary("all", v); + if not v then _,_,v = strfind(text, "%+(%d+) All Stats"); addPrimary("all", v); end + + -- "Increases by X" (Arcane Intellect, Divine Spirit, PW:F, etc.) + _,_,v = strfind(text, "[Ii]ncreases Strength by (%d+)"); addPrimary("str", v); + _,_,v = strfind(text, "[Ii]ncreases Agility by (%d+)"); addPrimary("agi", v); + _,_,v = strfind(text, "[Ii]ncreases Stamina by (%d+)"); addPrimary("sta", v); + _,_,v = strfind(text, "[Ii]ncreases Intellect by (%d+)"); addPrimary("int", v); + _,_,v = strfind(text, "[Ii]ncreases Spirit by (%d+)"); addPrimary("spi", v); + _,_,v = strfind(text, "[Ii]ncreases all attributes by (%d+)"); addPrimary("all", v); + _,_,v = strfind(text, "all party members by (%d+)"); -- Mark/Gift of the Wild form: "...by X" + if v and strfind(text, "attribute") then addPrimary("all", v); end + + -- Resistances (Shadow Protection, Prayer of Shadow, etc.) + _,_,v = strfind(text, "%+(%d+) Arcane Resistance"); if v then est.resArcane = est.resArcane + v; end + _,_,v = strfind(text, "%+(%d+) Fire Resistance"); if v then est.resFire = est.resFire + v; end + _,_,v = strfind(text, "%+(%d+) Nature Resistance"); if v then est.resNature = est.resNature + v; end + _,_,v = strfind(text, "%+(%d+) Frost Resistance"); if v then est.resFrost = est.resFrost + v; end + _,_,v = strfind(text, "%+(%d+) Shadow Resistance"); if v then est.resShadow = est.resShadow + v; end + _,_,v = strfind(text, "%+(%d+) to All Resistances"); if v then est.allRes = est.allRes + v; end + _,_,v = strfind(text, "resistance to all schools of magic by (%d+)"); + if v then est.allRes = est.allRes + v; end + _,_,v = strfind(text, "[Ss]hadow resistance by (%d+)"); if v then est.resShadow = est.resShadow + v; end + _,_,v = strfind(text, "[Ff]rost resistance by (%d+)"); if v then est.resFrost = est.resFrost + v; end + _,_,v = strfind(text, "[Ff]ire resistance by (%d+)"); if v then est.resFire = est.resFire + v; end + _,_,v = strfind(text, "[Nn]ature resistance by (%d+)"); if v then est.resNature = est.resNature + v; end + _,_,v = strfind(text, "[Aa]rcane resistance by (%d+)"); if v then est.resArcane = est.resArcane + v; end + + -- Attack power (Battle Shout, Trueshot Aura, Blessing of Might) + _,_,v = strfind(text, "melee attack power by (%d+)"); if v then est.ap = est.ap + v; end + _,_,v = strfind(text, "ranged attack power by (%d+)"); if v then est.rap = est.rap + v; end + _,_,v = strfind(text, "attack power by (%d+)"); + if v and not strfind(text, "ranged") then est.ap = est.ap + v; end + _,_,v = strfind(text, "%+(%d+) Attack Power"); if v then est.ap = est.ap + v; end + + -- Spell power / healing (Arcane Brilliance variants, Blessing of Wisdom, etc. + -- typical is "+X Spell Damage" or "+X Healing") + _,_,v = strfind(text, "%+(%d+) Spell Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Spell Power"); if v then est.spellDmg = est.spellDmg + v; est.healing = est.healing + v; end + _,_,v = strfind(text, "%+(%d+) Healing"); if v then est.healing = est.healing + v; end + + -- Crit % (Rallying Cry, Moonkin Aura, etc.) + _,_,v = strfind(text, "critical strike with spells by (%d+)%%"); + if v then est.critSpell = est.critSpell + v; end + _,_,v = strfind(text, "critical strike by (%d+)%%"); + if v then est.critMelee = est.critMelee + v; end + _,_,v = strfind(text, "critical hit chance by (%d+)%%"); + if v then est.critMelee = est.critMelee + v; est.critSpell = est.critSpell + v; end + + -- Mp5 (Blessing of Wisdom) + _,_,v = strfind(text, "Restores (%d+) mana per 5"); if v then est.mp5 = est.mp5 + v; end + _,_,v = strfind(text, "(%d+) mana every 5"); if v then est.mp5 = est.mp5 + v; end + + -- Armor (Inner Fire, Devotion Aura, Frost Armor, etc.) + _,_,v = strfind(text, "[Ii]ncreases armor by (%d+)"); if v then est.armor = est.armor + v; end + _,_,v = strfind(text, "%+(%d+) Armor"); if v then est.armor = est.armor + v; end + + -- Defense (Blessing of Sanctuary etc.) + _,_,v = strfind(text, "%+(%d+) Defense"); if v then est.defense = est.defense + v; end + + -- Dodge (Cat form etc.) + _,_,v = strfind(text, "chance to dodge by (%d+)%%"); if v then est.dodge = est.dodge + v; end +end + +-- Walk every visible buff on the inspected unit and fold recognized stat +-- bonuses into `est`. Uses the standard UnitBuff / GameTooltip:SetUnitBuff +-- flow available in 1.12. Silently skipped if the APIs are unavailable. +local function RelationshipsDashboard_ScanInspectBuffs(est) + if not est then return; end + if not RelationshipsDashboardTooltip then return; end + if not UnitBuff then return; end + + for i = 1, 32 do + local buffTex = UnitBuff(RD_UNIT, i); + if not buffTex then break; end + RelationshipsDashboard_ResetTooltip(); + -- SetUnitBuff exists on 1.12 clients that support inspect; guard it. + local ok = pcall(function() + RelationshipsDashboardTooltip:SetUnitBuff(RD_UNIT, i); + end); + if ok then + for j = 1, RelationshipsDashboardTooltip:NumLines() do + local tl = getglobal("RelationshipsDashboardTooltipTextLeft" .. j); + local text = tl and tl:GetText(); + RD_ParseBuffLineInto(est, text); + end + end + end +end + + +-- Scan every equipped item on the inspected unit and sum up the stat bonuses +-- printed on their tooltips. Returns a table of accumulated values. +local function RelationshipsDashboard_ScanInspectGear() + local est = { + str = 0, agi = 0, sta = 0, int = 0, spi = 0, allStats = 0, + armor = 0, + resArcane = 0, resFire = 0, resNature = 0, resFrost = 0, resShadow = 0, allRes = 0, + ap = 0, rap = 0, + critMelee = 0, critSpell = 0, hitMelee = 0, hitSpell = 0, + spellDmg = 0, healing = 0, + defense = 0, dodge = 0, parry = 0, block = 0, blockValue = 0, + mp5 = 0, + mhMin = 0, mhMax = 0, mhSpeed = 0, + ohMin = 0, ohMax = 0, ohSpeed = 0, + rMin = 0, rMax = 0, rSpeed = 0, + }; + + if not RelationshipsDashboardTooltip then return est; end + + -- Parse a single tooltip text line and fold any recognized stat bonuses + -- into `est`. `slotId` is passed through so weapon/ranged lines can be + -- routed correctly. Kept local so both the item-body loop and the + -- set-bonus loop can share exactly the same parsing (no divergence). + local function parseStatLine(text, slotId) + if not text then return; end + local v; + + -- Primary attributes + _,_,v = strfind(text, "%+(%d+) Strength"); if v then est.str = est.str + v; end + _,_,v = strfind(text, "%+(%d+) Agility"); if v then est.agi = est.agi + v; end + _,_,v = strfind(text, "%+(%d+) Stamina"); if v then est.sta = est.sta + v; end + _,_,v = strfind(text, "%+(%d+) Intellect"); if v then est.int = est.int + v; end + _,_,v = strfind(text, "%+(%d+) Spirit"); if v then est.spi = est.spi + v; end + _,_,v = strfind(text, "%+(%d+) to All Stats"); if v then est.allStats = est.allStats + v; end + if not v then _,_,v = strfind(text, "%+(%d+) All Stats"); if v then est.allStats = est.allStats + v; end end + + -- Armor + _,_,v = strfind(text, "(%d+) Armor"); + if v and not strfind(text, "Penetration") then est.armor = est.armor + v; end + + -- Resistances + _,_,v = strfind(text, "%+(%d+) Arcane Resistance"); if v then est.resArcane = est.resArcane + v; end + _,_,v = strfind(text, "%+(%d+) Fire Resistance"); if v then est.resFire = est.resFire + v; end + _,_,v = strfind(text, "%+(%d+) Nature Resistance"); if v then est.resNature = est.resNature + v; end + _,_,v = strfind(text, "%+(%d+) Frost Resistance"); if v then est.resFrost = est.resFrost + v; end + _,_,v = strfind(text, "%+(%d+) Shadow Resistance"); if v then est.resShadow = est.resShadow + v; end + _,_,v = strfind(text, "%+(%d+) to All Resistances"); if v then est.allRes = est.allRes + v; end + if not v then _,_,v = strfind(text, "%+(%d+) All Resistances"); if v then est.allRes = est.allRes + v; end end + + -- Attack power (ranged first) + _,_,v = strfind(text, "ranged attack power by (%d+)"); + if v then + est.rap = est.rap + v; + else + _,_,v = strfind(text, "attack power by (%d+)"); if v then est.ap = est.ap + v; end + _,_,v = strfind(text, "%+(%d+) Attack Power"); if v then est.ap = est.ap + v; end + end + + -- Crit + _,_,v = strfind(text, "critical strike with spells by (%d+)%%"); + if v then + est.critSpell = est.critSpell + v; + else + _,_,v = strfind(text, "critical strike by (%d+)%%"); if v then est.critMelee = est.critMelee + v; end + end + + -- Hit + _,_,v = strfind(text, "chance to hit with spells by (%d+)%%"); + if v then + est.hitSpell = est.hitSpell + v; + else + _,_,v = strfind(text, "chance to hit by (%d+)%%"); if v then est.hitMelee = est.hitMelee + v; end + end + + -- Spell damage / healing + _,_,v = strfind(text, "damage and healing done by magical spells and effects by up to (%d+)"); + if v then + est.spellDmg = est.spellDmg + v; + est.healing = est.healing + v; + else + _,_,v = strfind(text, "damage done by magical spells and effects by up to (%d+)"); + if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "healing done by spells and effects by up to (%d+)"); + if v then est.healing = est.healing + v; end + _,_,v = strfind(text, "healing spells by up to (%d+)"); + if v then est.healing = est.healing + v; end + _,_,v = strfind(text, "%+(%d+) Healing"); if v then est.healing = est.healing + v; end + _,_,v = strfind(text, "%+(%d+) Spell Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Spell Power"); if v then est.spellDmg = est.spellDmg + v; est.healing = est.healing + v; end + _,_,v = strfind(text, "%+(%d+) Fire Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Frost Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Arcane Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Shadow Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Nature Damage"); if v then est.spellDmg = est.spellDmg + v; end + _,_,v = strfind(text, "%+(%d+) Holy Damage"); if v then est.spellDmg = est.spellDmg + v; end + end + + -- Defense + _,_,v = strfind(text, "%+(%d+) Defense"); if v then est.defense = est.defense + v; end + _,_,v = strfind(text, "Increased Defense %+(%d+)"); if v then est.defense = est.defense + v; end + + -- Dodge / Parry / Block + _,_,v = strfind(text, "chance to dodge an attack by (%d+)%%"); if v then est.dodge = est.dodge + v; end + _,_,v = strfind(text, "%+(%d+)%% Dodge"); if v then est.dodge = est.dodge + v; end + _,_,v = strfind(text, "chance to parry an attack by (%d+)%%"); if v then est.parry = est.parry + v; end + _,_,v = strfind(text, "%+(%d+)%% Parry"); if v then est.parry = est.parry + v; end + _,_,v = strfind(text, "chance to block attacks with a shield by (%d+)%%"); if v then est.block = est.block + v; end + _,_,v = strfind(text, "block value of your shield by (%d+)"); if v then est.blockValue = est.blockValue + v; end + + -- Mana per 5 + _,_,v = strfind(text, "Restores (%d+) mana per 5"); if v then est.mp5 = est.mp5 + v; end + if not v then _,_,v = strfind(text, "%+(%d+) mana per 5"); if v then est.mp5 = est.mp5 + v; end end + if not v then _,_,v = strfind(text, "(%d+) [Mm]ana [Pp]er 5"); if v then est.mp5 = est.mp5 + v; end end + if not v then _,_,v = strfind(text, "(%d+) mana every 5"); if v then est.mp5 = est.mp5 + v; end end + + -- Turtle/1.12 additional tooltip variants + _,_,v = strfind(text, "[Ii]ncreases healing done by .- up to (%d+)"); + if v then est.healing = est.healing + v; end + _,_,v = strfind(text, "%+(%d+) [Ss]pell [Cc]rit"); + if v then est.critSpell = est.critSpell + v; end + _,_,v = strfind(text, "%+(%d+)%% [Ss]pell [Cc]rit"); + if v then est.critSpell = est.critSpell + v; end + _,_,v = strfind(text, "[Ii]ncreases attack power in Cat, Bear.- forms by (%d+)"); + if v then est.ap = est.ap + v; end -- Druid feral AP + _,_,v = strfind(text, "Feral Attack Power[:%s]+(%d+)"); + if v then est.ap = est.ap + v; end + -- Turtle common enchant / item phrasing without "Equip:" prefix + _,_,v = strfind(text, "%+(%d+) [Ww]eapon [Dd]amage"); + if v and (slotId == 16 or slotId == 17 or slotId == 18) then + if slotId == 16 then est.mhMin = est.mhMin + v; est.mhMax = est.mhMax + v; + elseif slotId == 17 then est.ohMin = est.ohMin + v; est.ohMax = est.ohMax + v; + else est.rMin = est.rMin + v; est.rMax = est.rMax + v; end + end + _,_,v = strfind(text, "Increases the block value of your shield by (%d+)"); + if v then est.blockValue = est.blockValue + v; end + + -- Weapon / ranged damage + speed (only for the weapon slots) + if slotId == 16 or slotId == 17 or slotId == 18 then + local _, _, dMin, dMax = strfind(text, "(%d+) %- (%d+) Damage"); + local _, _, spd = strfind(text, "Speed (%d+%.%d+)"); + if slotId == 16 then + if dMin then est.mhMin = tonumber(dMin); est.mhMax = tonumber(dMax); end + if spd then est.mhSpeed = tonumber(spd); end + elseif slotId == 17 then + if dMin then est.ohMin = tonumber(dMin); est.ohMax = tonumber(dMax); end + if spd then est.ohSpeed = tonumber(spd); end + else + if dMin then est.rMin = tonumber(dMin); est.rMax = tonumber(dMax); end + if spd then est.rSpeed = tonumber(spd); end + end + end + end + + -- Sets whose bonuses we have already folded in. Each set's bonus lines + -- are printed on EVERY equipped piece's tooltip, so we must apply them + -- exactly once per set no matter how many pieces the target wears. + local processedSets = {}; + + for i = 1, table.getn(EQUIPMENT_SLOTS) do + local slotId = EQUIPMENT_SLOTS[i]; + local itemLink = GetInventoryItemLink(RD_UNIT, slotId); + if itemLink then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, slotId); + + local inSet = false; -- currently inside a set block? + local setSkip = false; -- skip stats for this block? + local setEquipped = 0; -- how many pieces of this set are equipped + for j = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. j); + local text = textLine and textLine:GetText(); + if text then + -- Set header of the form "SetName (equipped/total)". + -- Also matches "Set: SetName (equipped/total)". + local _, _, eqStr, totStr = strfind(text, "%((%d+)/(%d+)%)"); + if eqStr and totStr then + inSet = true; + setEquipped = tonumber(eqStr) or 0; + -- Derive a stable set name key by stripping the count. + local name = gsub(text, "%s*%(%d+/%d+%)%s*$", ""); + name = gsub(name, "^%s*[Ss]et:%s*", ""); + name = gsub(name, "^%s+", ""); + name = gsub(name, "%s+$", ""); + if name == "" then name = "unnamed"; end + if processedSets[name] then + setSkip = true; + else + processedSets[name] = true; + setSkip = false; + end + -- Header line itself carries no stats. + elseif inSet then + -- Inside a set block. Bonus lines can look like: + -- "(3) +25 Strength" + -- "(3) Set: +25 Strength" + -- " Set: (3) +25 Strength" + -- "Set 3: +25 Strength" (Turtle/custom) + -- Piece-list lines have no "(N)" marker. + -- + -- Detection strategy: + -- 1) If we can find a required-piece count anywhere + -- in the line, treat it as a bonus line and apply + -- when the target has enough pieces equipped. + -- 2) As a fallback (in case a tooltip format hides + -- the count), use the FontString color: vanilla + -- renders ACTIVE set bonus lines in green + -- (~0,1,0) and inactive ones in gray (~0.5s). + -- Green => apply, gray => skip. This makes us + -- robust to header/format differences on + -- Turtle WoW / OctoWoW where the plain regex + -- previously dropped every set bonus during + -- inspect. + local _, _, reqStr = strfind(text, "%((%d+)%)"); + if not reqStr then + _,_,reqStr = strfind(text, "[Ss]et%s+(%d+)%s*:"); + end + + local isBonus = false; + local active = false; + if reqStr then + isBonus = true; + local req = tonumber(reqStr) or 99; + active = req <= setEquipped; + end + + -- Color-based override / fallback. GetTextColor() may + -- not exist on very old clients — pcall for safety. + local ok, r, g, b = pcall(function() + return textLine:GetTextColor(); + end); + if ok and type(r) == "number" and type(g) == "number" and type(b) == "number" then + -- Green = active set bonus. + if g > 0.6 and r < 0.4 and b < 0.4 then + isBonus = true; + active = true; + -- Gray = inactive set bonus (only override when we + -- already thought it was a bonus line). + elseif isBonus and r > 0.4 and r < 0.7 + and g > 0.4 and g < 0.7 + and b > 0.4 and b < 0.7 + and math.abs(r - g) < 0.1 and math.abs(g - b) < 0.1 then + active = false; + end + end + + if isBonus and active and not setSkip then + parseStatLine(text, slotId); + end + else + -- Normal item body line. + parseStatLine(text, slotId); + end + end + end + end + end + + + + -- Fold "all stats" / "all resistances" into the individual buckets. + if est.allStats > 0 then + est.str = est.str + est.allStats; est.agi = est.agi + est.allStats; + est.sta = est.sta + est.allStats; est.int = est.int + est.allStats; + est.spi = est.spi + est.allStats; + end + if est.allRes > 0 then + est.resArcane = est.resArcane + est.allRes; est.resFire = est.resFire + est.allRes; + est.resNature = est.resNature + est.allRes; est.resFrost = est.resFrost + est.allRes; + est.resShadow = est.resShadow + est.allRes; + end + + return est; +end + +-- Helper: format an estimated number. +local function RD_EstNum(n) + return tostring(floor(n + 0.5)); +end + +-- Helper: format an estimated percentage. +local function RD_EstPct(n) + return string.format("%.1f%%", n); +end + +-- Populate every dashboard row with estimates derived from the inspected +-- unit's equipped gear and level. Called from UpdateStats when RD_UNIT is not +-- "player". +function RelationshipsDashboard_UpdateStatsInspect() + local _, class = UnitClass(RD_UNIT); + class = class or "WARRIOR"; + local level = UnitLevel(RD_UNIT) or 1; + if level < 1 then level = 1; end + + local est = RelationshipsDashboard_ScanInspectGear(); + + -- Fold active buffs on the target into the same estimate bucket. This + -- covers Mark/Gift of the Wild, PW:Fortitude, Divine Spirit, Arcane + -- Intellect, Blessing of Kings/Might/Wisdom, Battle Shout, Trueshot + -- Aura, Shadow/Nature/etc. Protection, Inner Fire, and similar. The + -- personal panel gets these automatically via UnitStat; inspect does + -- not, so we parse buff tooltips. Re-fold allStats/allRes afterwards + -- because Gift of the Wild etc. add to those buckets. + local buffAllStatsBefore = est.allStats; + local buffAllResBefore = est.allRes; + RelationshipsDashboard_ScanInspectBuffs(est); + local dAll = est.allStats - buffAllStatsBefore; + if dAll > 0 then + est.str = est.str + dAll; est.agi = est.agi + dAll; + est.sta = est.sta + dAll; est.int = est.int + dAll; + est.spi = est.spi + dAll; + end + local dRes = est.allRes - buffAllResBefore; + if dRes > 0 then + est.resArcane = est.resArcane + dRes; est.resFire = est.resFire + dRes; + est.resNature = est.resNature + dRes; est.resFrost = est.resFrost + dRes; + est.resShadow = est.resShadow + dRes; + end + + + -- Base primary stats scaled by level, plus per-race offset, plus gear. + local anchors = RD_BASE_STATS_60[class] or RD_BASE_STATS_60.WARRIOR; + local _, raceKey = UnitRace(RD_UNIT); + if not raceKey then raceKey = UnitRace(RD_UNIT) or "Human"; end + -- Normalize race key: strip spaces (e.g. "Night Elf" -> "NightElf") and + -- collapse to the table's naming. + if raceKey then raceKey = gsub(raceKey, "%s+", ""); end + local raceMods = RD_RACE_MODS_60[raceKey] or RD_RACE_MODS_60.Human; + -- Vanilla base stats don't grow linearly from level 1. Blizzard's + -- curve is roughly quadratic: growth per level starts small and + -- accelerates. Fit: at L1 primaries are ~20, at L60 they match the + -- class anchor. Approximate with (L-1)/59 raised to ~1.4 so mid-level + -- (30-45) values match Turtle character sheets more closely than + -- straight linear scaling did. + local function baseStat(idx) + local anchor = anchors[idx] + (raceMods[idx] or 0); + if level >= 60 then return anchor; end + local low = 20; -- level-1 baseline + if anchor < low then low = anchor; end + local t = (level - 1) / 59; -- 0..1 + if t < 0 then t = 0; end + -- power curve; exp=1.35 matches vanilla growth within a couple points + local frac = t ^ 1.35; + local b = floor(low + (anchor - low) * frac + 0.5); + if b < 1 then b = 1; end + return b; + end + local totStr = baseStat(1) + est.str; + local totAgi = baseStat(2) + est.agi; + local totSta = baseStat(3) + est.sta; + local totInt = baseStat(4) + est.int; + local totSpi = baseStat(5) + est.spi; + + -- Passive racial resistances (Dwarf +10 Frost, Gnome +10 Arcane, + -- Undead +10 Shadow, NightElf/Tauren/Troll +10 Nature, etc.). + local raceRes = RD_RACE_RES[raceKey]; + if raceRes then + est.resArcane = est.resArcane + (raceRes.arcane or 0); + est.resFire = est.resFire + (raceRes.fire or 0); + est.resNature = est.resNature + (raceRes.nature or 0); + est.resFrost = est.resFrost + (raceRes.frost or 0); + est.resShadow = est.resShadow + (raceRes.shadow or 0); + end + -- Passive racial dodge (Night Elf Quickness = +1%). + est.dodge = est.dodge + (RD_RACE_DODGE[raceKey] or 0); + + + -- ==== General ==== + -- Health and mana ARE visible for a target, so use the real values. + local health = UnitHealth(RD_UNIT); + local maxHealth = UnitHealthMax(RD_UNIT); + if maxHealth and maxHealth > 0 then + RelationshipsDashboardHealthRowValue:SetText(health .. " / " .. maxHealth); + else + RelationshipsDashboardHealthRowValue:SetText("--"); + end + RelationshipsDashboardHealthRowValue:SetTextColor(0.2, 1, 0.2); + + local powerType = UnitPowerType(RD_UNIT); + local power = UnitMana(RD_UNIT); + local maxPower = UnitManaMax(RD_UNIT); + if powerType == 1 then RelationshipsDashboardPowerRowLabel:SetText("Rage:"); + elseif powerType == 2 then RelationshipsDashboardPowerRowLabel:SetText("Focus:"); + elseif powerType == 3 then RelationshipsDashboardPowerRowLabel:SetText("Energy:"); + else RelationshipsDashboardPowerRowLabel:SetText("Mana:"); end + if maxPower and maxPower > 0 then + RelationshipsDashboardPowerRowValue:SetText(power .. " / " .. maxPower); + else + RelationshipsDashboardPowerRowValue:SetText("--"); + end + RelationshipsDashboardPowerRowValue:SetTextColor(0.3, 0.6, 1); + + if RelationshipsDashboard_ClassUsesMana() and powerType ~= 0 then + RelationshipsDashboardManaRowLabel:SetText("Mana:"); + RelationshipsDashboardManaRowValue:SetText("--"); + RelationshipsDashboardManaRowValue:SetTextColor(0.3, 0.6, 1); + end + + -- Armor = item armor + Agility contribution (2 per Agi in vanilla). + local armorEst = est.armor + totAgi * 2; + RelationshipsDashboardArmorRowValue:SetText(RD_EstNum(armorEst)); + RelationshipsDashboardArmorRowValue:SetTextColor(1, 1, 1); + + -- Movement / durability / repair are not knowable for another player. + RelationshipsDashboardMovementRowValue:SetText("--"); + RelationshipsDashboardDurabilityRowValue:SetText("--"); + RelationshipsDashboardDurabilityRowValue:SetTextColor(1, 1, 1); + RelationshipsDashboardRepairCostRowValue:SetText("--"); + + -- GearScore + average item level work off the target's gear directly. + local gearScore, avgILvl = RelationshipsDashboard_CalculateGearScore(); + if gearScore and gearScore > 0 then + RelationshipsDashboardGearScoreRowValue:SetText(tostring(gearScore)); + else + RelationshipsDashboardGearScoreRowValue:SetText("--"); + end + if gearScore >= 3500 then RelationshipsDashboardGearScoreRowValue:SetTextColor(1, 0.5, 0); + elseif gearScore >= 2000 then RelationshipsDashboardGearScoreRowValue:SetTextColor(0.8, 0.2, 1); + elseif gearScore >= 1200 then RelationshipsDashboardGearScoreRowValue:SetTextColor(0, 0.44, 0.87); + elseif gearScore >= 500 then RelationshipsDashboardGearScoreRowValue:SetTextColor(0.12, 1, 0); + else RelationshipsDashboardGearScoreRowValue:SetTextColor(1, 1, 1); end + if avgILvl and avgILvl > 0 then + RelationshipsDashboardAvgILvlRowValue:SetText(string.format("%.1f", avgILvl)); + else + RelationshipsDashboardAvgILvlRowValue:SetText("--"); + end + + -- ==== Attributes ==== + RelationshipsDashboardStrengthRowValue:SetText(RD_EstNum(totStr)); + RelationshipsDashboardAgilityRowValue:SetText(RD_EstNum(totAgi)); + RelationshipsDashboardStaminaRowValue:SetText(RD_EstNum(totSta)); + RelationshipsDashboardIntellectRowValue:SetText(RD_EstNum(totInt)); + RelationshipsDashboardSpiritRowValue:SetText(RD_EstNum(totSpi)); + + -- ==== Offense ==== + -- Melee attack power by class formula. + local ap; + if class == "WARRIOR" or class == "PALADIN" then ap = level * 3 + totStr * 2 - 20; + elseif class == "SHAMAN" then ap = level * 2 + totStr * 2 - 20; + elseif class == "DRUID" then ap = totStr * 2 - 20; + elseif class == "ROGUE" or class == "HUNTER" then ap = level * 2 + totStr + totAgi - 20; + else ap = totStr - 10; end + if ap < 0 then ap = 0; end + ap = ap + est.ap; + est.apTotal = ap; + + -- Melee damage: weapon base + AP contribution (AP/14 per second). + if est.mhSpeed > 0 and est.mhMax > 0 then + local swingBonus = (ap / 14) * est.mhSpeed; + local effMin = est.mhMin + swingBonus; + local effMax = est.mhMax + swingBonus; + RelationshipsDashboardMeleeDmgRowValue:SetText(floor(effMin) .. " - " .. floor(effMax)); + RelationshipsDashboardWeaponDPSRowValue:SetText(string.format("%.1f", (effMin + effMax) / 2 / est.mhSpeed)); + else + RelationshipsDashboardMeleeDmgRowValue:SetText("--"); + RelationshipsDashboardWeaponDPSRowValue:SetText("--"); + end + + RelationshipsDashboardMeleeAPRowValue:SetText(RD_EstNum(ap)); + + if est.mhSpeed > 0 then + if est.ohSpeed > 0 then + RelationshipsDashboardMeleeSpeedRowValue:SetText(RelationshipsDashboard_FormatDecimal(est.mhSpeed) .. " / " .. RelationshipsDashboard_FormatDecimal(est.ohSpeed)); + else + RelationshipsDashboardMeleeSpeedRowValue:SetText(RelationshipsDashboard_FormatDecimal(est.mhSpeed)); + end + else + RelationshipsDashboardMeleeSpeedRowValue:SetText("--"); + end + + -- Weapon skill: player skill API is unavailable for a target, so show the + -- level cap (level * 5). + RelationshipsDashboardWeaponSkillRowValue:SetText(tostring(level * 5) .. " (max)"); + + RelationshipsDashboardMeleeHitRowValue:SetText(RD_EstPct(est.hitMelee)); + + local agiPerCrit = RD_AGI_PER_CRIT[class] or 20; + local meleeCrit = 5 + totAgi / agiPerCrit + est.critMelee; + RelationshipsDashboardMeleeCritRowValue:SetText(RD_EstPct(meleeCrit)); + + -- Ranged Attack Power (Turtle/1.12): Hunters get level*2 + Agi*2 - 20 + -- (2 RAP per Agility, not 1); other classes just use Agility - 10. + local rap; + if class == "HUNTER" then rap = level * 2 + totAgi * 2 - 20; + else rap = totAgi - 10; end + if rap < 0 then rap = 0; end + rap = rap + est.rap; + RelationshipsDashboardRangedAPRowValue:SetText(RD_EstNum(rap)); + + -- Ranged crit: base 5% + Agi/agiPerCrit + gear ranged crit (falls back + -- to melee crit bucket because most 1.12 items list a single crit stat). + local rangedCrit = 5 + totAgi / agiPerCrit + est.critMelee; + RelationshipsDashboardRangedCritRowValue:SetText(RD_EstPct(rangedCrit)); + + if est.rSpeed > 0 then + RelationshipsDashboardRangedSpeedRowValue:SetText(RelationshipsDashboard_FormatDecimal(est.rSpeed)); + else + RelationshipsDashboardRangedSpeedRowValue:SetText("--"); + end + if est.rMax > 0 then + RelationshipsDashboardRangedDmgRowValue:SetText(est.rMin .. " - " .. est.rMax); + else + RelationshipsDashboardRangedDmgRowValue:SetText("--"); + end + + RelationshipsDashboardSpellPowerRowValue:SetText(RD_EstNum(est.spellDmg)); + RelationshipsDashboardHealingPowerRowValue:SetText(RD_EstNum(est.healing)); + RelationshipsDashboardSpellHitRowValue:SetText(RD_EstPct(est.hitSpell)); + + -- Spell crit per Intellect varies by class in vanilla/Turtle. + -- Values are Int-per-1%-crit at level 60. + local intPerSpellCrit; + if class == "MAGE" then intPerSpellCrit = 59.5; + elseif class == "PRIEST" then intPerSpellCrit = 59.2; + elseif class == "WARLOCK" then intPerSpellCrit = 60.6; + elseif class == "DRUID" then intPerSpellCrit = 60.0; + elseif class == "SHAMAN" then intPerSpellCrit = 59.2; + elseif class == "PALADIN" then intPerSpellCrit = 54.0; + else intPerSpellCrit = 60.0; end + local spellCrit = 5 + totInt / intPerSpellCrit + est.critSpell; + RelationshipsDashboardSpellCritRowValue:SetText(RD_EstPct(spellCrit)); + + -- Mana regen: spirit-based (if a mana class) + gear mp5. + local spiritFactor = 0; + if class == "PRIEST" or class == "MAGE" or class == "DRUID" then spiritFactor = 0.125; + elseif class == "WARLOCK" or class == "SHAMAN" or class == "PALADIN" then spiritFactor = 0.1; end + local manaRegen = 0; + if spiritFactor > 0 then manaRegen = totSpi * spiritFactor / 2; end + manaRegen = manaRegen + est.mp5 / 5; + if manaRegen > 0 then + RelationshipsDashboardManaRegenRowValue:SetText(string.format("%.1f/s", manaRegen)); + else + RelationshipsDashboardManaRegenRowValue:SetText("--"); + end + + -- ==== Defenses ==== + local defense = level * 5 + est.defense; + RelationshipsDashboardDefenseRowValue:SetText(RD_EstNum(defense)); + + local dodge = totAgi / agiPerCrit + est.dodge; + RelationshipsDashboardDodgeRowValue:SetText(RD_EstPct(dodge)); + + if RD_CAN_PARRY[class] then + RelationshipsDashboardParryRowValue:SetText(RD_EstPct(5 + est.parry)); + else + RelationshipsDashboardParryRowValue:SetText("--"); + end + + if est.block > 0 or est.blockValue > 0 then + RelationshipsDashboardBlockRowValue:SetText(RD_EstPct(est.block)); + else + RelationshipsDashboardBlockRowValue:SetText("--"); + end + + -- Avoidance: rough miss (5%) + dodge + parry + block. + local avoidance = 5 + dodge + (RD_CAN_PARRY[class] and (5 + est.parry) or 0) + est.block; + RelationshipsDashboardAvoidanceRowValue:SetText(RD_EstPct(avoidance)); + + -- ==== Resistances ==== + RelationshipsDashboardArcaneResRowValue:SetText(RD_EstNum(est.resArcane)); + RelationshipsDashboardFireResRowValue:SetText(RD_EstNum(est.resFire)); + RelationshipsDashboardNatureResRowValue:SetText(RD_EstNum(est.resNature)); + RelationshipsDashboardFrostResRowValue:SetText(RD_EstNum(est.resFrost)); + RelationshipsDashboardShadowResRowValue:SetText(RD_EstNum(est.resShadow)); + + -- Apply class-specific visibility (hide irrelevant stats). + RelationshipsDashboard_ApplyClassVisibility(); +end + +------------------------------------------------------------------------------- +-- Update throttling / coalescing. +-- +-- RelationshipsDashboard_UpdateStats_Impl() is the heavy per-frame refresh +-- (iterates every equipment slot, scans tooltips for durability, walks buffs, +-- computes GearScore and repair costs). Vanilla WoW fires the events that +-- trigger it (UNIT_HEALTH, UNIT_MANA, UNIT_INVENTORY_CHANGED, PLAYER_MONEY, +-- etc.) in dense bursts — sometimes many per frame — which produces a +-- visible frame-time spike each time the panel is open. +-- +-- To fix that we split UpdateStats into two entry points: +-- * RelationshipsDashboard_UpdateStats() -> mark dirty, defer to next tick +-- * RelationshipsDashboard_UpdateStatsNow() -> run immediately (used when +-- the panel first opens so the +-- user never sees stale data) +-- +-- The OnUpdate handler flushes at most once per RD_UPDATE_THROTTLE seconds, +-- which collapses a whole burst of events into a single refresh. +------------------------------------------------------------------------------- +local RD_UPDATE_THROTTLE = 0.15; -- seconds between coalesced refreshes +RD_StatsDirty = false; +RD_StatsLastUpdate = 0; +RD_StatsAccum = 0; + +function RelationshipsDashboard_UpdateStatsNow() + RD_StatsDirty = false; + RD_StatsAccum = 0; + RelationshipsDashboard_UpdateStats_Impl(); +end + +function RelationshipsDashboard_UpdateStats() + if not RelationshipsDashboardFrame:IsVisible() then + return; + end + -- Defer: OnUpdate will flush this within RD_UPDATE_THROTTLE seconds. + RD_StatsDirty = true; +end + +function RelationshipsDashboard_FlushPendingStats(elapsed) + if not RD_StatsDirty then return; end + RD_StatsAccum = RD_StatsAccum + (elapsed or 0); + if RD_StatsAccum < RD_UPDATE_THROTTLE then return; end + RD_StatsAccum = 0; + RD_StatsDirty = false; + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats_Impl(); + end +end + +function RelationshipsDashboard_UpdateStats_Impl() + + if not RelationshipsDashboardFrame:IsVisible() then + return; + end + + -- Update title text to reflect the unit being displayed + if RelationshipsDashboardTitleText then + local uName = UnitName(RD_UNIT); + if RD_UNIT == "player" or not uName or uName == "" then + RelationshipsDashboardTitleText:SetText("Character Dashboard"); + else + local _, uClass = UnitClass(RD_UNIT); + local uLevel = UnitLevel(RD_UNIT); + local lvlStr = (uLevel and uLevel > 0) and (" (Lvl " .. uLevel .. ")") or ""; + RelationshipsDashboardTitleText:SetText(uName .. lvlStr .. (uClass and (" - " .. uClass) or "")); + end + end + + -- When inspecting another player, the client does not expose their computed + -- stats. Estimate everything from their equipped gear + level instead. + if RD_UNIT ~= "player" then + RelationshipsDashboard_UpdateStatsInspect(); + return; + end + + -- ==== Section: General ==== + -- Health + local health = UnitHealth(RD_UNIT); + local maxHealth = UnitHealthMax(RD_UNIT); + if maxHealth > 0 then + RelationshipsDashboardHealthRowValue:SetText(health .. " / " .. maxHealth); + else + RelationshipsDashboardHealthRowValue:SetText("--"); + end + RelationshipsDashboardHealthRowValue:SetTextColor(0.2, 1, 0.2); + + -- Power (Mana/Rage/Energy) + -- When a mana-capable class is in a non-mana form (e.g., druid bear/cat), + -- PowerRow shows the form's power (Rage/Energy), and ManaRow shows base Mana. + local powerType = UnitPowerType(RD_UNIT); + local power = UnitMana(RD_UNIT); + local maxPower = UnitManaMax(RD_UNIT); + local classUsesMana = RelationshipsDashboard_ClassUsesMana(); + + -- Track mana values when in caster form for use when shifted + if powerType == 0 then + -- Currently in caster form with mana bar visible + RelationshipsDashboard_LastKnownMana = power; + RelationshipsDashboard_LastKnownMaxMana = maxPower; + end + + if powerType == 1 then + RelationshipsDashboardPowerRowLabel:SetText("Rage:"); + RelationshipsDashboardPowerRowValue:SetText(power .. " / " .. maxPower); + RelationshipsDashboardPowerRowValue:SetTextColor(1, 0.2, 0.2); + elseif powerType == 2 then + RelationshipsDashboardPowerRowLabel:SetText("Focus:"); + RelationshipsDashboardPowerRowValue:SetText(power .. " / " .. maxPower); + RelationshipsDashboardPowerRowValue:SetTextColor(1, 0.8, 0); + elseif powerType == 3 then + RelationshipsDashboardPowerRowLabel:SetText("Energy:"); + RelationshipsDashboardPowerRowValue:SetText(power .. " / " .. maxPower); + RelationshipsDashboardPowerRowValue:SetTextColor(1, 1, 0); + else + RelationshipsDashboardPowerRowLabel:SetText("Mana:"); + if maxPower > 0 then + RelationshipsDashboardPowerRowValue:SetText(power .. " / " .. maxPower); + else + RelationshipsDashboardPowerRowValue:SetText("--"); + end + RelationshipsDashboardPowerRowValue:SetTextColor(0.3, 0.6, 1); + end + + -- ManaRow: Show base mana for mana-capable classes in non-mana forms + -- (e.g., druid in bear/cat form shows Rage/Energy on PowerRow + Mana on ManaRow) + -- When already in caster form, ManaRow is hidden by ApplyClassVisibility + if classUsesMana and powerType ~= 0 then + local mana = RelationshipsDashboard_LastKnownMana or 0; + local maxMana = RelationshipsDashboard_LastKnownMaxMana or 0; + -- Try to get current mana directly (some vanilla clients allow this) + -- UnitMana with powerType 0 doesn't work when shifted, so use stored values + RelationshipsDashboardManaRowLabel:SetText("Mana:"); + if maxMana > 0 then + RelationshipsDashboardManaRowValue:SetText(mana .. " / " .. maxMana); + else + RelationshipsDashboardManaRowValue:SetText("--"); + end + RelationshipsDashboardManaRowValue:SetTextColor(0.3, 0.6, 1); + end + + -- Armor + local baseArmor, effectiveArmor, armorBonus, posBuff, negBuff = UnitArmor(RD_UNIT); + if effectiveArmor then + if armorBonus and armorBonus ~= 0 then + RelationshipsDashboardArmorRowValue:SetText(effectiveArmor .. " (+" .. armorBonus .. ")"); + else + RelationshipsDashboardArmorRowValue:SetText(tostring(effectiveArmor)); + end + elseif baseArmor then + RelationshipsDashboardArmorRowValue:SetText(tostring(baseArmor)); + else + RelationshipsDashboardArmorRowValue:SetText("--"); + end + + -- Movement Speed + -- GetUnitSpeed() does NOT exist in vanilla 1.12 / TurtleWoW / OctoWoW + -- Calculate movement speed from known speed-boosting buffs instead + local speedPct = 100; -- Base run speed = 7 yards/sec = 100% + local _, playerClass = UnitClass(RD_UNIT); + + -- Check for speed-increasing buffs by spell name + -- Ghost Wolf (Shaman): 40% bonus = 140% + -- Aspect of the Cheetah (Hunter): 30% bonus = 130% + -- Aspect of the Pack (Hunter): 30% bonus = 130% + -- Sprint (Rogue): 70% bonus = 170% + -- Dash (Druid cat): 70% bonus = 170% + -- Travel Form (Druid): 40% bonus = 140% + -- Cheeta (Druid travel): 40% bonus = 140% + -- Sprint (item/enchant): minor bonus + -- Swiftness potions: 50% bonus = 150% + -- Carrot on a Stick: 3% mounted bonus + -- Mithril Spurs: 4% mounted bonus + -- Riding enchant: 2% mounted bonus + -- Nifty Stopwatch: 5% bonus + + -- Check if mounted (mount speed varies by riding skill) + local isMounted = false; + for i = 1, 32 do + local texture, applications, spellName = UnitBuff(RD_UNIT, i); + if not texture then break; end + if spellName then + -- Mount detection + if strfind(spellName, "Mount") or strfind(spellName, "Steed") or + strfind(spellName, "Charger") or strfind(spellName, "Warhorse") or + strfind(spellName, "Kodo") or strfind(spellName, "Mechanostrider") or + strfind(spellName, "Ram") or strfind(spellName, "Tiger") or + strfind(spellName, "Wolf") or strfind(spellName, "Raptor") or + strfind(spellName, "Skeletal") or strfind(spellName, "Frostsaber") or + strfind(spellName, "Nightsaber") or strfind(spellName, "Horse") or + strfind(spellName, "Palomino") or strfind(spellName, "Pinto") or + strfind(spellName, "Stallion") or strfind(spellName, "Mare") then + isMounted = true; + speedPct = 160; -- Epic mount = 100% bonus (200% total = 160% of base run) + -- Check for standard vs epic mount: we can't easily distinguish + -- Default to showing 200% for epic mount speed + speedPct = 200; + break; + end + end + end + + if not isMounted then + -- Check for speed-boosting buffs + for i = 1, 32 do + local texture, applications, spellName = UnitBuff(RD_UNIT, i); + if not texture then break; end + if spellName then + -- Shaman: Ghost Wolf = 140% speed + if spellName == "Ghost Wolf" then speedPct = 140; break; end + -- Hunter: Aspect of the Cheetah/Pack = 130% speed + if spellName == "Aspect of the Cheetah" then speedPct = 130; break; end + if spellName == "Aspect of the Pack" then speedPct = 130; break; end + -- Rogue: Sprint = 170% speed + if spellName == "Sprint" then speedPct = 170; break; end + -- Druid: Travel Form / Swift Flight Form + if spellName == "Travel Form" then speedPct = 140; break; end + if spellName == "Dash" then speedPct = 170; break; end + if spellName == "Cat Form" then speedPct = 100; break; end + -- Swiftness Potion + if spellName == "Swiftness" then speedPct = 150; break; end + -- Nifty Stopwatch + if spellName == "Speed" then speedPct = 105; break; end + -- Any other speed buff (generic check) + if strfind(strlower(spellName), "sprint") then speedPct = 170; break; end + if strfind(strlower(spellName), "dash") then speedPct = 170; break; end + if strfind(strlower(spellName), "speed") then speedPct = 105; break; end + end + end + end + + RelationshipsDashboardMovementRowValue:SetText(string.format("%.0f%%", speedPct)); + + -- Durability + local avgDurability, repairCost, slotsWithDur = RelationshipsDashboard_CalculateDurabilityAndRepair(); + if RelationshipsDashboard_MerchantRepairCost > 0 then + -- At a repair merchant: show the exact cost the game charges. + repairCost = RelationshipsDashboard_MerchantRepairCost; + else + -- Away from a merchant: scale the raw estimate by the calibration factor + -- learned from the last real merchant repair cost so it matches reality. + repairCost = floor(repairCost * (RD_RepairCalibration or 1)); + end + local durText = RelationshipsDashboard_FormatPercent(avgDurability); + if avgDurability >= 75 then + RelationshipsDashboardDurabilityRowValue:SetTextColor(0.2, 1, 0.2); + elseif avgDurability >= 50 then + RelationshipsDashboardDurabilityRowValue:SetTextColor(1, 1, 0); + elseif avgDurability >= 25 then + RelationshipsDashboardDurabilityRowValue:SetTextColor(1, 0.5, 0); + else + RelationshipsDashboardDurabilityRowValue:SetTextColor(1, 0.2, 0.2); + end + RelationshipsDashboardDurabilityRowValue:SetText(durText); + + -- Repair Total + RelationshipsDashboardRepairCostRowValue:SetText(RelationshipsDashboard_FormatMoney(repairCost)); + + -- GearScore + local gearScore, avgILvl, equippedCount = RelationshipsDashboard_CalculateGearScore(); + if gearScore > 0 then + RelationshipsDashboardGearScoreRowValue:SetText(tostring(gearScore)); + else + RelationshipsDashboardGearScoreRowValue:SetText("--"); + end + if gearScore >= 3500 then + RelationshipsDashboardGearScoreRowValue:SetTextColor(1, 0.5, 0); + elseif gearScore >= 2000 then + RelationshipsDashboardGearScoreRowValue:SetTextColor(0.8, 0.2, 1); + elseif gearScore >= 1200 then + RelationshipsDashboardGearScoreRowValue:SetTextColor(0, 0.44, 0.87); + elseif gearScore >= 500 then + RelationshipsDashboardGearScoreRowValue:SetTextColor(0.12, 1, 0); + else + RelationshipsDashboardGearScoreRowValue:SetTextColor(1, 1, 1); + end + + -- Avg Item Level + if avgILvl > 0 then + RelationshipsDashboardAvgILvlRowValue:SetText(string.format("%.1f", avgILvl)); + else + RelationshipsDashboardAvgILvlRowValue:SetText("--"); + end + + -- ==== Section: Attributes ==== + -- UnitStat indices: 1=STR, 2=AGI, 3=STA, 4=INT, 5=SPI + local baseStr, effectiveStr = UnitStat(RD_UNIT, 1); + if effectiveStr then + local bonus = effectiveStr - baseStr; + if bonus ~= 0 then + RelationshipsDashboardStrengthRowValue:SetText(effectiveStr .. " (" .. baseStr .. " +" .. bonus .. ")"); + else + RelationshipsDashboardStrengthRowValue:SetText(tostring(effectiveStr)); + end + else + RelationshipsDashboardStrengthRowValue:SetText(tostring(baseStr)); + end + + local baseAgi, effectiveAgi = UnitStat(RD_UNIT, 2); + if effectiveAgi then + local bonus = effectiveAgi - baseAgi; + if bonus ~= 0 then + RelationshipsDashboardAgilityRowValue:SetText(effectiveAgi .. " (" .. baseAgi .. " +" .. bonus .. ")"); + else + RelationshipsDashboardAgilityRowValue:SetText(tostring(effectiveAgi)); + end + else + RelationshipsDashboardAgilityRowValue:SetText(tostring(baseAgi)); + end + + local baseSta, effectiveSta = UnitStat(RD_UNIT, 3); + if effectiveSta then + local bonus = effectiveSta - baseSta; + if bonus ~= 0 then + RelationshipsDashboardStaminaRowValue:SetText(effectiveSta .. " (" .. baseSta .. " +" .. bonus .. ")"); + else + RelationshipsDashboardStaminaRowValue:SetText(tostring(effectiveSta)); + end + else + RelationshipsDashboardStaminaRowValue:SetText(tostring(baseSta)); + end + + local baseInt, effectiveInt = UnitStat(RD_UNIT, 4); + if effectiveInt then + local bonus = effectiveInt - baseInt; + if bonus ~= 0 then + RelationshipsDashboardIntellectRowValue:SetText(effectiveInt .. " (" .. baseInt .. " +" .. bonus .. ")"); + else + RelationshipsDashboardIntellectRowValue:SetText(tostring(effectiveInt)); + end + else + RelationshipsDashboardIntellectRowValue:SetText(tostring(baseInt)); + end + + local baseSpi, effectiveSpi = UnitStat(RD_UNIT, 5); + if effectiveSpi then + local bonus = effectiveSpi - baseSpi; + if bonus ~= 0 then + RelationshipsDashboardSpiritRowValue:SetText(effectiveSpi .. " (" .. baseSpi .. " +" .. bonus .. ")"); + else + RelationshipsDashboardSpiritRowValue:SetText(tostring(effectiveSpi)); + end + else + RelationshipsDashboardSpiritRowValue:SetText(tostring(baseSpi)); + end + + -- ==== Section: Offense ==== + -- Damage (first in DejaStats Offense section) + local minDamage, maxDamage, minOff, maxOff, posBuffDmg, negBuffDmg = UnitDamage(RD_UNIT); + if minDamage and maxDamage then + local effectiveMin = minDamage + (posBuffDmg or 0) + (negBuffDmg or 0); + local effectiveMax = maxDamage + (posBuffDmg or 0) + (negBuffDmg or 0); + local dmgText = floor(effectiveMin) .. " - " .. floor(effectiveMax); + if minOff and maxOff and minOff > 0 then + local effectiveMinOff = minOff + (posBuffDmg or 0) + (negBuffDmg or 0); + local effectiveMaxOff = maxOff + (posBuffDmg or 0) + (negBuffDmg or 0); + dmgText = dmgText .. " / " .. floor(effectiveMinOff) .. " - " .. floor(effectiveMaxOff); + end + RelationshipsDashboardMeleeDmgRowValue:SetText(dmgText); + else + RelationshipsDashboardMeleeDmgRowValue:SetText("--"); + end + + -- Attack Power + local baseAP, posBuffAP, negBuffAP = UnitAttackPower(RD_UNIT); + if baseAP then + local totalAP = baseAP + (posBuffAP or 0) + (negBuffAP or 0); + local apBonus = (posBuffAP or 0) + (negBuffAP or 0); + if apBonus ~= 0 then + RelationshipsDashboardMeleeAPRowValue:SetText(totalAP .. " (+" .. apBonus .. ")"); + else + RelationshipsDashboardMeleeAPRowValue:SetText(tostring(totalAP)); + end + else + RelationshipsDashboardMeleeAPRowValue:SetText("--"); + end + + -- Attack Speed + local mainSpeed, offSpeed = UnitAttackSpeed(RD_UNIT); + if mainSpeed then + if offSpeed and offSpeed > 0 then + RelationshipsDashboardMeleeSpeedRowValue:SetText(RelationshipsDashboard_FormatDecimal(mainSpeed) .. " / " .. RelationshipsDashboard_FormatDecimal(offSpeed)); + else + RelationshipsDashboardMeleeSpeedRowValue:SetText(RelationshipsDashboard_FormatDecimal(mainSpeed)); + end + else + RelationshipsDashboardMeleeSpeedRowValue:SetText("--"); + end + + -- Weapon DPS + if mainSpeed and minDamage and maxDamage then + local effectiveMin = minDamage + (posBuffDmg or 0) + (negBuffDmg or 0); + local effectiveMax = maxDamage + (posBuffDmg or 0) + (negBuffDmg or 0); + local avgDmg = (effectiveMin + effectiveMax) / 2; + local weaponDPS = avgDmg / mainSpeed; + RelationshipsDashboardWeaponDPSRowValue:SetText(string.format("%.2f", weaponDPS)); + else + RelationshipsDashboardWeaponDPSRowValue:SetText("--"); + end + + -- Weapon Skill + RelationshipsDashboardWeaponSkillRowValue:SetText(RelationshipsDashboard_GetWeaponSkill()); + + -- Hit Chance + local meleeHit = RelationshipsDashboard_GetMeleeHitChance(); + RelationshipsDashboardMeleeHitRowValue:SetText(RelationshipsDashboard_FormatPercent(meleeHit)); + + -- Crit Chance + local meleeCrit = RelationshipsDashboard_GetMeleeCritChance(); + RelationshipsDashboardMeleeCritRowValue:SetText(RelationshipsDashboard_FormatPercent(meleeCrit)); + + -- ==== Section: Enhancements ==== + -- Ranged Attack Power + local baseRAP, posBuffRAP, negBuffRAP = UnitRangedAttackPower(RD_UNIT); + if baseRAP then + local totalRAP = baseRAP + (posBuffRAP or 0) + (negBuffRAP or 0); + RelationshipsDashboardRangedAPRowValue:SetText(tostring(totalRAP)); + else + RelationshipsDashboardRangedAPRowValue:SetText("--"); + end + + -- Ranged Crit + local rangedCrit = RelationshipsDashboard_GetRangedCritChance(); + RelationshipsDashboardRangedCritRowValue:SetText(RelationshipsDashboard_FormatPercent(rangedCrit)); + + -- Ranged Speed + -- UnitRangedDamage does NOT exist in vanilla 1.12 + -- Get ranged attack speed from the equipped ranged weapon's tooltip + local rangedSpeedVal = nil; + local rangedItemLink = GetInventoryItemLink(RD_UNIT, 18); + if rangedItemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + local ok, err = pcall(function() RelationshipsDashboardTooltip:SetInventoryItem(RD_UNIT, 18); end); + if ok then + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + -- Match weapon speed pattern: "Speed XX.XX" + local _, _, spd = strfind(text, "Speed (%d+%.%d+)"); + if spd then + rangedSpeedVal = tonumber(spd); + break; + end + end + end + end + end + end + if rangedSpeedVal then + RelationshipsDashboardRangedSpeedRowValue:SetText(RelationshipsDashboard_FormatDecimal(rangedSpeedVal)); + else + RelationshipsDashboardRangedSpeedRowValue:SetText("--"); + end + + -- Ranged Damage + local rangedItemLink = GetInventoryItemLink(RD_UNIT, 18); + if rangedItemLink and RelationshipsDashboardTooltip then + RelationshipsDashboard_ResetTooltip(); + RelationshipsDashboardTooltip_SetInventoryItemSafe(RD_UNIT, 18); + for i = 1, RelationshipsDashboardTooltip:NumLines() do + local textLine = getglobal("RelationshipsDashboardTooltipTextLeft" .. i); + if textLine then + local text = textLine:GetText(); + if text then + local _, _, dMin, dMax = strfind(text, "(%d+)%s*-%s*(%d+)%s+Damage"); + if dMin and dMax then + RelationshipsDashboardRangedDmgRowValue:SetText(dMin .. " - " .. dMax); + break; + end + end + end + end + else + RelationshipsDashboardRangedDmgRowValue:SetText("--"); + end + + -- Spell Power + local spellPower = RelationshipsDashboard_GetSpellPower(); + RelationshipsDashboardSpellPowerRowValue:SetText(tostring(spellPower)); + + -- Healing Power + local healingPower = RelationshipsDashboard_GetHealingPower(); + RelationshipsDashboardHealingPowerRowValue:SetText(tostring(healingPower)); + + -- Spell Hit + local spellHit = RelationshipsDashboard_GetSpellHitChance(); + RelationshipsDashboardSpellHitRowValue:SetText(RelationshipsDashboard_FormatPercent(spellHit)); + + -- Spell Crit + local spellCrit = RelationshipsDashboard_GetSpellCritChance(); + RelationshipsDashboardSpellCritRowValue:SetText(RelationshipsDashboard_FormatPercent(spellCrit)); + + -- Mana Regen + local manaRegen = RelationshipsDashboard_GetManaRegen(); + if manaRegen > 0 then + RelationshipsDashboardManaRegenRowValue:SetText(string.format("%.1f/s", manaRegen)); + else + RelationshipsDashboardManaRegenRowValue:SetText("--"); + end + + -- ==== Section: Defenses ==== + -- Defense + local defense = RelationshipsDashboard_GetDefense(); + RelationshipsDashboardDefenseRowValue:SetText(tostring(defense)); + + -- Dodge + if GetDodgeChance then + RelationshipsDashboardDodgeRowValue:SetText(RelationshipsDashboard_FormatPercent(GetDodgeChance())); + else + RelationshipsDashboardDodgeRowValue:SetText("--"); + end + + -- Parry + local parryChance = RelationshipsDashboard_GetParryChance(); + RelationshipsDashboardParryRowValue:SetText(RelationshipsDashboard_FormatPercent(parryChance)); + + -- Block + local blockChance = RelationshipsDashboard_GetBlockChance(); + RelationshipsDashboardBlockRowValue:SetText(RelationshipsDashboard_FormatPercent(blockChance)); + + -- Avoidance (Dodge + Parry + Block + Miss chance) + local missChance = 5; + local level = UnitLevel(RD_UNIT); + local defenseSkill = defense or (level * 5); + if defenseSkill > level * 5 then + missChance = 5 + (defenseSkill - level * 5) * 0.04; + end + local dodgeChance = (GetDodgeChance and GetDodgeChance()) or 0; + local avoidance = missChance + dodgeChance + parryChance + blockChance; + RelationshipsDashboardAvoidanceRowValue:SetText(RelationshipsDashboard_FormatPercent(avoidance)); + + -- ==== Section: Resistances ==== + -- Resistance indices: 1=Holy, 2=Fire, 3=Nature, 4=Frost, 5=Shadow, 6=Arcane + local resBase, resTotal, resBonus, resPos, resNeg; + + -- Arcane (index 6) + resBase, resTotal, resBonus, resPos, resNeg = UnitResistance(RD_UNIT, RESISTANCE_INDICES.arcane); + RelationshipsDashboardArcaneResRowValue:SetText(tostring(resTotal or 0)); + + -- Fire (index 2) + resBase, resTotal, resBonus, resPos, resNeg = UnitResistance(RD_UNIT, RESISTANCE_INDICES.fire); + RelationshipsDashboardFireResRowValue:SetText(tostring(resTotal or 0)); + + -- Nature (index 3) + resBase, resTotal, resBonus, resPos, resNeg = UnitResistance(RD_UNIT, RESISTANCE_INDICES.nature); + RelationshipsDashboardNatureResRowValue:SetText(tostring(resTotal or 0)); + + -- Frost (index 4) + resBase, resTotal, resBonus, resPos, resNeg = UnitResistance(RD_UNIT, RESISTANCE_INDICES.frost); + RelationshipsDashboardFrostResRowValue:SetText(tostring(resTotal or 0)); + + -- Shadow (index 5) + resBase, resTotal, resBonus, resPos, resNeg = UnitResistance(RD_UNIT, RESISTANCE_INDICES.shadow); + RelationshipsDashboardShadowResRowValue:SetText(tostring(resTotal or 0)); + + -- ==== Apply class-specific visibility (hide irrelevant stats) ==== + RelationshipsDashboard_ApplyClassVisibility(); +end + +------------------------------------------------------------------------------- +-- Show/Hide Logic +-- Toggle the stats frame visibility with the CharacterFrame +------------------------------------------------------------------------------- +local function RelationshipsDashboard_ToggleVisibility() + if CharacterFrame:IsVisible() then + RelationshipsDashboardFrame:Show(); + RelationshipsDashboard_UpdateStatsNow(); + + else + RelationshipsDashboardFrame:Hide(); + end +end + +------------------------------------------------------------------------------- +-- Hook into CharacterFrame show/hide +-- NOTE: HookScript() does NOT exist in vanilla 1.12 (added in TBC 2.1.0) +-- hooksecurefunc() does NOT exist either (added in TBC 2.0) +-- We must override the Show/Hide methods directly and call the originals. +-- Lua 5.0 uses unpack(arg) instead of ... for varargs in some contexts, +-- but function(...) works fine in Lua 5.0 as long as we forward args correctly. +------------------------------------------------------------------------------- +local RelationshipsDashboard_CharacterFrameHooked = false; + +local function RelationshipsDashboard_HookCharacterFrame() + if CharacterFrame and not RelationshipsDashboard_CharacterFrameHooked then + RelationshipsDashboard_CharacterFrameHooked = true; + + -- Override CharacterFrame.Show to also show our stats panel + local origShow = CharacterFrame.Show; + CharacterFrame.Show = function(...) + origShow(unpack(arg)); + RelationshipsDashboardFrame:Show(); + RelationshipsDashboard_UpdateStatsNow(); + + end; + + -- Override CharacterFrame.Hide to also hide our stats panel + local origHide = CharacterFrame.Hide; + CharacterFrame.Hide = function(...) + origHide(unpack(arg)); + RelationshipsDashboardFrame:Hide(); + end; + end +end + +------------------------------------------------------------------------------- +-- Hook InspectFrame so that inspecting another player also opens this +-- dashboard and shows THEIR stats (via unit "target"). When the inspect +-- window closes we revert RD_UNIT back to "player". +------------------------------------------------------------------------------- +local RelationshipsDashboard_InspectFrameHooked = false; + +------------------------------------------------------------------------------- +-- Force the scroll viewport mask frames to a very high frame level so they +-- always draw ON TOP of the stat-row sub-frames inside the ScrollChild. +-- Must be re-applied whenever we change RelationshipsDashboardFrame's parent +-- or frame level (e.g. when hooking InspectFrame), because vanilla 1.12 +-- cascades frame level changes down to child frames. +------------------------------------------------------------------------------- +function RelationshipsDashboard_BoostMaskLevels() + local base = RelationshipsDashboardFrame:GetFrameLevel() or 2; + local contentLevel = base + 10; + local target = base + 100; + + if RelationshipsDashboardScrollFrame then + RelationshipsDashboardScrollFrame:SetFrameLevel(contentLevel); + end + if RelationshipsDashboardContent then + RelationshipsDashboardContent:SetFrameLevel(contentLevel + 1); + end + RelationshipsDashboard_ForEachScrollElement(function(element) + element:SetFrameLevel(contentLevel + 2); + end); + + if RelationshipsDashboardMaskTop then + RelationshipsDashboardMaskTop:SetFrameLevel(target); + end + if RelationshipsDashboardMaskBottom then + RelationshipsDashboardMaskBottom:SetFrameLevel(target); + end +end + + +function RelationshipsDashboard_TryHookInspectFrame() + if RelationshipsDashboard_InspectFrameHooked then return; end + if not InspectFrame then return; end + RelationshipsDashboard_InspectFrameHooked = true; + + local origShow = InspectFrame.Show; + InspectFrame.Show = function(...) + origShow(unpack(arg)); + -- Switch to inspect target + RD_UNIT = "target"; + if UnitExists("target") and UnitIsPlayer("target") then + -- IMPORTANT: parent to UIParent, NOT InspectFrame. + -- InspectFrame has child sub-frames (PaperDoll, model) with high + -- framelevels that will draw above our BG texture if we are a + -- child of InspectFrame — that's what caused the "text bleeding + -- through / scrolling through the inspect UI" bug. + RelationshipsDashboardFrame:SetParent(UIParent); + RelationshipsDashboardFrame:ClearAllPoints(); + -- Match the self (CharacterFrame) dashboard position: sit just off + -- the frame's right edge with the same -30 overlap offset so the + -- inspect dashboard lines up exactly like the personal one. + RelationshipsDashboardFrame:SetPoint("TOPLEFT", InspectFrame, "TOPRIGHT", -30, -16); + RelationshipsDashboardFrame:SetFrameStrata("HIGH"); + RelationshipsDashboardFrame:SetFrameLevel(20); + RelationshipsDashboard_BoostMaskLevels(); + RelationshipsDashboardFrame:Show(); + RelationshipsDashboard_ApplyClassVisibility(); + RelationshipsDashboard_UpdateStats(); + end + end; + + local origHide = InspectFrame.Hide; + InspectFrame.Hide = function(...) + origHide(unpack(arg)); + -- Restore player context and re-parent to CharacterFrame with the + -- original overlapping anchor (CharacterFrame's right edge is empty + -- border, so overlap is safe there). + RD_UNIT = "player"; + RelationshipsDashboardFrame:Hide(); + RelationshipsDashboardFrame:SetParent(CharacterFrame); + RelationshipsDashboardFrame:ClearAllPoints(); + RelationshipsDashboardFrame:SetPoint("TOPLEFT", CharacterFrame, "TOPRIGHT", -30, -16); + RelationshipsDashboardFrame:SetFrameStrata("MEDIUM"); + RelationshipsDashboardFrame:SetFrameLevel(2); + RelationshipsDashboard_BoostMaskLevels(); + if CharacterFrame:IsVisible() then + RelationshipsDashboardFrame:Show(); + RelationshipsDashboard_ApplyClassVisibility(); + RelationshipsDashboard_UpdateStats(); + end + end; +end + +------------------------------------------------------------------------------- +-- OnLoad - Initialize the addon +------------------------------------------------------------------------------- +function RelationshipsDashboard_OnLoad() + -- Create the tooltip scanner (hidden, used for data extraction) + RelationshipsDashboardTooltip = CreateFrame("GameTooltip", "RelationshipsDashboardTooltip", nil, "GameTooltipTemplate"); + RelationshipsDashboardTooltip:SetOwner(WorldFrame, "ANCHOR_NONE"); + + -- Initialize section header text (DejaStats-style gold section headers) + RDHeaderGeneralText:SetText("General"); + RDHeaderAttributesText:SetText("Attributes"); + RDHeaderOffenseText:SetText("Offense"); + RDHeaderEnhancementsText:SetText("Enhancements"); + RDHeaderDefensesText:SetText("Defenses"); + RDHeaderResistancesText:SetText("Resistances"); + + -- Initialize stat row labels matching DejaStats layout + -- Section: General + RelationshipsDashboardHealthRowLabel:SetText("Health:"); + RelationshipsDashboardPowerRowLabel:SetText("Mana:"); + RelationshipsDashboardManaRowLabel:SetText("Mana:"); + RelationshipsDashboardArmorRowLabel:SetText("Armor:"); + RelationshipsDashboardMovementRowLabel:SetText("Movement Speed:"); + RelationshipsDashboardDurabilityRowLabel:SetText("Durability:"); + RelationshipsDashboardRepairCostRowLabel:SetText("Repair Total:"); + RelationshipsDashboardRepairCostRowValue:SetTextColor(1, 0.2, 0.2); + RelationshipsDashboardGearScoreRowLabel:SetText("GearScore:"); + RelationshipsDashboardAvgILvlRowLabel:SetText("Avg Item Level:"); + + -- Section: Attributes + RelationshipsDashboardStrengthRowLabel:SetText("Strength:"); + RelationshipsDashboardAgilityRowLabel:SetText("Agility:"); + RelationshipsDashboardStaminaRowLabel:SetText("Stamina:"); + RelationshipsDashboardIntellectRowLabel:SetText("Intellect:"); + RelationshipsDashboardSpiritRowLabel:SetText("Spirit:"); + + -- Section: Offense + RelationshipsDashboardMeleeDmgRowLabel:SetText("Damage:"); + RelationshipsDashboardMeleeAPRowLabel:SetText("Attack Power:"); + RelationshipsDashboardMeleeSpeedRowLabel:SetText("Attack Speed:"); + RelationshipsDashboardWeaponDPSRowLabel:SetText("Weapon DPS:"); + RelationshipsDashboardWeaponSkillRowLabel:SetText("Weapon Skill:"); + RelationshipsDashboardMeleeHitRowLabel:SetText("Hit Chance:"); + RelationshipsDashboardMeleeCritRowLabel:SetText("Crit Chance:"); + + -- Section: Enhancements + RelationshipsDashboardRangedAPRowLabel:SetText("Ranged AP:"); + RelationshipsDashboardRangedCritRowLabel:SetText("Ranged Crit:"); + RelationshipsDashboardRangedSpeedRowLabel:SetText("Ranged Speed:"); + RelationshipsDashboardRangedDmgRowLabel:SetText("Ranged Damage:"); + RelationshipsDashboardSpellPowerRowLabel:SetText("Spell Power:"); + RelationshipsDashboardHealingPowerRowLabel:SetText("Healing Power:"); + RelationshipsDashboardSpellHitRowLabel:SetText("Spell Hit:"); + RelationshipsDashboardSpellCritRowLabel:SetText("Spell Crit:"); + RelationshipsDashboardManaRegenRowLabel:SetText("Mana Regen:"); + + -- Section: Defenses + RelationshipsDashboardDefenseRowLabel:SetText("Defense:"); + RelationshipsDashboardDodgeRowLabel:SetText("Dodge:"); + RelationshipsDashboardParryRowLabel:SetText("Parry:"); + RelationshipsDashboardBlockRowLabel:SetText("Block:"); + RelationshipsDashboardAvoidanceRowLabel:SetText("Avoidance:"); + RelationshipsDashboardAvoidanceRowValue:SetTextColor(0.2, 1, 0.2); + + -- Section: Resistances (school-colored labels) + RelationshipsDashboardArcaneResRowLabel:SetText("Arcane:"); + RelationshipsDashboardFireResRowLabel:SetText("Fire:"); + RelationshipsDashboardNatureResRowLabel:SetText("Nature:"); + RelationshipsDashboardFrostResRowLabel:SetText("Frost:"); + RelationshipsDashboardShadowResRowLabel:SetText("Shadow:"); + + -- Resistance label color overrides (school colors matching DejaStats) + RelationshipsDashboardArcaneResRowLabel:SetTextColor(0.7, 0.2, 1); -- Arcane (purple) + RelationshipsDashboardFireResRowLabel:SetTextColor(1, 0.4, 0.1); -- Fire (red-orange) + RelationshipsDashboardNatureResRowLabel:SetTextColor(0.2, 0.9, 0.2); -- Nature (green) + RelationshipsDashboardFrostResRowLabel:SetTextColor(0.3, 0.6, 1); -- Frost (blue) + RelationshipsDashboardShadowResRowLabel:SetTextColor(0.6, 0.2, 0.8); -- Shadow (violet) + + -- Power label override: update based on class power type at load + -- This will be refined on each UpdateStats call + local powerType = UnitPowerType("player"); + if powerType == 1 then + RelationshipsDashboardPowerRowLabel:SetText("Rage:"); + elseif powerType == 2 then + RelationshipsDashboardPowerRowLabel:SetText("Focus:"); + elseif powerType == 3 then + RelationshipsDashboardPowerRowLabel:SetText("Energy:"); + else + RelationshipsDashboardPowerRowLabel:SetText("Mana:"); + end + + -- Register for events + local frame = RelationshipsDashboardFrame; + frame:RegisterEvent("UNIT_STATS"); + frame:RegisterEvent("UNIT_ATTACK_POWER"); + frame:RegisterEvent("UNIT_RANGED_ATTACK_POWER"); + frame:RegisterEvent("UNIT_ATTACK_SPEED"); + frame:RegisterEvent("UNIT_RESISTANCES"); + frame:RegisterEvent("UNIT_DEFENSE"); + frame:RegisterEvent("UNIT_DAMAGE"); + frame:RegisterEvent("UPDATE_INVENTORY_ALERTS"); + frame:RegisterEvent("UNIT_INVENTORY_CHANGED"); + frame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED"); + frame:RegisterEvent("UNIT_MODEL_CHANGED"); + frame:RegisterEvent("PLAYER_ENTERING_WORLD"); + frame:RegisterEvent("PLAYER_MONEY"); + frame:RegisterEvent("UPDATE_TOOLTIP"); + frame:RegisterEvent("MERCHANT_SHOW"); + frame:RegisterEvent("MERCHANT_UPDATE"); + frame:RegisterEvent("MERCHANT_CLOSED"); + frame:RegisterEvent("UNIT_DISPLAYPOWER"); + frame:RegisterEvent("UNIT_MANA"); + frame:RegisterEvent("UNIT_RAGE"); + frame:RegisterEvent("UNIT_ENERGY"); + frame:RegisterEvent("UNIT_FOCUS"); + frame:RegisterEvent("UNIT_HEALTH"); + frame:RegisterEvent("PLAYER_DEAD"); + frame:RegisterEvent("PLAYER_REGEN_DISABLED"); + frame:RegisterEvent("PLAYER_REGEN_ENABLED"); + frame:RegisterEvent("ZONE_CHANGED_NEW_AREA"); + frame:RegisterEvent("ZONE_CHANGED"); + frame:RegisterEvent("UNIT_MAXHEALTH"); + frame:RegisterEvent("UNIT_MAXMANA"); + frame:RegisterEvent("UNIT_MAXRAGE"); + frame:RegisterEvent("UNIT_MAXENERGY"); + frame:RegisterEvent("UNIT_MAXFOCUS"); + frame:RegisterEvent("ADDON_LOADED"); + frame:RegisterEvent("VARIABLES_LOADED"); + frame:RegisterEvent("PLAYER_TARGET_CHANGED"); + frame:RegisterEvent("PLAYER_UNGHOST"); -- Player is no longer a ghost (rez'd) + frame:RegisterEvent("PLAYER_ALIVE"); -- Fires on both corpse-run and SH rez + frame:RegisterEvent("CORPSE_IN_RANGE"); -- Near own corpse (retrieval possible) + frame:RegisterEvent("CORPSE_OUT_OF_RANGE"); + -- Explicitly flush the saved-durability table back to its SavedVariable + -- global on logout / /reload. WoW normally handles this automatically, + -- but this safety net protects against the reference being unhooked by + -- any future edit that reassigns RD_SavedDurability locally. + frame:RegisterEvent("DUEL_REQUESTED"); + frame:RegisterEvent("DUEL_FINISHED"); + frame:RegisterEvent("PLAYER_LOGOUT"); + + + + -- Hide the scrollbar and ALL its sub-elements for a flat UI + -- UIPanelScrollFrameTemplate (WoW 1.12) creates $parentScrollBar (a Slider) with: + -- $parentScrollUpButton (Button: NormalTexture, PushedTexture, DisabledTexture, HighlightTexture) + -- $parentScrollDownButton (Button: NormalTexture, PushedTexture, DisabledTexture, HighlightTexture) + -- $parentThumbTexture (Texture inheriting UIPanelScrollBarButton) + -- We hide AND set alpha=0 on every element to guarantee nothing is visible + local scrollBar = getglobal("RelationshipsDashboardScrollFrameScrollBar"); + if scrollBar then + scrollBar:Hide(); + scrollBar:SetAlpha(0); + + -- Hide and make transparent the up/down arrow buttons and all their texture states + local scrollUp = getglobal("RelationshipsDashboardScrollFrameScrollBarScrollUpButton"); + local scrollDown = getglobal("RelationshipsDashboardScrollFrameScrollBarScrollDownButton"); + if scrollUp then + scrollUp:Hide(); + scrollUp:SetAlpha(0); + -- Hide each texture state on the Up button + local tex; + tex = scrollUp:GetNormalTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + tex = scrollUp:GetPushedTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + tex = scrollUp:GetDisabledTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + tex = scrollUp:GetHighlightTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + end + if scrollDown then + scrollDown:Hide(); + scrollDown:SetAlpha(0); + -- Hide each texture state on the Down button + local tex; + tex = scrollDown:GetNormalTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + tex = scrollDown:GetPushedTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + tex = scrollDown:GetDisabledTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + tex = scrollDown:GetHighlightTexture(); if tex then tex:SetAlpha(0); tex:Hide(); end + end + + -- Hide and make transparent the thumb (the draggable block in the scrollbar) + -- In WoW 1.12, ThumbTexture is a single Texture (no Left/Right/Middle sub-textures) + local thumb = getglobal("RelationshipsDashboardScrollFrameScrollBarThumbTexture"); + if thumb then + thumb:SetAlpha(0); + thumb:Hide(); + end + end + + -- Enable mouse wheel scrolling on the scroll frame + -- The ScrollFrame doesn't natively handle mouse wheel, so we add it + local scrollFrame = RelationshipsDashboardScrollFrame; + scrollFrame:EnableMouseWheel(true); + scrollFrame:SetScript("OnMouseWheel", function() + -- In WoW 1.12 Lua 5.0, arg1 contains the scroll delta + -- Positive = scroll up, Negative = scroll down + local delta = arg1; + local scrollBar = getglobal("RelationshipsDashboardScrollFrameScrollBar"); + if scrollBar then + local minVal, maxVal = scrollBar:GetMinMaxValues(); + local current = scrollBar:GetValue(); + local step = 30; -- pixels per scroll step + if delta > 0 then + -- Scroll up + if current - step < minVal then + scrollBar:SetValue(minVal); + else + scrollBar:SetValue(current - step); + end + else + -- Scroll down + if current + step > maxVal then + scrollBar:SetValue(maxVal); + else + scrollBar:SetValue(current + step); + end + end + RelationshipsDashboard_UpdateViewportClip(); + end + end); + + frame:SetScript("OnUpdate", function() + -- Vanilla 1.12 passes elapsed via arg1 (Lua 5.0 has no `...` here). + local elapsed = arg1 or 0; + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateViewportClip(); + -- Flush any pending coalesced stat refresh (throttled). + RelationshipsDashboard_FlushPendingStats(elapsed); + end + -- Detect ghost-state transitions (spirit-release → ghost, or rez → + -- alive) as they happen, so the durability % and estimated repair + -- cost update the moment the player becomes a ghost instead of + -- waiting until they respawn / a later event. + local isGhostNow = (UnitIsGhost and UnitIsGhost("player")) and true or false; + if RD_GhostStateLast == nil then + RD_GhostStateLast = isGhostNow; + elseif isGhostNow ~= RD_GhostStateLast then + RD_GhostStateLast = isGhostNow; + if isGhostNow then + -- Player just released and became a ghost. The 10% death + -- durability penalty is normally applied on PLAYER_DEAD, but + -- guard against a missed application (e.g. PLAYER_DEAD arrived + -- before saved-durability baselines existed). + if not RD_DeathPenaltyApplied then + RelationshipsDashboard_ApplyDeathPenalty(); + RD_DeathPenaltyApplied = true; + end + RD_WasGhost = true; + else + RD_DeathPenaltyApplied = false; + end + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + end + end); + + + -- Ensure the scroll-viewport masks always draw above the stat row sub-frames + -- inside the ScrollChild. Vanilla ScrollFrame does NOT clip nested child + -- frames, so without these masks the row FontStrings render outside the + -- scroll area when scrolled. See RelationshipsDashboard.xml for details. + RelationshipsDashboard_BoostMaskLevels(); + + -- Hook into CharacterFrame + RelationshipsDashboard_HookCharacterFrame(); RelationshipsDashboard_TryHookInspectFrame(); + + -- Initialize saved variables + if not RelationshipsDashboardDB then + RelationshipsDashboardDB = {}; + end + + -- Initial update (will run when CharacterFrame opens) + -- The frame starts hidden, so we don't update immediately +end + +------------------------------------------------------------------------------- +-- OnEvent - Handle registered events +------------------------------------------------------------------------------- +function RelationshipsDashboard_OnEvent(event) + if event == "ADDON_LOADED" then + if arg1 == "Blizzard_InspectUI" then + RelationshipsDashboard_TryHookInspectFrame(); + elseif arg1 == "RelationshipsDashboard" then + -- Bind the saved durability table so it persists across /reload + if RelationshipsDashboardDB_SavedDurability == nil then + RelationshipsDashboardDB_SavedDurability = {}; + end + RD_SavedDurability = RelationshipsDashboardDB_SavedDurability; + -- Restore the learned repair calibration factor. + if RelationshipsDashboardDB and RelationshipsDashboardDB.repairCalibration + and RelationshipsDashboardDB.repairCalibrationVersion == RD_REPAIR_CALIBRATION_VERSION then + RD_RepairCalibration = RelationshipsDashboardDB.repairCalibration; + else + RD_RepairCalibration = 1.0; + end + end + return; + elseif event == "VARIABLES_LOADED" then + if RelationshipsDashboardDB_SavedDurability == nil then + RelationshipsDashboardDB_SavedDurability = {}; + end + RD_SavedDurability = RelationshipsDashboardDB_SavedDurability; + if RelationshipsDashboardDB and RelationshipsDashboardDB.repairCalibration + and RelationshipsDashboardDB.repairCalibrationVersion == RD_REPAIR_CALIBRATION_VERSION then + RD_RepairCalibration = RelationshipsDashboardDB.repairCalibration; + else + RD_RepairCalibration = 1.0; + end + return; + elseif event == "PLAYER_LOGOUT" then + -- Guarantee the saved-durability table (and calibration) survive + -- /reload and full logout, even if some other code path reassigned + -- RD_SavedDurability to a fresh table after ADDON_LOADED. + if RD_SavedDurability then + RelationshipsDashboardDB_SavedDurability = RD_SavedDurability; + end + if RelationshipsDashboardDB and RD_RepairCalibration then + RelationshipsDashboardDB.repairCalibration = RD_RepairCalibration; + RelationshipsDashboardDB.repairCalibrationVersion = RD_REPAIR_CALIBRATION_VERSION; + end + return; + + elseif event == "PLAYER_TARGET_CHANGED" then + -- The dashboard can stay open while the user clicks between different + -- targets in the world (or opens/closes inspect). Resync RD_UNIT against + -- reality every time target changes, so class-based row filtering always + -- matches the unit whose stats we are about to display. + if RelationshipsDashboardFrame:IsVisible() then + if InspectFrame and InspectFrame:IsVisible() + and UnitExists("target") and UnitIsPlayer("target") then + RD_UNIT = "target"; + else + RD_UNIT = "player"; + end + RelationshipsDashboard_ApplyClassVisibility(); + RelationshipsDashboard_UpdateStats(); + end + return; + end + if event == "PLAYER_ENTERING_WORLD" then + -- Delay initial setup slightly + RelationshipsDashboard_HookCharacterFrame(); RelationshipsDashboard_TryHookInspectFrame(); + -- Initialize mana tracking for druid form support + local powerType = UnitPowerType("player"); + if powerType == 0 then + RelationshipsDashboard_LastKnownMana = UnitMana("player"); + RelationshipsDashboard_LastKnownMaxMana = UnitManaMax("player"); + end + RD_LastMoney = GetMoney(); + RD_InBattleground = RelationshipsDashboard_IsInBattleground(); + if RD_InBattleground and not RD_BG_DurabilitySnapshot then + RelationshipsDashboard_SnapshotDurabilityForBG(); + end + -- Sync stored ghost state to reality on login + if UnitIsGhost and UnitIsGhost("player") then + RD_WasGhost = true; + end + elseif event == "UNIT_DISPLAYPOWER" then + -- Power type changed (e.g., druid shifted forms) + if arg1 and arg1 ~= "player" then return; end + local powerType = UnitPowerType("player"); + if powerType == 0 then + RelationshipsDashboard_LastKnownMana = UnitMana("player"); + RelationshipsDashboard_LastKnownMaxMana = UnitManaMax("player"); + end + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_ApplyClassVisibility(); + RelationshipsDashboard_UpdateStats(); + end + elseif event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then + RelationshipsDashboard_UpdateRepairFromMerchant(); + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + elseif event == "MERCHANT_CLOSED" then + RelationshipsDashboard_MerchantRepairCost = 0; + RD_AtRepairMerchant = false; + RD_LastMoney = GetMoney(); + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + elseif event == "PLAYER_DEAD" then + -- Refresh BG state before deciding to apply the death penalty. + RD_InBattleground = RelationshipsDashboard_IsInBattleground(); + if RD_InBattleground and not RD_BG_DurabilitySnapshot then + -- We entered a BG without seeing ZONE_CHANGED first (rare but + -- observed on OctoWoW). Snapshot now so the restore is a no-op. + RelationshipsDashboard_SnapshotDurabilityForBG(); + end + -- Player died: apply 10% durability loss (skipped inside BGs). + RelationshipsDashboard_ApplyDeathPenalty(); + if RD_InBattleground then + RelationshipsDashboard_RestoreDurabilityFromBGSnapshot(); + end + RD_DeathPenaltyApplied = true; + RD_WasGhost = true; + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + elseif event == "PLAYER_UNGHOST" or event == "PLAYER_ALIVE" then + -- Detect spirit-healer resurrection: player was a ghost, and after + -- becoming alive is NOT near their corpse (corpse-run always leaves + -- you at the corpse location — spirit rez teleports you to the + -- graveyard). Vanilla exposes HasCorpse via GetCorpseRecoveryDelay(): + -- returns > 0 only after a spirit rez. That's our signal. + local isAlive = not (UnitIsGhost and UnitIsGhost("player")) + and not (UnitIsDead and UnitIsDead("player")); + if RD_WasGhost and isAlive then + local corpseDelay = 0; + if GetCorpseRecoveryDelay then + corpseDelay = GetCorpseRecoveryDelay() or 0; + end + if corpseDelay > 0 then + RelationshipsDashboard_ApplySpiritHealerPenalty(); + end + RD_WasGhost = false; + end + -- Clear the death-penalty guard once the player is alive again so a + -- subsequent death re-applies the 10% loss. + if not (UnitIsGhost and UnitIsGhost("player")) then + RD_DeathPenaltyApplied = false; + RD_GhostStateLast = false; + end + -- Always refresh the dashboard on rez (corpse-run OR spirit-heal). + -- The 10% death penalty was already applied on PLAYER_DEAD but the + -- character panel is usually closed at that moment, so this is the + -- first chance the visible dashboard has to redraw with the loss. + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + elseif event == "PLAYER_REGEN_DISABLED" then + -- Entering combat: start tracking hits for durability estimation + RD_InCombat = true; + RD_CombatHitCount = 0; + RD_LastHealth = UnitHealth("player"); + elseif event == "PLAYER_REGEN_ENABLED" then + -- Leaving combat: stop tracking + RD_InCombat = false; + RD_CombatHitCount = 0; + elseif event == "DUEL_REQUESTED" then + -- A duel has been initiated between the player and someone else. + -- Duels never cause real durability loss, so treat the duration + -- like a battleground for our purposes. We capture equipped + -- durability snapshots so we can restore them exactly if the duel + -- somehow does mutate our tracker. + RD_InDuel = true; + elseif event == "DUEL_FINISHED" then + -- Duel is over (accepted-and-completed, declined, or cancelled). + -- Restore estimated durability to full for equipped items so any + -- combat-wear ticks that fired mid-duel are undone. + if RD_InDuel then + RelationshipsDashboard_ResetDurabilityToFull(); + end + RD_InDuel = false; + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + + elseif event == "ZONE_CHANGED_NEW_AREA" or event == "ZONE_CHANGED" then + -- Zone changed: update battleground status + local wasInBG = RD_InBattleground; + RD_InBattleground = RelationshipsDashboard_IsInBattleground(); + -- Entering a battleground: snapshot current durability so we can + -- restore it exactly on exit regardless of any events fired inside. + if RD_InBattleground and not wasInBG then + RelationshipsDashboard_SnapshotDurabilityForBG(); + end + -- When leaving a battleground, restore the pre-BG snapshot instead + -- of resetting to full (avoids over-repairing gear that was already + -- damaged before queueing). + if wasInBG and not RD_InBattleground then + if RD_BG_DurabilitySnapshot then + RelationshipsDashboard_RestoreDurabilityFromBGSnapshot(); + RD_BG_DurabilitySnapshot = nil; + else + RelationshipsDashboard_ResetDurabilityToFull(); + end + end + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + elseif event == "PLAYER_MONEY" then + -- Gold changed. If a repair merchant is open this is very likely a + -- repair (or a purchase). Check whether money actually decreased and + -- whether the drop is consistent with the last-known repair-all cost. + -- If so, we KNOW a repair just happened -> force a full reset even if + -- GetRepairAllCost hasn't yet updated to 0 (some server builds lag by + -- a frame). + local newMoney = GetMoney(); + local spent = 0; + if RD_LastMoney and newMoney and newMoney < RD_LastMoney then + spent = RD_LastMoney - newMoney; + end + if RD_AtRepairMerchant then + -- Detect "just repaired": money dropped by ~90%+ of the previously + -- reported repair-all cost. Covers Repair All AND individual + -- right-click repairs (which drop by a slot's share). + if spent > 0 and RD_PrevMerchantRepairCost > 0 + and spent >= math.floor(RD_PrevMerchantRepairCost * 0.9) + and spent <= RD_PrevMerchantRepairCost + 100 then + RelationshipsDashboard_MerchantRepairCost = 0; + RD_PrevMerchantRepairCost = 0; + RelationshipsDashboard_ResetDurabilityToFull(); + else + -- Otherwise just re-query cost normally; the function will + -- itself trigger a reset if cost dropped to 0. + RelationshipsDashboard_UpdateRepairFromMerchant(); + end + end + RD_LastMoney = newMoney; + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + else + -- All other stat-related events (UNIT_MANA, UNIT_HEALTH, etc.) + -- arg1 is the unitID for UNIT_* events — only update for "player" + if arg1 and arg1 ~= "player" then + return; + end + -- Track damage taken in combat for durability estimation + if event == "UNIT_HEALTH" and RD_InCombat then + local currentHealth = UnitHealth("player"); + if RD_LastHealth > 0 and currentHealth < RD_LastHealth then + local damageTaken = RD_LastHealth - currentHealth; + -- Apply combat wear (the function internally tracks hit count) + RelationshipsDashboard_ApplyCombatWear(damageTaken); + end + RD_LastHealth = currentHealth; + end + if RelationshipsDashboardFrame:IsVisible() then + RelationshipsDashboard_UpdateStats(); + end + end +end diff --git a/RelationshipsDashboard.toc b/RelationshipsDashboard.toc new file mode 100644 index 0000000..c0f1b40 --- /dev/null +++ b/RelationshipsDashboard.toc @@ -0,0 +1,13 @@ +## Interface: 11200 +## Title: RelationshipsDashboard +## Notes: Character stats, GearScore, and repair cost display |cffff9900by Relationship|r +## Author: Relationship +## Version: 1.0 +## SavedVariables: RelationshipsDashboardDB +## SavedVariablesPerCharacter: RelationshipsDashboardDB_SavedDurability +## Dependencies: +## OptionalDeps: +Database.lua +RelationshipsDashboard.lua +RelationshipsDashboard.xml + diff --git a/RelationshipsDashboard.xml b/RelationshipsDashboard.xml new file mode 100644 index 0000000..296e332 --- /dev/null +++ b/RelationshipsDashboard.xml @@ -0,0 +1,655 @@ + +