Merit Hunter+

Live progress, remaining counts, and quick wins for every Torn honor and medal, right on the awards page.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Advertisement:

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

Advertisement:

// ==UserScript==
// @name         Merit Hunter+
// @version      1.14.2
// @description  Live progress, remaining counts, and quick wins for every Torn honor and medal, right on the awards page.
// @author       Rowage [3926289]
// @copyright    2026, Rowage [3926289]
// @license      CC-BY-NC-ND-4.0
// @match        https://www.torn.com/page.php?sid=awards*
// @match        https://torn.com/page.php?sid=awards*
// @match        https://*.torn.com/page.php?sid=awards*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM.xmlHttpRequest
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.deleteValue
// @connect      api.torn.com
// @run-at       document-idle
// @noframes
// @namespace https://torn.com/profiles.php?XID=3926289
// ==/UserScript==
(function () {
    'use strict';

    const DATA = JSON.parse("{\"honors\":{\"map\":{\"1\":{\"p\":\"items.found.city\",\"t\":50},\"4\":{\"p\":\"jobs.job_points_used\",\"t\":100},\"7\":{\"p\":\"hospital.medical_items_used\",\"t\":5000},\"10\":{\"p\":\"investments.bank.current\",\"t\":1000000000},\"11\":{\"p\":\"travel.total\",\"t\":100},\"13\":{\"p\":\"profile.level\",\"t\":75,\"s\":\"profile\"},\"15\":{\"p\":\"attacking.killstreak.best\",\"t\":10},\"16\":{\"p\":\"attacking.killstreak.best\",\"t\":100},\"17\":{\"p\":\"attacking.killstreak.best\",\"t\":500},\"18\":{\"p\":\"profile.level\",\"t\":10,\"s\":\"profile\"},\"20\":{\"p\":\"attacking.hits.critical\",\"t\":25},\"22\":{\"p\":\"attacking.defends.won\",\"t\":50},\"23\":{\"p\":\"hospital.reviving.revives\",\"t\":500},\"27\":{\"p\":\"attacking.attacks.stealth\",\"t\":100},\"28\":{\"p\":\"finishing_hits.mechanical\",\"t\":100},\"29\":{\"p\":\"drugs.cannabis\",\"t\":50},\"30\":{\"p\":\"drugs.ecstasy\",\"t\":50},\"31\":{\"p\":\"drugs.ketamine\",\"t\":50},\"32\":{\"p\":\"drugs.lsd\",\"t\":50},\"33\":{\"p\":\"drugs.opium\",\"t\":50},\"34\":{\"p\":\"drugs.shrooms\",\"t\":50},\"35\":{\"p\":\"drugs.speed\",\"t\":50},\"36\":{\"p\":\"drugs.pcp\",\"t\":50},\"37\":{\"p\":\"drugs.xanax\",\"t\":50},\"38\":{\"p\":\"drugs.vicodin\",\"t\":50},\"39\":{\"p\":\"attacking.attacks.won\",\"t\":5},\"40\":{\"p\":\"attacking.attacks.won\",\"t\":20},\"41\":{\"p\":\"attacking.attacks.won\",\"t\":50},\"42\":{\"p\":\"attacking.attacks.won\",\"t\":100},\"43\":{\"p\":\"attacking.attacks.won\",\"t\":250},\"44\":{\"p\":\"attacking.attacks.won\",\"t\":500},\"45\":{\"p\":\"attacking.attacks.won\",\"t\":1000},\"46\":{\"p\":\"attacking.attacks.won\",\"t\":2000},\"47\":{\"p\":\"attacking.attacks.won\",\"t\":3000},\"48\":{\"p\":\"attacking.attacks.won\",\"t\":4000},\"49\":{\"p\":\"attacking.attacks.won\",\"t\":5000},\"50\":{\"p\":\"travel.hunting.skill\",\"t\":50},\"51\":{\"p\":\"travel.hunting.skill\",\"t\":75},\"52\":{\"p\":\"travel.hunting.skill\",\"t\":100},\"130\":{\"p\":\"travel.argentina\",\"t\":50},\"131\":{\"p\":\"travel.mexico\",\"t\":50},\"132\":{\"p\":\"travel.united_arab_emirates\",\"t\":50},\"133\":{\"p\":\"travel.hawaii\",\"t\":50},\"134\":{\"p\":\"travel.japan\",\"t\":50},\"135\":{\"p\":\"travel.united_kingdom\",\"t\":50},\"136\":{\"p\":\"travel.south_africa\",\"t\":50},\"137\":{\"p\":\"travel.switzerland\",\"t\":50},\"138\":{\"p\":\"travel.china\",\"t\":50},\"139\":{\"p\":\"travel.canada\",\"t\":50},\"140\":{\"p\":\"attacking.ammunition.total\",\"t\":1000},\"141\":{\"p\":\"finishing_hits.heavy_artillery\",\"t\":100},\"142\":{\"p\":\"finishing_hits.clubbing\",\"t\":100},\"143\":{\"p\":\"finishing_hits.temporary\",\"t\":100},\"144\":{\"p\":\"finishing_hits.machine_guns\",\"t\":100},\"145\":{\"p\":\"finishing_hits.pistols\",\"t\":100},\"146\":{\"p\":\"finishing_hits.rifles\",\"t\":100},\"147\":{\"p\":\"finishing_hits.shotguns\",\"t\":100},\"148\":{\"p\":\"finishing_hits.sub_machine_guns\",\"t\":100},\"149\":{\"p\":\"finishing_hits.piercing\",\"t\":100},\"150\":{\"p\":\"finishing_hits.slashing\",\"t\":100},\"151\":{\"p\":\"attacking.ammunition.total\",\"t\":10000},\"164\":{\"p\":\"jobs.job_points_used\",\"t\":1000},\"165\":{\"p\":\"travel.total\",\"t\":1000},\"216\":{\"p\":\"items.viruses_coded\",\"t\":100},\"222\":{\"p\":\"items.found.easter_eggs\",\"t\":10},\"227\":{\"p\":\"attacking.hits.critical\",\"t\":1000},\"229\":{\"p\":\"other.awards\",\"t\":250},\"232\":{\"p\":\"bounties.collected.amount\",\"t\":250},\"236\":{\"p\":\"bounties.collected.value\",\"t\":10000000},\"238\":{\"p\":\"items.found.dump\",\"t\":1000},\"239\":{\"p\":\"trading.bazaar.customers\",\"t\":100},\"240\":{\"p\":\"battle_stats.defense\",\"t\":1000000},\"241\":{\"p\":\"battle_stats.dexterity\",\"t\":1000000},\"242\":{\"p\":\"battle_stats.speed\",\"t\":1000000},\"243\":{\"p\":\"battle_stats.strength\",\"t\":1000000},\"245\":{\"p\":\"other.activity.time\",\"t\":1000,\"m\":3600},\"247\":{\"p\":\"attacking.networth.largest_mug\",\"t\":1000000},\"248\":{\"p\":\"jail.busts.success\",\"t\":1000},\"249\":{\"p\":\"jail.busts.success\",\"t\":2500},\"250\":{\"p\":\"jail.busts.success\",\"t\":10000},\"251\":{\"p\":\"crimes.offenses.total\",\"t\":10000},\"252\":{\"p\":\"jail.bails.amount\",\"t\":500},\"259\":{\"p\":\"profile.level\",\"t\":50,\"s\":\"profile\"},\"264\":{\"p\":\"profile.level\",\"t\":100,\"s\":\"profile\"},\"265\":{\"p\":\"profile.level\",\"t\":100,\"s\":\"profile\"},\"266\":{\"p\":\"items.used.energy\",\"t\":250},\"267\":{\"p\":\"hospital.reviving.revives\",\"t\":1000},\"268\":{\"p\":\"trading.points.sold\",\"t\":1000},\"270\":{\"p\":\"attacking.attacks.stalemate\",\"t\":100},\"271\":{\"p\":\"items.trashed\",\"t\":5000},\"272\":{\"p\":\"travel.cayman_islands\",\"t\":50},\"273\":{\"p\":\"trading.items.auctions.won\",\"t\":10},\"334\":{\"p\":\"other.refills.token\",\"t\":250},\"398\":{\"p\":\"hospital.blood_withdrawn\",\"t\":1000},\"418\":{\"p\":\"hospital.blood_withdrawn\",\"t\":250},\"490\":{\"p\":\"attacking.attacks.assist\",\"t\":250},\"497\":{\"p\":\"battle_stats.defense\",\"t\":10000000},\"498\":{\"p\":\"battle_stats.defense\",\"t\":1000000000},\"505\":{\"p\":\"battle_stats.speed\",\"t\":10000000},\"506\":{\"p\":\"battle_stats.speed\",\"t\":100000000},\"515\":{\"p\":\"finishing_hits.hand_to_hand\",\"t\":100},\"517\":{\"p\":\"attacking.hits.one_hit_kills\",\"t\":100},\"525\":{\"p\":\"jobs.stats.endurance\",\"t\":100000},\"530\":{\"p\":\"jobs.stats.intelligence\",\"t\":100000},\"533\":{\"p\":\"jobs.stats.manual\",\"t\":100000},\"534\":{\"p\":\"items.used.alcohol\",\"t\":500},\"537\":{\"p\":\"items.used.candy\",\"t\":500},\"538\":{\"p\":\"items.used.energy\",\"t\":500},\"539\":{\"p\":\"items.used.books\",\"t\":10},\"541\":{\"p\":\"travel.items_bought\",\"t\":100},\"542\":{\"p\":\"travel.items_bought\",\"t\":1000},\"543\":{\"p\":\"travel.items_bought\",\"t\":10000},\"546\":{\"p\":\"investments.stocks.payouts\",\"t\":100},\"549\":{\"p\":\"travel.time_spent\",\"t\":7,\"m\":86400},\"550\":{\"p\":\"battle_stats.speed\",\"t\":1000000000},\"552\":{\"p\":\"crimes.offenses.organized_crimes\",\"t\":100},\"557\":{\"p\":\"travel.time_spent\",\"t\":365,\"m\":86400},\"566\":{\"p\":\"other.refills.nerve\",\"t\":250},\"567\":{\"p\":\"travel.time_spent\",\"t\":31,\"m\":86400},\"571\":{\"p\":\"racing.races.won\",\"t\":100},\"572\":{\"p\":\"racing.skill\",\"t\":10},\"581\":{\"p\":\"racing.points\",\"t\":2500},\"601\":{\"p\":\"attacking.hits.success\",\"t\":10000},\"606\":{\"p\":\"other.awards\",\"t\":100},\"614\":{\"p\":\"other.awards\",\"t\":500},\"629\":{\"p\":\"battle_stats.dexterity\",\"t\":100000000},\"635\":{\"p\":\"battle_stats.dexterity\",\"t\":10000000},\"636\":{\"p\":\"missions.credits\",\"t\":10000},\"638\":{\"p\":\"battle_stats.dexterity\",\"t\":1000000000},\"640\":{\"p\":\"battle_stats.defense\",\"t\":100000000},\"643\":{\"p\":\"battle_stats.strength\",\"t\":10000000},\"646\":{\"p\":\"battle_stats.strength\",\"t\":100000000},\"647\":{\"p\":\"battle_stats.strength\",\"t\":1000000000},\"651\":{\"p\":\"education.complete\",\"t\":50,\"s\":\"education\"},\"653\":{\"p\":\"education.complete\",\"t\":10,\"s\":\"education\"},\"656\":{\"p\":\"education.complete\",\"t\":100,\"s\":\"education\"},\"659\":{\"p\":\"education.complete\",\"t\":25,\"s\":\"education\"},\"664\":{\"p\":\"missions.contracts.total\",\"t\":1000},\"679\":{\"p\":\"battle_stats.total\",\"t\":100000000},\"686\":{\"p\":\"battle_stats.total\",\"t\":10000},\"687\":{\"p\":\"battle_stats.total\",\"t\":100},\"690\":{\"p\":\"battle_stats.total\",\"t\":10000000000},\"694\":{\"p\":\"battle_stats.total\",\"t\":1000000},\"704\":{\"p\":\"battle_stats.total\",\"t\":100000000000},\"708\":{\"p\":\"battle_stats.total\",\"t\":10000000},\"720\":{\"p\":\"battle_stats.total\",\"t\":1000},\"721\":{\"p\":\"battle_stats.total\",\"t\":1000000000},\"723\":{\"p\":\"battle_stats.total\",\"t\":100000},\"742\":{\"p\":\"jobs.job_points_used\",\"t\":10000},\"763\":{\"p\":\"attacking.unarmored_wins\",\"t\":250},\"791\":{\"p\":\"attacking.ammunition.special\",\"t\":10000},\"793\":{\"p\":\"attacking.ammunition.special\",\"t\":1000},\"800\":{\"p\":\"attacking.ammunition.special\",\"t\":100},\"834\":{\"p\":\"attacking.ammunition.total\",\"t\":100000},\"836\":{\"p\":\"attacking.ammunition.total\",\"t\":1000000},\"846\":{\"p\":\"travel.attacks_won\",\"t\":100},\"903\":{\"p\":\"hospital.times_hospitalized\",\"t\":250},\"906\":{\"p\":\"jail.times_jailed\",\"t\":250},\"942\":{\"p\":\"attacking.ammunition.hollow_point\",\"t\":2500},\"943\":{\"p\":\"attacking.ammunition.piercing\",\"t\":2500},\"944\":{\"p\":\"attacking.ammunition.incendiary\",\"t\":2500},\"945\":{\"p\":\"attacking.ammunition.tracer\",\"t\":2500},\"1001\":{\"p\":\"attacking.damage.total\",\"t\":10000000},\"1002\":{\"p\":\"attacking.damage.total\",\"t\":1000000},\"1003\":{\"p\":\"attacking.damage.total\",\"t\":100000000},\"1004\":{\"p\":\"attacking.damage.total\",\"t\":100000},\"1005\":{\"p\":\"investments.stocks.profits\",\"t\":1000000000},\"1006\":{\"p\":\"investments.stocks.losses\",\"t\":1000000000},\"1014\":{\"p\":\"crimes.skills.search_for_cash\",\"t\":100},\"1025\":{\"p\":\"crimes.skills.bootlegging\",\"t\":100},\"1029\":{\"p\":\"crimes.skills.shoplifting\",\"t\":100},\"1034\":{\"p\":\"crimes.skills.graffiti\",\"t\":100},\"1053\":{\"p\":\"crimes.skills.card_skimming\",\"t\":100},\"1064\":{\"p\":\"crimes.skills.burglary\",\"t\":100},\"1078\":{\"p\":\"crimes.skills.pickpocketing\",\"t\":100},\"1083\":{\"p\":\"crimes.skills.hustling\",\"t\":100},\"1104\":{\"p\":\"crimes.skills.disposal\",\"t\":100},\"1118\":{\"p\":\"crimes.skills.cracking\",\"t\":100},\"1130\":{\"p\":\"crimes.skills.forgery\",\"t\":100},\"1277\":{\"p\":\"crimes.skills.scamming\",\"t\":100},\"1374\":{\"p\":\"crimes.skills.arson\",\"t\":100}},\"cosmetic\":[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,168,169,170,171,172,173,174,175,176,177,178,179,181,182,183,184,186,188,189,190,191,192,193,194,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,725,726,774,775,787,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,857,858,859,956,1008],\"legacy\":[2,6,24,25,152,153,154,155,157,158,159,160,161]},\"medals\":{\"map\":{\"30\":{\"p\":\"jail.busts.success\",\"t\":250},\"31\":{\"p\":\"jail.busts.success\",\"t\":500},\"32\":{\"p\":\"jail.busts.success\",\"t\":1000},\"33\":{\"p\":\"jail.busts.success\",\"t\":2000},\"34\":{\"p\":\"profile.level\",\"t\":5,\"s\":\"profile\"},\"35\":{\"p\":\"profile.level\",\"t\":10,\"s\":\"profile\"},\"36\":{\"p\":\"profile.level\",\"t\":15,\"s\":\"profile\"},\"37\":{\"p\":\"profile.level\",\"t\":20,\"s\":\"profile\"},\"38\":{\"p\":\"profile.level\",\"t\":25,\"s\":\"profile\"},\"39\":{\"p\":\"profile.level\",\"t\":30,\"s\":\"profile\"},\"40\":{\"p\":\"profile.level\",\"t\":35,\"s\":\"profile\"},\"41\":{\"p\":\"profile.level\",\"t\":40,\"s\":\"profile\"},\"42\":{\"p\":\"profile.level\",\"t\":45,\"s\":\"profile\"},\"43\":{\"p\":\"profile.level\",\"t\":50,\"s\":\"profile\"},\"44\":{\"p\":\"profile.level\",\"t\":55,\"s\":\"profile\"},\"45\":{\"p\":\"profile.level\",\"t\":60,\"s\":\"profile\"},\"46\":{\"p\":\"profile.level\",\"t\":65,\"s\":\"profile\"},\"47\":{\"p\":\"profile.level\",\"t\":70,\"s\":\"profile\"},\"48\":{\"p\":\"profile.level\",\"t\":75,\"s\":\"profile\"},\"49\":{\"p\":\"profile.level\",\"t\":80,\"s\":\"profile\"},\"50\":{\"p\":\"profile.level\",\"t\":85,\"s\":\"profile\"},\"51\":{\"p\":\"profile.level\",\"t\":90,\"s\":\"profile\"},\"52\":{\"p\":\"profile.level\",\"t\":95,\"s\":\"profile\"},\"53\":{\"p\":\"profile.level\",\"t\":100,\"s\":\"profile\"},\"105\":{\"p\":\"jail.busts.success\",\"t\":4000},\"106\":{\"p\":\"jail.busts.success\",\"t\":6000},\"107\":{\"p\":\"jail.busts.success\",\"t\":8000},\"174\":{\"p\":\"attacking.attacks.won\",\"t\":50},\"175\":{\"p\":\"attacking.attacks.won\",\"t\":250},\"176\":{\"p\":\"attacking.attacks.won\",\"t\":500},\"177\":{\"p\":\"attacking.attacks.won\",\"t\":2500},\"178\":{\"p\":\"attacking.attacks.won\",\"t\":10000},\"179\":{\"p\":\"attacking.defends.won\",\"t\":50},\"180\":{\"p\":\"attacking.defends.won\",\"t\":250},\"181\":{\"p\":\"attacking.defends.won\",\"t\":500},\"182\":{\"p\":\"attacking.defends.won\",\"t\":2500},\"183\":{\"p\":\"attacking.defends.won\",\"t\":10000},\"184\":{\"p\":\"attacking.escapes.player\",\"t\":50},\"185\":{\"p\":\"attacking.escapes.player\",\"t\":250},\"186\":{\"p\":\"attacking.escapes.player\",\"t\":1000},\"187\":{\"p\":\"attacking.escapes.foes\",\"t\":50},\"188\":{\"p\":\"attacking.escapes.foes\",\"t\":250},\"189\":{\"p\":\"attacking.escapes.foes\",\"t\":1000},\"190\":{\"p\":\"attacking.killstreak.best\",\"t\":25},\"191\":{\"p\":\"attacking.killstreak.best\",\"t\":50},\"192\":{\"p\":\"attacking.killstreak.best\",\"t\":100},\"193\":{\"p\":\"attacking.killstreak.best\",\"t\":250},\"194\":{\"p\":\"attacking.killstreak.best\",\"t\":500},\"195\":{\"p\":\"attacking.hits.critical\",\"t\":500},\"196\":{\"p\":\"attacking.hits.critical\",\"t\":2500},\"197\":{\"p\":\"attacking.hits.critical\",\"t\":10000},\"198\":{\"p\":\"hospital.medical_items_used\",\"t\":500},\"199\":{\"p\":\"hospital.medical_items_used\",\"t\":5000},\"200\":{\"p\":\"hospital.medical_items_used\",\"t\":25000},\"201\":{\"p\":\"bounties.collected.amount\",\"t\":25},\"202\":{\"p\":\"bounties.collected.amount\",\"t\":100},\"203\":{\"p\":\"bounties.collected.amount\",\"t\":500},\"204\":{\"p\":\"items.found.city\",\"t\":10},\"205\":{\"p\":\"items.found.city\",\"t\":50},\"206\":{\"p\":\"items.found.city\",\"t\":100},\"207\":{\"p\":\"travel.total\",\"t\":25},\"208\":{\"p\":\"travel.total\",\"t\":100},\"209\":{\"p\":\"travel.total\",\"t\":500},\"210\":{\"p\":\"other.donator_days\",\"t\":30},\"211\":{\"p\":\"other.donator_days\",\"t\":100},\"212\":{\"p\":\"other.donator_days\",\"t\":250},\"213\":{\"p\":\"other.donator_days\",\"t\":500},\"214\":{\"p\":\"other.donator_days\",\"t\":1000},\"215\":{\"p\":\"attacking.faction.respect\",\"t\":100},\"216\":{\"p\":\"attacking.faction.respect\",\"t\":500},\"217\":{\"p\":\"attacking.faction.respect\",\"t\":1000},\"218\":{\"p\":\"attacking.faction.respect\",\"t\":2500},\"219\":{\"p\":\"attacking.faction.respect\",\"t\":5000},\"220\":{\"p\":\"attacking.faction.respect\",\"t\":10000},\"221\":{\"p\":\"attacking.faction.respect\",\"t\":25000},\"222\":{\"p\":\"attacking.faction.respect\",\"t\":50000},\"223\":{\"p\":\"attacking.faction.respect\",\"t\":75000},\"224\":{\"p\":\"attacking.faction.respect\",\"t\":100000},\"242\":{\"p\":\"crimes.offenses.total\",\"t\":100},\"243\":{\"p\":\"crimes.offenses.total\",\"t\":200},\"244\":{\"p\":\"crimes.offenses.total\",\"t\":300},\"245\":{\"p\":\"crimes.offenses.total\",\"t\":500},\"246\":{\"p\":\"crimes.offenses.total\",\"t\":750},\"247\":{\"p\":\"crimes.offenses.total\",\"t\":1000},\"248\":{\"p\":\"crimes.offenses.total\",\"t\":1500},\"249\":{\"p\":\"crimes.offenses.total\",\"t\":2000},\"250\":{\"p\":\"crimes.offenses.total\",\"t\":2500},\"251\":{\"p\":\"crimes.offenses.total\",\"t\":3000},\"252\":{\"p\":\"crimes.offenses.total\",\"t\":4000},\"253\":{\"p\":\"crimes.offenses.total\",\"t\":5000},\"254\":{\"p\":\"crimes.offenses.total\",\"t\":6000},\"255\":{\"p\":\"crimes.offenses.total\",\"t\":7500},\"256\":{\"p\":\"crimes.offenses.total\",\"t\":10000},\"257\":{\"p\":\"crimes.offenses.vandalism\",\"t\":100},\"258\":{\"p\":\"crimes.offenses.vandalism\",\"t\":200},\"259\":{\"p\":\"crimes.offenses.vandalism\",\"t\":300},\"260\":{\"p\":\"crimes.offenses.vandalism\",\"t\":500},\"261\":{\"p\":\"crimes.offenses.vandalism\",\"t\":750},\"262\":{\"p\":\"crimes.offenses.vandalism\",\"t\":1000},\"263\":{\"p\":\"crimes.offenses.vandalism\",\"t\":1500},\"264\":{\"p\":\"crimes.offenses.vandalism\",\"t\":2000},\"265\":{\"p\":\"crimes.offenses.vandalism\",\"t\":2500},\"266\":{\"p\":\"crimes.offenses.vandalism\",\"t\":3000},\"267\":{\"p\":\"crimes.offenses.vandalism\",\"t\":4000},\"268\":{\"p\":\"crimes.offenses.vandalism\",\"t\":5000},\"269\":{\"p\":\"crimes.offenses.vandalism\",\"t\":6000},\"270\":{\"p\":\"crimes.offenses.vandalism\",\"t\":7500},\"271\":{\"p\":\"crimes.offenses.vandalism\",\"t\":10000},\"272\":{\"p\":\"crimes.offenses.theft\",\"t\":100},\"273\":{\"p\":\"crimes.offenses.theft\",\"t\":200},\"274\":{\"p\":\"crimes.offenses.theft\",\"t\":300},\"275\":{\"p\":\"crimes.offenses.theft\",\"t\":500},\"276\":{\"p\":\"crimes.offenses.theft\",\"t\":750},\"277\":{\"p\":\"crimes.offenses.theft\",\"t\":1000},\"278\":{\"p\":\"crimes.offenses.theft\",\"t\":1500},\"279\":{\"p\":\"crimes.offenses.theft\",\"t\":2000},\"280\":{\"p\":\"crimes.offenses.theft\",\"t\":2500},\"281\":{\"p\":\"crimes.offenses.theft\",\"t\":3000},\"282\":{\"p\":\"crimes.offenses.theft\",\"t\":4000},\"283\":{\"p\":\"crimes.offenses.theft\",\"t\":5000},\"284\":{\"p\":\"crimes.offenses.theft\",\"t\":6000},\"285\":{\"p\":\"crimes.offenses.theft\",\"t\":7500},\"286\":{\"p\":\"crimes.offenses.theft\",\"t\":10000},\"287\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":100},\"288\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":200},\"289\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":300},\"290\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":500},\"291\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":750},\"292\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":1000},\"293\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":1500},\"294\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":2000},\"295\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":2500},\"296\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":3000},\"297\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":4000},\"298\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":5000},\"299\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":6000},\"300\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":7500},\"301\":{\"p\":\"crimes.offenses.counterfeiting\",\"t\":10000},\"302\":{\"p\":\"crimes.offenses.fraud\",\"t\":100},\"303\":{\"p\":\"crimes.offenses.fraud\",\"t\":200},\"304\":{\"p\":\"crimes.offenses.fraud\",\"t\":300},\"305\":{\"p\":\"crimes.offenses.fraud\",\"t\":500},\"306\":{\"p\":\"crimes.offenses.fraud\",\"t\":750},\"307\":{\"p\":\"crimes.offenses.fraud\",\"t\":1000},\"308\":{\"p\":\"crimes.offenses.fraud\",\"t\":1500},\"309\":{\"p\":\"crimes.offenses.fraud\",\"t\":2000},\"310\":{\"p\":\"crimes.offenses.fraud\",\"t\":2500},\"311\":{\"p\":\"crimes.offenses.fraud\",\"t\":3000},\"312\":{\"p\":\"crimes.offenses.fraud\",\"t\":4000},\"313\":{\"p\":\"crimes.offenses.fraud\",\"t\":5000},\"314\":{\"p\":\"crimes.offenses.fraud\",\"t\":6000},\"315\":{\"p\":\"crimes.offenses.fraud\",\"t\":7500},\"316\":{\"p\":\"crimes.offenses.fraud\",\"t\":10000},\"317\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":100},\"318\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":200},\"319\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":300},\"320\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":500},\"321\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":750},\"322\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":1000},\"323\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":1500},\"324\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":2000},\"325\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":2500},\"326\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":3000},\"327\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":4000},\"328\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":5000},\"329\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":6000},\"330\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":7500},\"331\":{\"p\":\"crimes.offenses.illicit_services\",\"t\":10000},\"332\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":100},\"333\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":200},\"334\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":300},\"335\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":500},\"336\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":750},\"337\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":1000},\"338\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":1500},\"339\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":2000},\"340\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":2500},\"341\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":3000},\"342\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":4000},\"343\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":5000},\"344\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":6000},\"345\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":7500},\"346\":{\"p\":\"crimes.offenses.cybercrime\",\"t\":10000}},\"legacy\":[54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,81,82,83,84,85,86,87,88,97,98,99,100,101,102,103,104,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,152,153,154,155,163,164,165,166,167,168,169,170,171,172,173]},\"prio\":{\"honor1\":200,\"honor8\":200,\"medal26\":100,\"medal27\":200,\"medal198\":150,\"medal204\":70,\"honor239\":100,\"honor245\":200,\"honor316\":14,\"honor371\":1,\"honor606\":40,\"honor607\":200,\"honor844\":150,\"honor845\":1,\"honor873\":100,\"honor15\":6,\"honor16\":14,\"honor20\":5,\"honor27\":40,\"honor28\":28,\"honor39\":2,\"honor40\":3,\"honor41\":5,\"honor42\":10,\"honor43\":35,\"honor44\":100,\"honor45\":150,\"honor46\":200,\"honor140\":15,\"honor141\":28,\"honor142\":28,\"honor143\":28,\"honor144\":28,\"honor145\":28,\"honor146\":28,\"honor147\":28,\"honor148\":28,\"honor149\":28,\"honor150\":28,\"honor151\":100,\"medal190\":14,\"medal191\":14,\"medal192\":14,\"medal195\":150,\"medal201\":50,\"medal215\":14,\"medal216\":100,\"medal217\":100,\"medal218\":150,\"medal219\":200,\"medal220\":200,\"honor227\":200,\"honor236\":1,\"honor247\":1,\"honor253\":30,\"honor254\":1,\"honor255\":30,\"honor256\":30,\"honor257\":30,\"honor317\":1,\"honor477\":100,\"honor478\":100,\"honor481\":1,\"honor488\":100,\"honor500\":100,\"honor515\":28,\"honor517\":15,\"honor605\":1,\"honor615\":1,\"honor627\":1,\"honor639\":1,\"honor641\":30,\"honor665\":1,\"honor719\":1,\"honor739\":1,\"honor763\":50,\"honor781\":1,\"honor793\":150,\"honor800\":150,\"honor827\":1,\"honor828\":1,\"honor838\":1,\"honor896\":1,\"honor902\":1,\"honor903\":100,\"honor916\":200,\"honor942\":35,\"honor943\":35,\"honor944\":35,\"honor945\":35,\"honor951\":31,\"honor955\":1,\"honor1002\":100,\"honor1004\":15,\"honor269\":14,\"honor326\":14,\"honor327\":20,\"honor338\":5,\"honor513\":1,\"honor519\":5,\"medal210\":30,\"medal211\":100,\"honor29\":3,\"honor30\":100,\"honor31\":5,\"honor32\":20,\"honor33\":15,\"honor34\":10,\"honor35\":15,\"honor36\":15,\"honor37\":50,\"honor38\":15,\"honor53\":200,\"honor398\":200,\"honor406\":200,\"honor418\":100,\"honor653\":150,\"honor871\":30,\"honor11\":50,\"honor130\":15,\"honor131\":5,\"honor132\":50,\"honor133\":15,\"honor134\":25,\"honor135\":15,\"honor136\":50,\"honor137\":15,\"honor138\":25,\"honor139\":5,\"medal207\":10,\"medal208\":30,\"medal209\":100,\"honor272\":5,\"honor541\":2,\"honor542\":15,\"honor543\":150,\"honor549\":40,\"honor567\":150,\"honor846\":100,\"honor853\":1,\"honor233\":50,\"honor234\":150,\"honor686\":50,\"honor687\":3,\"honor694\":200,\"honor720\":5,\"honor723\":100,\"honor888\":100,\"honor18\":4,\"medal34\":3,\"medal35\":4,\"medal36\":5,\"medal37\":20,\"medal38\":35,\"medal39\":60,\"medal40\":90,\"medal41\":130,\"medal42\":180,\"medal74\":50,\"medal75\":100,\"medal76\":150,\"honor288\":200,\"honor380\":100,\"honor395\":2,\"honor534\":25,\"honor537\":12,\"honor617\":20,\"honor860\":1,\"honor3\":1,\"honor12\":1,\"honor268\":1,\"honor271\":1,\"honor273\":28,\"honor520\":1,\"honor521\":1,\"honor544\":14,\"honor678\":1,\"honor716\":1,\"honor717\":1,\"honor743\":1,\"honor882\":1,\"medal89\":3,\"medal90\":3,\"medal91\":3,\"medal92\":3,\"medal93\":10,\"medal94\":10,\"medal95\":20,\"medal96\":40,\"medal236\":100,\"medal237\":200,\"honor21\":150,\"honor571\":150,\"honor734\":150,\"medal1\":5,\"medal2\":5,\"medal3\":5,\"medal4\":5,\"medal5\":5,\"medal6\":20,\"medal7\":40,\"medal8\":60,\"medal9\":80,\"medal10\":110,\"medal11\":140,\"medal12\":170,\"medal13\":200,\"honor50\":2,\"honor221\":14,\"honor222\":1,\"honor309\":1,\"honor375\":1,\"honor443\":1,\"honor459\":1,\"honor731\":1,\"honor843\":1,\"honor964\":8,\"honor969\":3,\"honor4\":10,\"honor220\":1,\"medal256\":67,\"medal271\":100,\"medal286\":67,\"medal301\":100,\"medal316\":167,\"medal331\":500,\"medal346\":220,\"honor676\":70,\"honor1012\":5,\"honor1014\":21,\"honor1025\":26,\"honor1029\":33,\"honor1031\":21,\"honor1032\":12,\"honor1034\":28,\"honor1038\":1,\"honor1053\":200,\"honor1054\":30,\"honor1064\":60,\"honor1076\":33,\"honor1078\":32,\"honor1083\":17,\"honor1097\":20,\"honor1104\":35,\"honor1106\":30,\"honor1118\":80,\"honor1129\":25,\"honor1130\":80,\"honor1136\":14,\"honor1277\":80,\"honor7\":83,\"honor10\":200,\"honor13\":500,\"honor17\":83,\"honor22\":3,\"honor23\":25,\"honor47\":33,\"honor48\":44,\"honor49\":55,\"honor51\":25,\"honor52\":33,\"honor164\":200,\"honor165\":100,\"honor216\":25,\"honor229\":500,\"honor232\":62,\"honor238\":200,\"honor240\":4,\"honor241\":4,\"honor242\":4,\"honor243\":4,\"honor248\":33,\"honor249\":83,\"honor250\":333,\"honor251\":22,\"honor252\":100,\"honor259\":333,\"honor264\":666,\"honor265\":666,\"honor266\":12,\"honor267\":50,\"honor270\":0,\"honor334\":125,\"honor490\":2,\"honor497\":40,\"honor498\":4000,\"honor505\":40,\"honor506\":400,\"honor525\":40,\"honor530\":40,\"honor533\":40,\"honor538\":25,\"honor539\":10,\"honor546\":333,\"honor550\":4000,\"honor552\":0,\"honor557\":630,\"honor566\":125,\"honor572\":5,\"honor581\":20,\"honor601\":40,\"honor614\":1000,\"honor629\":400,\"honor635\":40,\"honor636\":3333,\"honor638\":4000,\"honor640\":400,\"honor643\":40,\"honor646\":400,\"honor647\":4000,\"honor651\":250,\"honor656\":500,\"honor659\":125,\"honor664\":1000,\"honor679\":142,\"honor690\":14285,\"honor704\":142857,\"honor708\":14,\"honor721\":1428,\"honor742\":2000,\"honor791\":33,\"honor834\":333,\"honor836\":3333,\"honor906\":31,\"honor1001\":40,\"honor1003\":400,\"honor1005\":33,\"honor1006\":33,\"honor1374\":333,\"medal30\":8,\"medal31\":16,\"medal32\":33,\"medal33\":66,\"medal43\":333,\"medal44\":366,\"medal45\":400,\"medal46\":433,\"medal47\":466,\"medal48\":500,\"medal49\":533,\"medal50\":566,\"medal51\":600,\"medal52\":633,\"medal53\":666,\"medal105\":133,\"medal106\":200,\"medal107\":266,\"medal174\":0,\"medal175\":2,\"medal176\":5,\"medal177\":27,\"medal178\":111,\"medal179\":3,\"medal180\":16,\"medal181\":33,\"medal182\":166,\"medal183\":666,\"medal184\":99999,\"medal185\":99999,\"medal186\":99999,\"medal187\":99999,\"medal188\":99999,\"medal189\":99999,\"medal193\":41,\"medal194\":83,\"medal196\":20,\"medal197\":83,\"medal199\":83,\"medal200\":416,\"medal202\":25,\"medal203\":125,\"medal205\":2,\"medal206\":4,\"medal212\":250,\"medal213\":500,\"medal214\":1000,\"medal221\":416,\"medal222\":833,\"medal223\":1250,\"medal224\":1666,\"medal242\":0,\"medal243\":0,\"medal244\":0,\"medal245\":1,\"medal246\":1,\"medal247\":2,\"medal248\":3,\"medal249\":4,\"medal250\":5,\"medal251\":6,\"medal252\":8,\"medal253\":11,\"medal254\":13,\"medal255\":16,\"medal257\":0,\"medal258\":0,\"medal259\":0,\"medal260\":1,\"medal261\":1,\"medal262\":2,\"medal263\":3,\"medal264\":4,\"medal265\":5,\"medal266\":6,\"medal267\":8,\"medal268\":11,\"medal269\":13,\"medal270\":16,\"medal272\":0,\"medal273\":0,\"medal274\":0,\"medal275\":1,\"medal276\":1,\"medal277\":2,\"medal278\":3,\"medal279\":4,\"medal280\":5,\"medal281\":6,\"medal282\":8,\"medal283\":11,\"medal284\":13,\"medal285\":16,\"medal287\":0,\"medal288\":0,\"medal289\":0,\"medal290\":1,\"medal291\":1,\"medal292\":2,\"medal293\":3,\"medal294\":4,\"medal295\":5,\"medal296\":6,\"medal297\":8,\"medal298\":11,\"medal299\":13,\"medal300\":16,\"medal302\":0,\"medal303\":0,\"medal304\":0,\"medal305\":1,\"medal306\":1,\"medal307\":2,\"medal308\":3,\"medal309\":4,\"medal310\":5,\"medal311\":6,\"medal312\":8,\"medal313\":11,\"medal314\":13,\"medal315\":16,\"medal317\":0,\"medal318\":0,\"medal319\":0,\"medal320\":1,\"medal321\":1,\"medal322\":2,\"medal323\":3,\"medal324\":4,\"medal325\":5,\"medal326\":6,\"medal327\":8,\"medal328\":11,\"medal329\":13,\"medal330\":16,\"medal332\":0,\"medal333\":0,\"medal334\":0,\"medal335\":1,\"medal336\":1,\"medal337\":2,\"medal338\":3,\"medal339\":4,\"medal340\":5,\"medal341\":6,\"medal342\":8,\"medal343\":11,\"medal344\":13,\"medal345\":16},\"cost\":{\"honor1\":2,\"honor4\":20,\"honor7\":83,\"honor10\":200,\"honor11\":10,\"honor13\":500,\"honor15\":1,\"honor16\":16,\"honor17\":83,\"honor18\":66,\"honor20\":0,\"honor22\":3,\"honor23\":25,\"honor27\":0,\"honor28\":8,\"honor29\":8,\"honor30\":8,\"honor31\":8,\"honor32\":8,\"honor33\":8,\"honor34\":8,\"honor35\":8,\"honor36\":8,\"honor37\":6,\"honor38\":8,\"honor39\":0,\"honor40\":0,\"honor41\":0,\"honor42\":1,\"honor43\":2,\"honor44\":5,\"honor45\":11,\"honor46\":22,\"honor47\":33,\"honor48\":44,\"honor49\":55,\"honor50\":16,\"honor51\":25,\"honor52\":33,\"honor130\":10,\"honor131\":10,\"honor132\":10,\"honor133\":10,\"honor134\":10,\"honor135\":10,\"honor136\":10,\"honor137\":10,\"honor138\":10,\"honor139\":10,\"honor140\":3,\"honor141\":8,\"honor142\":8,\"honor143\":8,\"honor144\":8,\"honor145\":8,\"honor146\":8,\"honor147\":8,\"honor148\":8,\"honor149\":8,\"honor150\":8,\"honor151\":33,\"honor164\":200,\"honor165\":100,\"honor216\":25,\"honor227\":8,\"honor229\":500,\"honor232\":62,\"honor236\":2500000,\"honor238\":200,\"honor239\":5,\"honor240\":4,\"honor241\":4,\"honor242\":4,\"honor243\":4,\"honor245\":250,\"honor248\":33,\"honor249\":83,\"honor250\":333,\"honor251\":22,\"honor252\":100,\"honor259\":333,\"honor264\":666,\"honor265\":666,\"honor266\":12,\"honor267\":50,\"honor268\":50,\"honor270\":0,\"honor271\":62,\"honor272\":10,\"honor273\":0,\"honor334\":125,\"honor398\":333,\"honor418\":83,\"honor490\":2,\"honor497\":40,\"honor498\":4000,\"honor505\":40,\"honor506\":400,\"honor515\":8,\"honor517\":0,\"honor525\":40,\"honor530\":40,\"honor533\":40,\"honor534\":33,\"honor537\":33,\"honor538\":25,\"honor539\":10,\"honor541\":3,\"honor542\":33,\"honor543\":333,\"honor546\":333,\"honor549\":12,\"honor550\":4000,\"honor552\":0,\"honor557\":630,\"honor566\":125,\"honor567\":53,\"honor571\":10,\"honor572\":5,\"honor581\":20,\"honor601\":40,\"honor606\":200,\"honor614\":1000,\"honor629\":400,\"honor635\":40,\"honor636\":3333,\"honor638\":4000,\"honor640\":400,\"honor643\":40,\"honor646\":400,\"honor647\":4000,\"honor651\":250,\"honor653\":50,\"honor656\":500,\"honor659\":125,\"honor664\":1000,\"honor679\":142,\"honor686\":0,\"honor687\":0,\"honor690\":14285,\"honor694\":1,\"honor704\":142857,\"honor708\":14,\"honor720\":0,\"honor721\":1428,\"honor723\":0,\"honor742\":2000,\"honor763\":50,\"honor791\":33,\"honor793\":3,\"honor800\":0,\"honor834\":333,\"honor836\":3333,\"honor846\":4,\"honor903\":25,\"honor906\":31,\"honor942\":8,\"honor943\":8,\"honor944\":8,\"honor945\":8,\"honor1001\":40,\"honor1002\":4,\"honor1003\":400,\"honor1004\":0,\"honor1005\":33,\"honor1006\":33,\"honor1014\":333,\"honor1025\":333,\"honor1029\":333,\"honor1034\":333,\"honor1053\":333,\"honor1064\":333,\"honor1078\":333,\"honor1083\":333,\"honor1104\":333,\"honor1118\":333,\"honor1130\":333,\"honor1277\":333,\"honor1374\":333,\"medal30\":8,\"medal31\":16,\"medal32\":33,\"medal33\":66,\"medal34\":33,\"medal35\":66,\"medal36\":100,\"medal37\":133,\"medal38\":166,\"medal39\":200,\"medal40\":233,\"medal41\":266,\"medal42\":300,\"medal43\":333,\"medal44\":366,\"medal45\":400,\"medal46\":433,\"medal47\":466,\"medal48\":500,\"medal49\":533,\"medal50\":566,\"medal51\":600,\"medal52\":633,\"medal53\":666,\"medal105\":133,\"medal106\":200,\"medal107\":266,\"medal174\":0,\"medal175\":2,\"medal176\":5,\"medal177\":27,\"medal178\":111,\"medal179\":3,\"medal180\":16,\"medal181\":33,\"medal182\":166,\"medal183\":666,\"medal190\":4,\"medal191\":8,\"medal192\":16,\"medal193\":41,\"medal194\":83,\"medal195\":4,\"medal196\":20,\"medal197\":83,\"medal198\":8,\"medal199\":83,\"medal200\":416,\"medal201\":6,\"medal202\":25,\"medal203\":125,\"medal204\":0,\"medal205\":2,\"medal206\":4,\"medal207\":2,\"medal208\":10,\"medal209\":50,\"medal210\":30,\"medal211\":100,\"medal212\":250,\"medal213\":500,\"medal214\":1000,\"medal215\":1,\"medal216\":8,\"medal217\":16,\"medal218\":41,\"medal219\":83,\"medal220\":166,\"medal221\":416,\"medal222\":833,\"medal223\":1250,\"medal224\":1666,\"medal242\":0,\"medal243\":0,\"medal244\":0,\"medal245\":1,\"medal246\":1,\"medal247\":2,\"medal248\":3,\"medal249\":4,\"medal250\":5,\"medal251\":6,\"medal252\":8,\"medal253\":11,\"medal254\":13,\"medal255\":16,\"medal256\":22,\"medal257\":0,\"medal258\":0,\"medal259\":0,\"medal260\":1,\"medal261\":1,\"medal262\":2,\"medal263\":3,\"medal264\":4,\"medal265\":5,\"medal266\":6,\"medal267\":8,\"medal268\":11,\"medal269\":13,\"medal270\":16,\"medal271\":22,\"medal272\":0,\"medal273\":0,\"medal274\":0,\"medal275\":1,\"medal276\":1,\"medal277\":2,\"medal278\":3,\"medal279\":4,\"medal280\":5,\"medal281\":6,\"medal282\":8,\"medal283\":11,\"medal284\":13,\"medal285\":16,\"medal286\":22,\"medal287\":0,\"medal288\":0,\"medal289\":0,\"medal290\":1,\"medal291\":1,\"medal292\":2,\"medal293\":3,\"medal294\":4,\"medal295\":5,\"medal296\":6,\"medal297\":8,\"medal298\":11,\"medal299\":13,\"medal300\":16,\"medal301\":22,\"medal302\":0,\"medal303\":0,\"medal304\":0,\"medal305\":1,\"medal306\":1,\"medal307\":2,\"medal308\":3,\"medal309\":4,\"medal310\":5,\"medal311\":6,\"medal312\":8,\"medal313\":11,\"medal314\":13,\"medal315\":16,\"medal316\":22,\"medal317\":0,\"medal318\":0,\"medal319\":0,\"medal320\":1,\"medal321\":1,\"medal322\":2,\"medal323\":3,\"medal324\":4,\"medal325\":5,\"medal326\":6,\"medal327\":8,\"medal328\":11,\"medal329\":13,\"medal330\":16,\"medal331\":22,\"medal332\":0,\"medal333\":0,\"medal334\":0,\"medal335\":1,\"medal336\":1,\"medal337\":2,\"medal338\":3,\"medal339\":4,\"medal340\":5,\"medal341\":6,\"medal342\":8,\"medal343\":11,\"medal344\":13,\"medal345\":16,\"medal346\":22}}");

    const API = 'https://api.torn.com/v2';
    const DEF_TTL = 86400e3;
    const USER_TTL = 120e3;
    const LS = 'tap:';

    const HAS_GM_GET = typeof GM_getValue === 'function';
    const HAS_GM_SET = typeof GM_setValue === 'function';
    const HAS_GM_DEL = typeof GM_deleteValue === 'function';
    const GMO = (typeof GM !== 'undefined' && GM) ? GM : null;
    const ASYNC_GET = !HAS_GM_GET && GMO && typeof GMO.getValue === 'function';
    const ASYNC_SET = !HAS_GM_SET && GMO && typeof GMO.setValue === 'function';
    const ASYNC_DEL = !HAS_GM_DEL && GMO && typeof GMO.deleteValue === 'function';
    const MEM = {};
    const store = {
        get(k) {
            try {
                if (k in MEM) return MEM[k];
                if (HAS_GM_GET) { const v = GM_getValue(k, null); return v == null ? null : v; }
                if (ASYNC_GET) return null;
                return localStorage.getItem(k);
            } catch (e) { return null; }
        },
        set(k, v) {
            try {
                MEM[k] = v;
                if (HAS_GM_SET) GM_setValue(k, v);
                else if (ASYNC_SET) Promise.resolve(GMO.setValue(k, v)).catch(() => {});
                else localStorage.setItem(k, v);
            } catch (e) {}
        },
        del(k) {
            try {
                delete MEM[k];
                if (HAS_GM_DEL) GM_deleteValue(k);
                else if (ASYNC_DEL) Promise.resolve(GMO.deleteValue(k)).catch(() => {});
                else localStorage.removeItem(k);
            } catch (e) {}
        },
    };

    const cache = {
        get(k, ttl) {
            try {
                const r = JSON.parse(store.get(LS + k) || 'null');
                if (r && Date.now() - r.ts < ttl) return r.v;
            } catch (e) {}
            return null;
        },
        set(k, v) { try { store.set(LS + k, JSON.stringify({ ts: Date.now(), v })); } catch (e) {} },
        del(k) { store.del(LS + k); },
    };
    const USER_KEYS = ['ps', 'uh', 'um', 'pr', 'edu'];

    function seedStore() {
        if (!ASYNC_GET) return Promise.resolve();
        const keys = ['key'].concat(USER_KEYS, ['def_honors', 'def_medals']).map(k => LS + k);
        return Promise.all(keys.map(k =>
            Promise.resolve(GMO.getValue(k)).then(v => { if (v != null) MEM[k] = v; }, () => {})
        )).catch(() => {});
    }

    function getKey() { return (store.get(LS + 'key') || '').trim(); }
    function setKey(k) { store.set(LS + 'key', (k || '').trim()); }
    const GMX = (typeof GM_xmlhttpRequest === 'function') ? GM_xmlhttpRequest
        : (typeof GM !== 'undefined' && GM && typeof GM.xmlHttpRequest === 'function') ? GM.xmlHttpRequest.bind(GM)
        : null;

    function apiRaw(path) {
        const url = API + path + (path.includes('?') ? '&' : '?')
            + 'key=' + encodeURIComponent(getKey()) + '&comment=MeritHunterPlus';
        if (GMX) {
            return new Promise((res, rej) => {
                GMX({
                    method: 'GET',
                    url,
                    timeout: 15000,
                    onload: r => {
                        let j;
                        try { j = JSON.parse(r.responseText); } catch (e) { return rej(new Error('bad json')); }
                        if (j && j.error) return rej(j.error);
                        res(j);
                    },
                    onerror: () => rej(new Error('network')),
                    ontimeout: () => rej(new Error('timeout')),
                });
            });
        }
        return fetch(url, { credentials: 'omit' }).then(r => r.json()).then(j => {
            if (j && j.error) throw j.error;
            return j;
        }, () => { throw new Error('network'); });
    }

    async function cachedApi(path, key, ttl) {
        const hit = cache.get(key, ttl);
        if (hit) return hit;
        const v = await apiRaw(path);
        cache.set(key, v);
        return v;
    }

    function resolve(pstat, ps, level, eduDone) {
        if (pstat === 'profile.level') return level;
        if (pstat === 'education.complete') return eduDone;
        let o = ps;
        for (const seg of pstat.split('.')) { if (o == null) return 0; o = o[seg]; }
        return typeof o === 'number' ? o : 0;
    }

    function computeAll(state) {
        const { ps, level, eduDone, eH, eM } = state;
        const recs = {};
        const add = (kind, idStr, m) => {
            const id = +idStr;
            const thr = m.t * (m.m || 1);
            const cur = resolve(m.p, ps, level, eduDone);
            if (cur == null) return;
            const earned = (kind === 'honor' ? eH : eM).has(id);
            const raw = thr > 0 ? cur / thr : 0;
            recs[kind + id] = {
                kind, id, cur, thr, earned, p: m.p,
                pct: earned ? 1 : Math.max(0, Math.min(0.99, raw)),
                over: !earned && raw >= 1,
            };
        };
        for (const k in DATA.honors.map) add('honor', k, DATA.honors.map[k]);
        for (const k in DATA.medals.map) add('medal', k, DATA.medals.map[k]);
        return recs;
    }

    const ID_RE = /\/images\/(honors|medals)\/(\d+)\//;
    const TILE_SEL = 'li img[src*="/images/honors/"], li img[src*="/images/medals/"],'
        + 'li img[srcset*="/images/honors/"], li img[srcset*="/images/medals/"],'
        + 'li img[data-src*="/images/honors/"], li img[data-src*="/images/medals/"]';
    function tileInfo(img) {
        const attrs = [img.getAttribute('src'), img.getAttribute('srcset'), img.getAttribute('data-src')];
        for (const a of attrs) {
            const mm = a && ID_RE.exec(a);
            if (mm) return { kind: mm[1] === 'honors' ? 'honor' : 'medal', id: +mm[2] };
        }
        return null;
    }
    function fmt(n) { return n.toLocaleString('en-US'); }
    function pctOf(rec) { return Math.round(rec.pct * 100); }

    const PRIO = DATA.prio || {};
    const COST = DATA.cost || {};
    const QUICK_DAYS = 7;
    function priority(row) {
        const p = PRIO[row.key];
        return typeof p === 'number' ? p : Infinity;
    }
    function grindDays(row) {
        const c = COST[row.key];
        if (typeof c === 'number') return c;
        return priority(row);
    }
    function effort(row) {
        const base = grindDays(row) === Infinity ? 1e9 : grindDays(row);
        if (row.rec && !row.earned) return row.rec.over ? base : base * (1 - row.rec.pct);
        return base;
    }
    function remaining(rec) { return Math.max(0, rec.thr - rec.cur); }
    function compact(n) {
        if (n < 10000) return fmt(n);
        if (n < 1e6) return Math.round(n / 1000) + 'k';
        if (n < 1e9) return (n / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
        return (n / 1e9).toFixed(1).replace(/\.0$/, '') + 'B';
    }

    let MODEL = [];
    const ROWMAP = {};
    let unearnedOnly = false;

    function buildModel(state, defs, recs) {
        MODEL = [];
        const push = (kind, def, earnedSet) => {
            if (kind === 'honor' && DATA.honors.cosmetic.includes(def.id)) return;
            if ((def.circulation == null || def.circulation === 0) && !earnedSet.has(def.id)) return;
            const rec = recs[kind + def.id];
            const legacy = (kind === 'medal' ? DATA.medals.legacy : (DATA.honors.legacy || [])).includes(def.id);
            if (legacy && !earnedSet.has(def.id)) return;
            const cat = (def.type && def.type.title) ? def.type.title : 'misc';
            const row = {
                kind, id: def.id, key: kind + def.id,
                name: def.name, desc: def.description || '', cat,
                earned: rec ? rec.earned : earnedSet.has(def.id),
                rec, legacy, li: null,
            };
            MODEL.push(row);
            ROWMAP[row.key] = row;
        };
        defs.honors.forEach(d => push('honor', d, state.eH));
        defs.medals.forEach(d => push('medal', d, state.eM));
    }

    let PANEL;
    function ringSVG(pct) {
        const r = 30, c = 2 * Math.PI * r, off = c * (1 - pct / 100);
        return '<div class="tap-ringbox">'
            + '<svg class="tap-ringsvg" width="72" height="72" viewBox="0 0 72 72">'
            + '<circle cx="36" cy="36" r="' + r + '" class="tap-ringbg"></circle>'
            + '<circle cx="36" cy="36" r="' + r + '" class="tap-ringfg" '
            + 'stroke-dasharray="' + c.toFixed(1) + '" stroke-dashoffset="' + off.toFixed(1) + '"></circle>'
            + '</svg><span class="tap-ringpct">' + pct + '<i>%</i></span></div>';
    }

    function gridUL() {
        const img = document.querySelector(TILE_SEL);
        if (img) {
            const ul = img.closest('ul');
            if (ul && ul.childElementCount >= 3) return ul;
        }
        const host = document.querySelector('[class*="awardsPage"]') || document.querySelector('#mainContainer');
        if (!host) return null;
        let best = null, bestN = 2;
        host.querySelectorAll('ul').forEach(ul => {
            if (ul.querySelector(TILE_SEL)) { best = ul; bestN = ul.childElementCount; }
        });
        if (best) return best;
        host.querySelectorAll('ul').forEach(ul => {
            const n = ul.childElementCount;
            if (n > bestN) { bestN = n; best = ul; }
        });
        return best;
    }
    function awardHost() {
        const grid = gridUL();
        if (grid) {
            let n = grid;
            const stop = document.getElementById('mainContainer') || document.body;
            while (n.parentElement && n.parentElement !== stop && n.parentElement !== document.body) {
                n = n.parentElement;
                if (n.querySelectorAll('ul').length >= 2) return n;
            }
            if (grid.parentElement) return grid.parentElement;
        }
        return document.querySelector('[class*="awardsPage"]')
            || document.querySelector('#mainContainer [class*="content"]')
            || document.getElementById('mainContainer')
            || null;
    }
    function topBlock(node, host) {
        let n = node;
        while (n.parentElement && n.parentElement !== host && host.contains(n)) n = n.parentElement;
        return n;
    }
    function catBar(host, grid) {
        let earliest = null;
        host.querySelectorAll('ul, nav').forEach(el => {
            if (el === grid || el.contains(grid) || (grid && grid.contains(el))) return;
            if (el.querySelector(TILE_SEL)) return;
            if (el.childElementCount < 2) return;
            if (grid && !(el.compareDocumentPosition(grid) & 0x04)) return;
            if (!earliest || (el.compareDocumentPosition(earliest) & 0x04)) earliest = el;
        });
        return earliest;
    }
    function placePanel() {
        if (!PANEL) return false;
        const host = awardHost();
        if (host) {
            const grid = gridUL();
            const cat = catBar(host, grid);
            let anchor = null;
            [cat, grid].forEach(c => {
                if (!c) return;
                const tb = topBlock(c, host);
                if (tb.parentElement !== host) return;
                if (!anchor || (tb.compareDocumentPosition(anchor) & 0x04)) anchor = tb;
            });
            if (anchor && anchor.parentNode === host) {
                if (anchor.previousElementSibling !== PANEL) host.insertBefore(PANEL, anchor);
                return true;
            }
            if (host.firstElementChild !== PANEL) host.insertBefore(PANEL, host.firstElementChild);
            return true;
        }
        return false;
    }

    function buildUI() {
        if (document.getElementById('tap-panel')) return;
        PANEL = document.createElement('div');
        PANEL.id = 'tap-panel';
        PANEL.innerHTML =
            '<div class="tap-corner"><span class="tap-status"></span>'
            + '<label class="tap-toggle"><input type="checkbox" id="tap-un"><span>Unearned</span></label>'
            + '<button class="tap-refresh" title="Refresh data from Torn">refresh</button>'
            + '<button class="tap-key" title="Change API key">key</button></div>'
            + '<div class="tap-needkey" hidden>'
            + '<div class="tap-nk-title">Merit Hunter+</div>'
            + '<div class="tap-nk-msg">Paste your Torn API key to light up the dashboard. '
            + '<a href="https://www.torn.com/preferences.php#tab=api" target="_blank" rel="noopener noreferrer">Get a key</a>'
            + ' (Limited access is enough). It is stored only in your browser.</div>'
            + '<div class="tap-nk-row"><input type="text" class="tap-nk-input" placeholder="Paste API key here" '
            + 'autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false">'
            + '<button class="tap-nk-save">Activate</button></div>'
            + '<div class="tap-nk-err" hidden></div></div>'
            + '<div class="tap-top"><div class="tap-ringwrap"></div>'
            + '<div class="tap-col" data-list="quick"><div class="tap-colhead">QUICK WINS</div><div class="tap-list"></div></div>'
            + '<div class="tap-col" data-list="almost"><div class="tap-colhead">ALMOST THERE</div><div class="tap-list"></div></div></div>'
            + '<div class="tap-easy"><div class="tap-colhead">TRACKABLE, NOT STARTED</div><div class="tap-grid"></div></div>'
            + '<div class="tap-chals"><div class="tap-colhead">SPECIFIC CHALLENGES</div><div class="tap-cats"></div></div>';
        placePanel();
        const unBox = PANEL.querySelector('#tap-un');
        unBox.checked = unearnedOnly;
        unBox.addEventListener('change', e => {
            unearnedOnly = e.target.checked; applyGridFilter();
        });
        const inp = PANEL.querySelector('.tap-nk-input');
        const saveKey = () => {
            const v = (inp.value || '').trim();
            if (!v) { nkError('Paste a key first.'); inp.focus(); return; }
            if (v !== getKey()) USER_KEYS.forEach(k => cache.del(k));
            setKey(v); nkError(''); load();
        };
        PANEL.querySelector('.tap-nk-save').addEventListener('click', saveKey);
        inp.addEventListener('keydown', e => { if (e.key === 'Enter') { e.preventDefault(); saveKey(); } });
        PANEL.querySelector('.tap-key').addEventListener('click', () => {
            const b = PANEL.querySelector('.tap-needkey');
            if (b.hidden) { inp.value = getKey(); showNeedsKey(); inp.focus(); }
            else hideNeedsKey();
        });
        PANEL.querySelector('.tap-refresh').addEventListener('click', e => {
            const b = e.currentTarget;
            if (b.disabled) return;
            b.disabled = true; b.textContent = '...';
            USER_KEYS.forEach(k => cache.del(k));
            load().finally(() => { b.disabled = false; b.textContent = 'refresh'; toast('refreshed'); });
        });
        PANEL.addEventListener('click', e => {
            const head = e.target.closest('.tap-cathead');
            if (head) {
                const body = head.nextElementSibling;
                body.hidden = !body.hidden;
                head.classList.toggle('open', !body.hidden);
                return;
            }
            const item = e.target.closest('[data-key]');
            if (!item) return;
            const row = ROWMAP[item.dataset.key];
            if (row && row.li) {
                row.li.scrollIntoView({ behavior: 'smooth', block: 'center' });
                row.li.classList.add('tap-flash');
                setTimeout(() => row.li && row.li.classList.remove('tap-flash'), 1400);
            }
        });
    }

    function itemHTML(r) {
        const p = pctOf(r.rec);
        return '<button class="tap-item" data-key="' + r.key + '" title="' + (r.name + ': ' + r.desc).replace(/"/g, '') + '">'
            + '<span class="tap-iname">' + r.name + '</span>'
            + '<span class="tap-ibar"><i style="width:' + p + '%"></i></span>'
            + '<span class="tap-ipct">' + p + '%</span>'
            + '<span class="tap-irem">' + (r.rec.over ? '≈' : compact(remaining(r.rec)) + ' left') + '</span></button>';
    }

    function chalHTML(r) {
        return '<button class="tap-chal" data-key="' + r.key + '" title="' + (r.name + ': ' + r.desc).replace(/"/g, '') + '">'
            + '<span class="tap-cname">' + r.name + '</span>'
            + '<span class="tap-cdesc">' + r.desc + '</span></button>';
    }

    function currentTab() {
        const m = /[?&]tab=(honors|medals)/.exec(location.href);
        return m && m[1] === 'medals' ? 'medal' : 'honor';
    }
    function onMerits() { return /[?&]tab=merits/.test(location.href); }

    function renderStrip() {
        const tab = currentTab();
        renderStrip._tab = tab;
        const pool = MODEL.filter(r => r.kind === tab);
        const total = pool.length;
        const earned = pool.filter(r => r.earned).length;
        const pct = total ? Math.round(earned / total * 100) : 0;
        const label = tab === 'medal' ? 'Medals' : 'Honors';
        PANEL.querySelector('.tap-ringwrap').innerHTML =
            ringSVG(pct) + '<span class="tap-ringsub">' + fmt(earned) + ' / ' + fmt(total) + '</span>'
            + '<div class="tap-kinds"><span>' + label + ' <b>' + pct + '%</b></span></div>';

        const unearned = pool.filter(r => r.rec && !r.earned);
        const quick = unearned.filter(r => COST[r.key] != null && COST[r.key] <= QUICK_DAYS)
            .sort((a, b) => effort(a) - effort(b)).slice(0, 8);
        const almost = unearned.filter(r => r.rec.pct > 0)
            .sort((a, b) => b.rec.pct - a.rec.pct).slice(0, 8);
        const notStarted = unearned.filter(r => r.rec.pct === 0)
            .sort((a, b) => effort(a) - effort(b)).slice(0, 18);
        const challenges = pool
            .filter(r => !r.earned && !r.rec)
            .sort((a, b) => effort(a) - effort(b) || a.name.localeCompare(b.name));
        const fill = (sel, list, empty, render) => {
            const el = PANEL.querySelector(sel);
            el.innerHTML = list.length ? list.map(render || itemHTML).join('')
                : '<span class="tap-none">' + empty + '</span>';
        };
        fill('[data-list=quick] .tap-list', quick, 'No quick wins left. Everything still open is a real grind from here.');
        fill('[data-list=almost] .tap-list', almost, 'No tracked award is part-way done yet.');
        fill('.tap-grid', notStarted, 'Every trackable award is already underway or done. Only specific challenges remain.');

        const byCat = {};
        challenges.forEach(r => { (byCat[r.cat] = byCat[r.cat] || []).push(r); });
        const cats = Object.keys(byCat).sort((a, b) => byCat[b].length - byCat[a].length);
        const catsEl = PANEL.querySelector('.tap-cats');
        catsEl.innerHTML = cats.length ? cats.map(c =>
            '<div class="tap-cat"><button class="tap-cathead"><span class="tap-caret">▸</span>'
            + '<span class="tap-catname">' + c + '</span><i>' + byCat[c].length + '</i></button>'
            + '<div class="tap-catbody" hidden>' + byCat[c].map(chalHTML).join('') + '</div></div>'
        ).join('') : '<span class="tap-none">all specific challenges done</span>';
    }

    function applyGridFilter() {
        for (const r of MODEL) {
            if (!r.li) continue;
            r.li.style.display = unearnedOnly && r.earned ? 'none' : '';
        }
        applyMedalFilter();
    }

    function applyMedalFilter() {
        const cards = document.querySelectorAll('ul[class*="medalsList"] > li');
        if (!cards.length) return;
        cards.forEach(li => {
            const earned = !li.querySelector('[class*="lockedMedal"]');
            if (unearnedOnly && earned) { li.style.display = 'none'; li.dataset.tapHid = '1'; }
            else if (li.dataset.tapHid) { li.style.display = ''; delete li.dataset.tapHid; }
        });
    }

    let DEFS = null, RECS = {};
    function indexTiles() {
        if (!DEFS) return;
        document.querySelectorAll(TILE_SEL)
            .forEach(img => {
                const info = tileInfo(img);
                if (!info) return;
                const row = ROWMAP[info.kind + info.id];
                if (row) row.li = img.closest('li');
            });
        placePanel();
        applyGridFilter();
    }

    function onAwards() { return /[?&]sid=awards/.test(location.href); }

    function setStatus(msg) {
        const s = PANEL && PANEL.querySelector('.tap-status');
        if (s) s.textContent = msg || '';
    }
    function nkError(msg) {
        const e = PANEL && PANEL.querySelector('.tap-nk-err');
        if (!e) return;
        e.textContent = msg || '';
        e.hidden = !msg;
    }
    function showNeedsKey(err) {
        if (onMerits() || !onAwards()) return;
        if (!document.getElementById('tap-panel')) buildUI();
        placePanel();
        const b = PANEL && PANEL.querySelector('.tap-needkey');
        if (b) b.hidden = false;
        if (PANEL) PANEL.style.display = '';
        setStatus('');
        if (err !== undefined) nkError(err);
    }
    function hideNeedsKey() {
        const b = PANEL && PANEL.querySelector('.tap-needkey');
        if (b) b.hidden = true;
        nkError('');
    }

    function ensureUI() {
        if (!onAwards() || onMerits()) { if (PANEL) PANEL.style.display = 'none'; return; }
        if (!MODEL.length) { if (!getKey()) showNeedsKey(); return; }
        if (!document.getElementById('tap-panel')) { buildUI(); renderStrip(); return; }
        PANEL.style.display = '';
        placePanel();
        if (renderStrip._tab !== currentTab()) renderStrip();
    }

    function injectCSS() {
        if (document.getElementById('tap-css')) return;
        const css =
        '#tap-panel{--bg:#f2f2f2;--bd:#cdcdcd;--tx:#222;--mut:#777;--head:#444;--track:rgba(0,0,0,.12);'
        + '--acc:#69a829;--now:#5f9a3a;--soon:#b0973a;--mid:#b07636;--long:#9a4f4f;--hover:rgba(127,127,127,.08);'
        + 'position:relative;display:flex;flex-direction:column;gap:14px;padding:14px 18px;margin:0 0 12px;'
        + 'background:var(--bg);border:1px solid var(--bd);border-radius:6px;color:var(--tx);'
        + 'font:13px/1.4 var(--font-default,Arial,sans-serif)}'
        + '.tap-top{display:flex;align-items:stretch;gap:18px}'
        + '.tap-corner{position:absolute;top:10px;right:12px;display:flex;align-items:center;gap:10px;z-index:2}'
        + 'body.dark-mode #tap-panel{--bg:#333;--bd:#454545;--tx:#d6d6d6;--mut:#969696;--head:#e0e0e0;'
        + '--track:rgba(255,255,255,.1);--acc:#7bc02e;--now:#7bc02e;--soon:#c9b259;--mid:#c98f59;--long:#c97e7e;'
        + '--hover:rgba(255,255,255,.06)}'
        + '#tap-panel *{box-sizing:border-box}'
        + '.tap-ringwrap{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;flex:none;width:92px}'
        + '.tap-ringbox{position:relative;width:72px;height:72px}'
        + '.tap-ringsvg{transform:rotate(-90deg)}'
        + '.tap-ringbg{fill:none;stroke:var(--track);stroke-width:6}'
        + '.tap-ringfg{fill:none;stroke:var(--acc);stroke-width:6;stroke-linecap:round;'
        + 'transition:stroke-dashoffset .6s ease}'
        + '.tap-ringpct{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;'
        + 'font-size:19px;font-weight:700;font-variant-numeric:tabular-nums}'
        + '.tap-ringpct i{font-size:10px;font-style:normal;opacity:.55;margin-left:1px}'
        + '.tap-ringsub{font-size:10px;color:var(--mut);font-variant-numeric:tabular-nums;text-align:center}'
        + '.tap-kinds{display:flex;flex-direction:column;gap:2px;align-items:center;font-size:10px;color:var(--mut)}'
        + '.tap-kinds b{color:var(--tx);font-variant-numeric:tabular-nums}'
        + '.tap-col{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;border-left:1px solid var(--bd);padding-left:18px}'
        + '.tap-col[data-list=almost] .tap-colhead{padding-right:92px}'
        + '.tap-col[data-list=almost] .tap-list{padding-top:4px}'
        + '.tap-easy{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--bd);padding-top:12px}'
        + '.tap-colhead{font-size:11px;color:var(--head);font-weight:700;display:flex;align-items:baseline;gap:8px}'
        + '.tap-list{display:flex;flex-direction:column;gap:1px}'
        + '.tap-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px 20px}'
        + '.tap-chals{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--bd);padding-top:12px}'
        + '.tap-cats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px 24px;align-items:start}'
        + '.tap-cat{min-width:0}'
        + '.tap-cathead{display:flex;align-items:center;gap:8px;width:100%;padding:4px 6px;background:none;'
        + 'border:0;border-radius:4px;color:var(--tx);cursor:pointer;font:inherit;font-size:12px;text-align:left}'
        + '.tap-cathead:hover{background:var(--hover)}'
        + '.tap-caret{font-size:9px;color:var(--mut);transition:transform .15s;flex:none}'
        + '.tap-cathead.open .tap-caret{transform:rotate(90deg)}'
        + '.tap-catname{font-weight:700;text-transform:capitalize;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}'
        + '.tap-cathead i{font-style:normal;color:var(--mut);font-variant-numeric:tabular-nums}'
        + '.tap-catbody{display:flex;flex-direction:column;gap:1px;padding:2px 0 8px 18px}'
        + '.tap-catbody[hidden]{display:none}'
        + '.tap-chal{display:flex;flex-direction:column;gap:0;padding:4px 6px;background:none;border:0;min-width:0;'
        + 'border-radius:4px;color:var(--tx);cursor:pointer;font:inherit;text-align:left;width:100%;overflow:hidden}'
        + '.tap-chal:hover{background:var(--hover)}'
        + '.tap-cname{font-size:12px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}'
        + '.tap-cdesc{font-size:11px;color:var(--mut);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}'
        + '.tap-none{font-size:11px;color:var(--mut);padding:4px 0}'
        + '.tap-item{display:grid;grid-template-columns:minmax(0,1fr) 40px 28px 52px;align-items:center;gap:8px;'
        + 'padding:4px 6px;background:none;border:0;border-radius:4px;color:var(--tx);cursor:pointer;'
        + 'font:inherit;font-size:12px;text-align:left;width:100%}'
        + '.tap-item:hover{background:var(--hover)}'
        + '.tap-iname{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}'
        + '.tap-ibar{height:4px;border-radius:2px;background:var(--track);overflow:hidden}'
        + '.tap-ibar i{display:block;height:100%;background:var(--acc)}'
        + '.tap-ipct{font-variant-numeric:tabular-nums;color:var(--mut);text-align:right;font-size:11px}'
        + '.tap-irem{font-variant-numeric:tabular-nums;font-weight:700;text-align:right;font-size:11px;color:var(--acc)}'
        + '.tap-toggle{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--mut);cursor:pointer;user-select:none}'
        + '.tap-toggle input{accent-color:var(--acc);cursor:pointer}'
        + '.tap-key,.tap-refresh{border:1px solid var(--bd);background:none;color:var(--mut);font-size:11px;'
        + 'padding:2px 9px;border-radius:4px;cursor:pointer}'
        + '.tap-key:hover,.tap-refresh:hover{color:var(--tx)}'
        + '.tap-refresh:disabled{opacity:.5;cursor:default}'
        + '@media(max-width:820px){.tap-top{flex-wrap:wrap}.tap-col{flex-basis:100%;border-left:0;padding-left:0}.tap-grid{grid-template-columns:1fr 1fr}}'
        + 'li.tap-flash{outline:2px solid var(--acc,#6f9a3f);outline-offset:2px;border-radius:4px}'
        + '.tap-status{font-size:10px;color:var(--mut);font-variant-numeric:tabular-nums}'
        + '.tap-needkey{display:flex;flex-direction:column;gap:8px;font-size:12px;color:var(--tx);'
        + 'padding:12px 14px;border:1px solid var(--bd);border-radius:5px;background:var(--hover);max-width:560px}'
        + '.tap-needkey[hidden]{display:none}'
        + '.tap-nk-title{font-size:14px;font-weight:700;color:var(--head)}'
        + '.tap-nk-msg{color:var(--mut);line-height:1.5}'
        + '.tap-nk-msg a{color:var(--acc);text-decoration:none}'
        + '.tap-nk-msg a:hover{text-decoration:underline}'
        + '.tap-nk-row{display:flex;gap:8px;align-items:center}'
        + '.tap-nk-input{flex:1;min-width:0;padding:6px 9px;font:inherit;font-size:13px;color:var(--tx);'
        + 'background:var(--bg);border:1px solid var(--bd);border-radius:4px}'
        + '.tap-nk-input:focus{outline:none;border-color:var(--acc)}'
        + '.tap-nk-save{flex:none;border:1px solid var(--acc);background:var(--acc);color:#fff;font:inherit;'
        + 'font-size:12px;font-weight:700;padding:6px 16px;border-radius:4px;cursor:pointer}'
        + '.tap-nk-save:hover{filter:brightness(1.08)}'
        + '.tap-nk-err{font-size:11px;color:#c0392b}'
        + 'body.dark-mode #tap-panel .tap-nk-err{color:#e07a6f}'
        + '.tap-nk-err[hidden]{display:none}'
        + '@media (prefers-reduced-motion:reduce){#tap-panel *{transition:none!important}}';
        const s = document.createElement('style');
        s.id = 'tap-css';
        s.textContent = css;
        (document.head || document.documentElement).appendChild(s);
    }

    function toast(msg) {
        let t = document.getElementById('tap-toast');
        if (!t) { t = document.createElement('div'); t.id = 'tap-toast'; document.body.appendChild(t); }
        t.textContent = 'Awards+: ' + msg;
        t.style.cssText = 'position:fixed;bottom:14px;right:14px;z-index:99999;background:#222;color:#fff;'
            + 'padding:8px 12px;border-radius:6px;font:12px Arial;box-shadow:0 2px 8px rgba(0,0,0,.4)';
        clearTimeout(t._h); t._h = setTimeout(() => t.remove(), 6000);
    }

    async function load() {
        if (onMerits() || !onAwards()) return;
        if (!document.getElementById('tap-panel')) buildUI();
        if (PANEL) PANEL.style.display = '';
        if (!getKey()) { showNeedsKey(); return; }
        hideNeedsKey();
        setStatus('loading...');
        try {
            const [honorsDef, medalsDef, pStat, uHonors, uMedals, profile, edu] = await Promise.all([
                cachedApi('/torn/honors', 'def_honors', DEF_TTL),
                cachedApi('/torn/medals', 'def_medals', DEF_TTL),
                cachedApi('/user/personalstats?cat=all', 'ps', USER_TTL),
                cachedApi('/user/honors', 'uh', USER_TTL),
                cachedApi('/user/medals', 'um', USER_TTL),
                cachedApi('/user/profile', 'pr', USER_TTL),
                cachedApi('/user/education', 'edu', USER_TTL),
            ]);
            const state = {
                ps: pStat.personalstats,
                level: profile.profile.level,
                eduDone: ((edu.education && edu.education.complete) || []).length,
                eH: new Set((uHonors.honors || []).map(h => h.id)),
                eM: new Set((uMedals.medals || []).map(m => m.id)),
            };
            DEFS = { honors: honorsDef.honors, medals: medalsDef.medals };
            RECS = computeAll(state);
            buildModel(state, DEFS, RECS);
            hideNeedsKey();
            setStatus('');
            if (!onMerits()) { buildUI(); renderStrip(); }
            indexTiles();
        } catch (e) {
            const code = e && e.code;
            const msg = (e && e.error) ? e.error : (e && e.message) || 'load failed';
            setStatus('');
            if (code === 1 || code === 2 || code === 10 || code === 13 || /key/i.test(msg)) {
                USER_KEYS.forEach(k => cache.del(k));
                showNeedsKey('That key did not work (' + msg + '). Use a key with Limited access, then try again.');
            } else {
                showNeedsKey('Could not load data: ' + msg + '. Check your key or try refresh.');
            }
        }
    }

    let booted = false;
    function tick() { if (!booted) return; try { ensureUI(); indexTiles(); } catch (e) {} }

    function kick(n) {
        tick();
        if (n > 0) setTimeout(() => kick(n - 1), 400);
    }

    function start() {
        if (start._on) return;
        start._on = true;
        try { injectCSS(); } catch (e) {}
        const boot = () => { if (booted) return; booted = true; load(); };
        seedStore().then(boot, boot);
        setTimeout(boot, 3000);
        try {
            const mo = new MutationObserver(() => {
                if (start._t) return;
                start._t = setTimeout(() => { start._t = null; tick(); }, 200);
            });
            mo.observe(document.body || document.documentElement, { childList: true, subtree: true });
        } catch (e) {}
        try {
            const fire = () => setTimeout(tick, 120);
            ['pushState', 'replaceState'].forEach(m => {
                const orig = history[m];
                if (typeof orig !== 'function') return;
                history[m] = function () { const r = orig.apply(this, arguments); fire(); return r; };
            });
            window.addEventListener('popstate', fire);
        } catch (e) {}
        kick(12);
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
    else start();
})();