Greasy Fork is available in English.

Sangu Package

Package for Tribal Wars bullies

// ==UserScript==
// @name            Sangu Package
// @author          Laoujin / De Goede Fee
// @namespace       sangu.be
// @description     Package for Tribal Wars bullies
// @icon            http://www.sangu.be/images/favicon.png
// @include         https://*.tribalwars.nl/game.php?*
// @include         http://sangu.be/*
// @include         http://www.sangu.be/*
// @version         8.90.1
// @grant           GM_xmlhttpRequest
// ==/UserScript==

//We are Sangu. You will be assimilated. Resistance is Futile.

// The not-one-file source code can be found at:
// https://github.com/SanguPackage/Script

function sangu_ready() {
	//var start_time = new Date();
	//console.time("SanguPackage");
    var /**
         * When game_data.majorVersion is different from Sangu version then activate sangu 'compatibility' mode (gray icon)
         */
        sangu_version = '8.90.0',
        /**
         * true: popup with crash dump, false: don't show the popup
         */
        sangu_crash = sangu_version.split(".").length === 4,
        /**
         * jQuery element of the cell (td) that contains all page specific widgets
         */
        content_value = $("#content_value"),
        /**
         * config/ Configuration per server (nl, de). Contains stuff like ajaxAllowed, etc
         */
            server_settings = {},
        /**
         * config/ Contains all translations except for the setting related translations in sangu_trans
         */
        trans = {},
        /**
         * config/ Contains all user settings
         */
        user_data = {},
        /**
         * config/ The current world configuration. settings like hasArchers, nightbonus, etc
         */
         world_config = {},
        /**
         * config/ Contains all data for this world (resources, units, buildings, units_off, unitsSize, ...)
         * What's in this variable depends on world_config.
         * This variable is a complete and utter mess :)
         */
        world_data = {},
        /**
         * Identifies the current page based on the querystring
         */
        current_page = {
            screen: game_data.screen,
            mode: game_data.mode
        },
        keyCodeMap = {
            8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pausebreak", 20: "capslock", 27: "escape", 32: " ",
            33: "pageup", 34: "pagedown", 35: "end", 36: "home", 37: "arrow left", 38: "arrow up", 39: "arrow right", 40: "arrow down", 43: "+",
            44: "printscreen", 45: "insert", 46: "delete", 48: "0", 49: "1", 50: "2", 51: "3", 52: "4", 53: "5", 54: "6", 55: "7", 56: "8", 57: "9",
            59: ";", 61: "=", 65: "a",  66: "b", 67: "c", 68: "d", 69: "e", 70: "f", 71: "g", 72: "h", 73: "i", 74: "j", 75: "k", 76: "l", 77: "m",
            78: "n", 79: "o", 80: "p", 81: "q", 82: "r", 83: "s", 84: "t", 85: "u", 86: "v", 87: "w", 88: "x", 89: "y", 90: "z", 96: "0", 97: "1",
            98: "2", 99: "3", 100: "4", 101: "5",  102: "6", 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111: "/", 112: "f1",
            113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6",  118: "f7", 119: "f8", 120: "f9",  121: "f10", 122: "f11", 123: "f12", 144: "numlock",
            145: "scrolllock", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'"
        };

	server_settings = {
	    /**
	     * Calculate how many more days we can attack in vacation mode
	     */
	    maxSitDays: 60,
	    helpdeskUrl: "https://forum.tribalwars.nl/showthread.php?137674-8-11-GM-Algemeen-discussietopic-Sangu-Package",
	    /**
	     * This needs to be here for 'historical' reasons (Innogames versionchecker API remembers email on the server)
	     * when in 'compatibility' mode (gray sangu icon). Also used in the crash report.
	     */
	    sangu: "sangu.be",
	    sanguEmail: "package@sangu.be",
	    /**
	     * More then 500 [ cannot be sent in messages or pasted in the noteblock
	     */
	    allowedSquareBrackets: 500,
	    /**
	     * Are ajax calls allowed on this server
	     */
	    ajaxAllowed: true,
	    /*
	     * async: true on AJAX calls is only allowed when this property is true
	     */
	    asyncAjaxAllowed: false,
	    /**
	     * True: we add a direct link in the place to fill in coordinates. False: Show coords in an input field
	     */
	    coordinateLinkAllowed: false,
	    /**
	     * Can we fill in the coordinates directly in the place (using the url querystring) from troops overview
	     */
	    autoFillCoordinatesAllowed: true,
	    scriptsDatabaseUrl: "http://www.twscripts.nl/"
	};
	
	//$.extend(server_settings, {
	//    extraProperty: "yaye"
	//});
	/**
	 * Contains all translation
	 * The highest level is split in
	 * - tw = translations that should be translated by their server equivalents (they are used somewhere in the html by Innogames)
	 * - sp = new translations specific for the Sangu Package
	 */
	trans = {
		tw: {
			units: {
				names: { "spear": "Speer", "sword": "Zwaard", "archer": "Boog", "axe": "Bijl", "spy": "Verk", "light": "Lc", "marcher": "Bb", "heavy": "Zc", "ram": "Ram", "catapult": "Kata", "knight": "Ridder", "snob": "Edel" },
				twShortNames: { "spear": "Speer", "sword": "Zwaard", "archer": "Boog", "axe": "Bijl", "spy": "Verk.", "light": "Lcav.", "marcher": "Bboog.", "heavy": "Zcav.", "ram": "Ram", "catapult": "Kata.", "knight": "Ridder", "snob": "Edel." },
				shortNames: { "spear": "Sp", "sword": "Zw", "archer": "Boog", "axe": "Bijl", "spy": "Ver", "light": "Lc", "marcher": "Bb", "heavy": "Zc", "ram": "Ram", "catapult": "Kata", "knight": "Ridder", "snob": "Edel" },
				militia: "Militia"
			},
			all: {
				today: "vandaag om",
				tomorrow: "morgen om",
				dateOn: "op",
				timeOn: "om",
				farm: "Boerderij",
				wood: "Hout",
				iron: "IJzer",
				stone: "Leem",
				groups: "Groepen",
				continentPrefix: "C"
			},
			main: {
				loyaltyHeader: "Toestemming:"
			},
			command: {
				returnText: "Terugkeer",
				attack: "Aanval",
				support: "Ondersteuning",
				haul: "Buit:",
				abortedOperation: "Afgebroken commando",
				catapultTarget: "Katapultdoel:",
				buttonValue: "OK",
				attackOn: "Aanval op ",
				supportFor: "Ondersteuning voor ",
				walkingTimeTitle: "Duur:"
			},
			incoming: {
				defaultCommandName: "Bevel"
			},
			place: {
				troopMovements: "Troepenbewegingen"
			},
			market: {
				incomingTransports: "Binnenkomende transporten"
			},
			profile: {
				title: "Profiel",
				claimedBy: "Geclaimd door:",
				awardsWon: "Behaalde awards"
			},
			overview: {
				village: "Dorp",
				incomingTroops: "Aankomend"
			}
		},
		sp: {
			sp: {
	            settings: {
	                reset: "De standaard Sangu Package settings herstellen",
	                resetAll: "Sangu Package 'fabrieksinstellingen' herstellen",
	                configuration: "Configuratie",
	                configurationFormTogglerTooltip: "Klik op de knoppen om de verschillende editeerschermen te openen",
	                activate: "Activeer",
	                deleteTooltip: "Verwijderen",
	                addRecord: "» Toevoegen",
	                exportSettings: "Instellingen exporteren",
	                importSettings: "Instellingen importeren",
	                importSettingsDesc: "Door de sangu instellingen te exporteren en elders opnieuw te importeren kan je de huidige sangu configuratie hergebruiken op een andere wereld of computer.",
	                importSettingsSuccess: "Settings zijn geïmporteerd!",
	                importError: "Het ziet er naar uit dat de geplakte tekst foutief is.",
	                importErrorContinueAnyway: "Toch importeren?"
	            },
	            donate: {
	                title: "Donatie",
	                whyWouldI: "Als je op regelmatige basis functionaliteit van het Sangu Package gebruikt, dan is dat een goede reden om een donatie te doen."
	                            + "<br><br>"
	                            + "Jouw dankbaarheid en financiële steun helpen me motiveren verder te blijven werken aan het Sangu Package.",
	                books: "Er staan ook een aantal zeer interessante JavaScript boeken op mijn {abegin}Amazon wishlist{aend}. Daarmee kan je me ook altijd een plezier doen :)",
	                notable: "Een aantal personen hebben reeds een notabele donatie gedaan:",
	                buttonAmount: "Doneer €{amount}",
	                beer: "Trakteer me een biertje",
	                food: "Een spaghetti voor Wouter! (of pizza!)",
	                yaye: "Een nieuw IT boek voor mijn verzameling!"
	            },
				configuration: "Sangu Package configureren (v{version})",
				activatePackage: "Sangu Package activeren",
				deactivatePackage: "Sangu Package deactiveren",
	            packageCrashTitle: "Het Sangu Package is gecrasht :)",
	            packageCrashTooltip: "Crash!!! Klik op de bol om het crash rapport te bekijken. "
	                + "Je kan dit rapport naar ons doorsturen waardoor we het probleem mogelijk kunnen oplossen.",
	            packageCrash:
	                "<a href='http://" + server_settings.sangu + "'>Controleer eerst of er een update is!</a><br>"
	                + "<b>Foutmelding</b>: <i>{error}</i><br>"
	                + "<b>Details</b>:<br>"
	                + "<textarea style='width: 95%' rows='20' id='crashArea'>"
	                + "Foutmelding: {error}\n"
	                + "Pagina: {title} -> {page}\n"
	                + "URL: {url}\n"
	                + "Versie: {version}\n"
	                + "Brower: {browser}\n"
	                + "game_data: {game_data}\n"
	                + "\n{stacktrace}\n"
	                + "\n\n\n[HTML]\n"
	                + "</textarea>"
	                + "<br><br>Je kan de bug <a href='{forum-url}' target='_blank'>hier</a> melden."
	                + "<br>Of je kan de bug <a href='mailto:{email}'>mailen</a>."
	                + "<br><br><center><i>Een bug waarvan we niet weten dat ie bestaat zal ook niet gefixed worden!</i></center>"
	                + "<br><center><b>Geef zoveel mogelijk informatie mee bij het sturen van een bugrapport!!!</b></center>",
	
				activatePackageWithCompatibility: "Sangu Package (v{version}) mogelijk incompatibel met huidige TW versie",
				firstTimeRun: "<b>Welkom!</b> Het Sangu Package is momenteel inactief. Klik op de nieuwe {img} naast de opslagplaats hierboven om het package aan en uit te schakelen.",
	            firstTimeRunEditSettings: "Klik op de nieuwe 'Sangu Package' link om het package naar jouw smaak in te stellen!",
				removeScriptWarning: "Niet meer tonen",
	            moreScripts: "Meer scripts",
	            moreScriptsTooltip: "Ga naar de site met alle goedgekeurde TW scripts",
	            sanguLinkTitle: "Het package naar jouw smaak instellen"
			},
			all: {
				populationShort: "Pop",
				population: "Populatie",
				total: "Totaal",
				last: "Laatste",
				target: "Doel",
				targetEx: "Doelwit",
				more: "meer",
				less: "minder",
				all: "Alle",
				withText: "met",
				merchants: "Handelaren",
				further: "verder",
				closer: "dichter",
				fieldsSuffix: "(F{0})",
	            close: "Sluiten"
			},
			main: {
				unitsReplacement: "Eigen",
				unitsOther: "Ondersteunende Eenheden",
				rallyPointTroops: "troepen",
				ownStackTitle: "Totale populatie van de eigen troepen",
				supportingStackTitle: "Totale populatie van de ondersteunende troepen",
	            showHiddenDivs: "&raquo; Alle verborgen terugzetten ({amount} verborgen)",
	            hideDiv: "Volledig verbergen"
			},
			map: {
				dodgeLastTagged: "Dodgetijd van de laatst getagde aanval"
			},
			tagger: {
				openButton: "Open Tagger",
				rename: "Herbenoemen",
				renameTooltip: "Alle bevelen waarvan de checkbox aangevinkt is hernoemen",
				incomingTroops: "Binnenkomende troepen",
				arrival: "Aankomst",
				arrivalIn: "Aankomst in",
				sentNow: "Zojuist",
				sentSeconds: "seconde(n)",
				sent1Minute: "1 minuut",
				sentMinutes: "minuten",
				sent1Hour: "1 uur",
				sentHours: "uren",
				sentOn: "Verstuurtijd",
				ago: "Geleden",
				arrivesInNightBonus: " (NACHT!)",
				tagIt: "Aanval Taggen",
				checkAllSupport: "Aanvinken van alle zichtbare ondersteuning",
				uncheckAllSupport: "Uitvinken van alle zichtbare ondersteuning",
				tagged: "Tagged!",
				dodgeTime: "Dodgetijd",
				slowest: "Traagst",
				slowestTip: "Traagste eenheid in het dorp",
				allAbove: "Alle vroegere aanvallen aanvinken",
				allBelow: "Alle latere aanvallen aanvinken",
				renameTo: "Hernoemen naar: ",
				switchModus: "&raquo; Alle aanvallen openen/sluiten",
				checkAllAttacks: "Aanvinken van alle zichtbare aanvallen",
				uncheckAllAttacks: "Uitvinken van alle zichtbare aanvallen",
				activeDodgeTime: "Actieve dodgetijd (wordt op de kaart getoond)",
				totalAttacksOnVillage: "Aantal aanvallen",
	            renameButtonShortcutTooltip: "Shortcut: CTRL + {hitkey}"
			},
			place: {
				distance: "Afstand",
				backOn: "Terug op",
				onlyAttack: "1 aanval op {arrivalDateFirst} ({timeLeftFirst})",
				multipleAttack: "{amount} aanvallen tussen {arrivalDateFirst} ({timeLeftFirst}) en {arrivalDateLast} ({timeLeftLast})",
				changeSpeedImageTooltips: "{originalTitle} - Klik om de traagste eenheid te wijzigen"
			},
			jumper: {
				goToMap: "Ga naar de kaart"
			},
			command: {
				returnOn: "Terug op:",
				arrival: "Aankomst",
				dodgeNotFarEnough: "De dodge is niet ver genoeg!",
				dodgeMinuteReturn: "(Terugkeer na {minutes})",
				catapultImageTitle: "Klik om gebouw te vernietigen"
			},
			overviews: {
				totalVillages: "Aantal dorpen:",
				loadNextPage: "[volgende pagina laden]"
			},
			troopOverview: {
	            help: "<b>Laat je looptijden uitrekenen door Sangu!</b><br>"
	                + "Gebruik de nieuwe kolom uiterst rechts om de looptijden tot een ingegeven doeldorp te berekenen.<br>"
	                + "<br>Je kan de eenheden icons ({unitIcon}) aanklikken om de snelheid van de traagste eenheid te wijzigen."
	                + "<span style='line-height: 2'>"
	                + "<br>Klikken wijzigt de <span style='border: 2px green dotted'>snelheid op de huidige pagina</span>. "
	                + "<br>Dubbelklikken wijzigt de <span style='border: 3px red solid'>snelheid op alle pagina's</span>."
	                + "</span>"
	                + "<br>De cellen met de groene en rode rand geven de huidige traagst eenheid-snelheid aan."
	                + "<br><br><b>De iconen in de 'Opdracht' kolom</b>:"
	                + "<br>Gebruik <img src='graphic/dots/red.png'> om een rij te verwijderen."
	                + "<br>Gebruik <img src='graphic/command/attack.png'> om naar de verzamelplaats te gaan."
	                + "(gebruik de middelste muisknop om in een nieuwe tab te openen)",
	            helpTitle: "Snel dorpen aanvallen (of ondersteunen)",
				removeVillage: "Dorp verwijderen",
				toThePlace: "Verzamelplaats",
				setTargetVillageButton: "OK",
				setTargetVillageButtonAlert: "Geef de coördinaten van het dorp dat je wil aanvallen (of ondersteunen)",
				commandTitle: "Opdracht",
				selectUnitSpeed: "Selecteer {0} als traagste eenheid. (Klik op deze pagina, Dubbel klik op alle pagina's.)",
				nightBonus: "Nacht?",
				village: "Dorp",
				filterTroops: "Filter",
				filterTroopsTooltip: "Toon enkel de dorpen met meer dan het aangegeven aantal eenheden",
				filterPopulation: "Filter populatie",
				filterPopulationTooltip: "Toon enkel de dorpen met meer/minder bevolking",
	            filterWalkingTime: "Filter looptijd",
	            filterWalkingTimeTooltip: "Toon enkel de dorpen met een langere looptijd (in uren) tot het doeldorp",
				calcStack: "Bereken stack",
				calcStackTooltip: "Toon de bevolking per dorp in de \"Nacht?\" kolom",
				filterNoble: "Toon edels",
				filterNobleTooltip: "Toon enkel de dorpen waar edels aanwezig zijn",
				filterUnderAttack: "Toon onder aanval",
				filterUnderAttackTooltip: "Toon enkel de dorpen die onder aanval zijn",
				sort: "Sorteren",
				sortTooltip: "Sorteren op looptijd tot doeldorp",
				restack: "Stack BB Codes",
				restackTitle: "<b>Alle dorpen met minstens {requiredDiff}k bevolking minder dan {to}k</b><br>"
	                + "<font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>",
				cheapNobles: "Goedkope edelmannen beschikbaar",
	
	            filtersReverse: "De filtering omdraaien",
	            filtersReverseInfo: "Filters omdraaien",
	            freeTextFilter: "Tekst filter",
	            freeTextFilterTooltip: "Dorpen {filterType} de tekst wegfilteren",
	            freeTextFilterTooltipFilterTypeWith: "met",
	            freeTextFilterTooltipFilterTypeWithout: "zonder",
	            continentFilter: "Continent",
	            continentFilterTooltip: "Alle dorpen in continent wegfilteren",
	            continentFilterTooltipReverse: "Alle dorpen in continent tonen"
			},
			prodOverview: {
				filter: "Filter",
				filterFullGS: "Volle opslag",
				merchantTooltip: "Vink aan om handelaren te highlighten",
				merchantAmountTooltip: "Als de checkbox aangevinkt is worden dorpen met minder dan x handelaren in het rood gehighlight",
				bbCodes: "BB Codes",
				bbCodesInfo: "Gebruik IMG",
				filterTooltip: "Dorpen die niet aan de filtercriteria voldoen verbergen",
				filterTooltipReverse: "Dorpen die voldoen aan de filtercriteria highlighten",
				filterFullGSTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen vol is verbergen",
				filterFullGSTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen vol is highlighten",
				filterAllTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen meer/minder dan x is verbergen",
				filterAllTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen meer/minder dan x is highlighten",
				filter1Tooltip: "Dorpen waarbij er nier meer/minder dan x {0} is verbergen",
				filter1TooltipReverse: "Dorpen waarbij er meer/minder dan x {0} is highlighten",
	            tooMuch: "Teveel:",
	            tooMuchText: "Alle dorpen met minstens {diff}k meer grondstoffen dan {min}k",
	            tooLittle: "Te weinig:",
	            tooLittleText: "Alle dorpen met minstens {diff}k minder grondstoffen dan {min}k",
	            bbCodeExtraInfo: "<br><font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>"
			},
			buildOverview: {
				optimistic: "Optimistisch",
				mark: "Duiden",
				filter: "Filteren"
			},
			smithOverview: {
				optimistic: "Optimistisch",
				mark: "Duiden",
				filter: "Filteren"
			},
			defOverview: {
				stackButton: "Totalen berekenen",
				stackTooltip: "Totale stack en afstanden berekenen",
				stackFilter: "Filter op stack",
				stackFilterTooltip: "Filter dorpen met meer/minder dan x totale stack vanbuiten het dorp",
				village: "Dorp:",
				distFilter: "Filter op afstand",
				distFilterTooltip: "Filter alle dorpen die verder/dichter dan x velden liggen van dorp y",
				stackBBCodes: "Stack BBCodes",
				stackBBCodesTooltip: "Bepaal BB codes en aantal troepen voor een stack tot x populatie voor alle zichtbare dorpen",
				filterNoSupport: "Zonder OS wegfilteren",
				filterNoSupportTooltip: "Wegfilteren van alle dorpen waar geen ondersteuning meer zichtbaar is",
				extraFiltersSupport: "Ondersteunende dorpen filters:",
				extraFiltersDefense: "Ondersteuning filters:",
				extraFiltersReverse: "De filtering omdraaien",
				extraFiltersInfo: "Filters omdraaien",
				distFilter2: "Afstand filter",
				freeTextFilter: "Tekst filter",
				barbarianFilter: "Barbarendorpen",
				barbarianFilterTooltip: "Toon alle ondersteuningen naar barbarendorpen",
				nobleFilter: "Alle edel-ondersteuning tonen",
				nobleFilterRev: "Alle edel-ondersteuning wegfilteren",
				spyFilter: "Alle verkenner-ondersteuning tonen",
				spyFilterRev: "Alle verkenner-ondersteuning wegfilteren",
				attackFilter: "Alle aanval-ondersteuning tonen",
				attackFilterRev: "Alle aanval-ondersteuning wegfilteren",
				supportFilter: "Alle verdediging-ondersteuning tonen",
				supportFilterRev: "Alle verdediging-ondersteuning wegfilteren",
				otherPlayerFilterShow: "tonen",
				otherPlayerFilterHide: "wegfilteren",
				otherPlayerFilterTo: "Alle ondersteuningen naar andere spelers {action}",
				otherPlayerFilterFrom: "Alle ondersteuningen van andere spelers {action}",
	
				filterTooltipVillageTypeSupporting: "Ondersteunende dorpen",
				filterTooltipVillageTypeSupported: "Ondersteunde dorpen",
				freeTextFilterTooltip: "{villageType} {filterType} de tekst wegfilteren",
				freeTextFilterTooltipFilterTypeWith: "met",
				freeTextFilterTooltipFilterTypeWithout: "zonder",
				distanceFilterTooltip: "{villageType} die {filterType} dan het aangegeven aantal velden liggen wegfilteren",
				distanceFilterTooltipFilterTypeCloser: "dichter",
				distanceFilterTooltipFilterTypeFurther: "verder",
	
				totalFromOtherVillages: "totaal uit andere dorpen",
				totalInOtherVillages: "totaal in andere dorpen",
				freeText: "Vrij tekstveld (wordt niet opgeslagen!):",
				fieldsPrefix: "F{0}",
				thousandSuffix: "k",
				totalVillages: "Dorpen ({0})",
				distanceToVillageNoneEntered: "Geef een coördinaat! (eerste tekstveld)",
				distanceToVillage: "Afstand tot {0}",
				filterUnderAttack: "Filter onder aanval"
			},
			commands: {
				filterReturn: "Filter terugkeer",
				filterReturnTooltip: "'Teruggestuurd' en 'Terugkeer' bevelen verbergen",
				totalRows: "Somlijn",
				group: "Groeperen",
				totalRowsText: "{0}x OS = {1} pop",
				totalVillagesSupport: "Ondersteunde dorpen:",
				totalVillagesAttack: "Aangevallen dorpen:",
				totalSupport: "Ondersteuningen",
				totalAttack: "Aanvallen",
				bbCodeExport: "BBCode Export",
				bbCodeExportTooltip: "Overblijvende aanvallen exporteren",
	            supportPlayerExport: "Ondersteuning exporteren",
	            supportPlayerExportTooltip: "Geef de naam van de speler waarvoor je de ondersteuning wil exporteren "
	                + "(of laat leeg om alle ondersteuningen te exporteren). Door de export als mededeling "
	                + "naar de andere speler door te sturen "
	                + "kan deze jouw gestuurde troepen als bevelnaam zetten. (Hij heeft daarvoor natuurlijk"
	                + " ook het Sangu Package nodig :)",
				filtersReverse: "De filtering omdraaien",
				filtersReverseInfo: "Filters omdraaien",
				freeTextFilter: "Tekst filter",
				freeTextFilterTooltip: "Aanvallen {filterType} de tekst wegfilteren",
				freeTextFilterTooltipFilterTypeWith: "met",
				freeTextFilterTooltipFilterTypeWithout: "zonder",
				nobleFilter: "Alle edelaanvallen tonen",
				nobleFilterRev: "Alle edelaanvallen wegfilteren",
				spyFilter: "Alle verkenneraanvallen tonen",
				spyFilterRev: "Alle verkenneraanvallen wegfilteren",
				tableTotal: "Bevel ({0})",
				fakeFilter: "Alle fake aanvallen wegfilteren",
				fakeFilterRev: "Alle fake aanvallen tonen",
				continentFilter: "Continent",
				continentFilterTooltip: "Alle dorpen in continent wegfilteren",
				continentFilterTooltipReverse: "Alle dorpen in continent tonen",
				exportAttackHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]",
				exportDefenseHeader: "{village} {support#} ondersteuningen voor [b]{totalStack} pop[/b]",
				exportCompleteHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]\n+ {support#} ondersteuningen voor [b]{totalStack} pop[/b]",
	            exportNone: "Geen ondersteuning gevonden!"
			},
			groups: {
				villageFilter: "Dorpsnaam",
				villageFilterTitle: "Alle dorpen met de tekst in de dorpsnaam wegfilteren",
				villageFilterTitleRev: "Alle dorpen met de tekst in de dorpsnaam tonen",
				pointsFilter: "Punten",
				amountFilter: "Aantal",
				groupNameFilter: "Groepsnaam",
				amountFilterTitle: "Alle dorpen met minder groepen wegfilteren",
				amountFilterTitleRev: "Alle dorpen met meer groepen wegfilteren",
				pointsFilterTitle: "Alle dorpen met minder punten wegfilteren",
				pointsFilterTitleRev: "Alle dorpen met meer punten wegfilteren",
				farmFilterTitle: "Alle dorpen met minder populatie wegfilteren",
				farmFilterTitleRev: "Alle dorpen met meer populatie wegfilteren",
				groupNameFilterTitle: "Alle dorpen met de tekst in een groepsnaam wegfilteren",
				groupNameFilterTitleRev: "Alle dorpen met de tekst in een groepsnaam tonen"
			},
			snob: {
				canProduce: "Je kan meteen produceren:"
			},
			profile: {
				twStatsMap: "TWStats Kaart",
				externalPage: "(Extern)",
				internalPage: "(Intern)",
				conquers: "Overnames",
				villages: "Dorpen:",
				graphPoints: "Punten",
				graphVillages: "Dorpen",
				graphOD: "OD Totaal",
				graphODD: "OD Verdediging",
	            graphODA: "OD Aanval",
	            graphODS: "OD Ondersteuning",
				graphRank: "Rang",
				graphMembers: "Leden",
				graphTWMap: "TribalWarsMap.com"
			},
			incomings: {
				dynamicGrouping: "Dynamisch groeperen",
	            dynamicGroupingTooltip: "Groepeert trager maar bevriest de pagina niet",
				summation: "Somlijn",
				fastGrouping: "Snel groeperen",
	            fastGroupingTooltip: "Groepeert sneller en bevriest de pagina (geen refreshs wanneer een aanval binnenkomt)",
				showNewIncomings: "Toon nieuwe aanvallen",
	            sortByAttackId: "Sorteer op aanvalsid",
	            sortByAttackIdTooltip: "Een kleiner aanvalsid betekent een eerder verstuurde aanval",
				amount: "Aanvallen:",
	            attackId: "Aanvalsid",
	            attackIdDifference: "Verschil",
	            filterColumnButton: "Kolom filter",
	            filterColumnButtonTooltip: "Alle bevelen waarbij de geselecteerde kolom de ingegeven tekst bevat {type}",
	            filterColumnButtonTooltipHide: "verbergen",
	            filterColumnButtonTooltipShow: "tonen",
	
				indicator: {
					lastTimeCheckHintBoxTooltip: "Klik op {img} om de laatste tijdcheck met de huidige tijd te vervangen.",
					lastTimeCheckNotYetSet: "(nog niet)"
				},
	            commandsImport: "Ondersteuning importeren",
	            commandsImportTooltip: "Ondersteuning naar jouw dorpen kan op jouw account ingelezen worden"
	                + " door de andere speler zijn bevelen te laten exporteren via Sangu Package (Pagina Overzicht: Bevelen)"
	                + " en die export hier te plakken.",
	            commandsImportError: "Fout bij het inladen van de ondersteuningen.\nHet zou er zoals dit moeten uitzien: \n"
	                + '[{"commandName": "702|459 (speler) Zw=1 (Pop: 1)", "commandId": "7538763"}]',
	            commandsImportSuccess: "{replaced} van de {total} ondersteuningen zijn hernoemd."
			},
			rest: {
				sittingAttackTill: "Aanvallen en verdedigen van dorpen niet in eigen beheer tot:",
				friendsOnline: "Vrienden {friends} ({onlineimg} {online#} | {offlineimg} {offline#})",
				friendsOnlineTitle: "Online: {playerNames}"
			}
		}
	};

		/**
		 * Log the parameter to the console (print yaye when undefined)
		 */
		function q(what) { console.log(typeof what === "undefined" ? "yaye" : what); }
		
		/**
		 * Alert the parameter (yaye when undefined)
		 */
		function qa(what) { alert(typeof what === "undefined" ? "yaye" : what); }
		
		/**
		 * Show crash report
		 */
		function sangu_alert(e, title) {
		    var activator = $("#sangu_activator");
		
		    activator
		        .attr("src", "graphic/dots/grey.png")
		        .attr("title", trans.sp.sp.packageCrashTooltip);
		
		    (function() {
		        var position = $("#storage").position(),
		            options = {
		                left: position.left - 150,
		                top: position.top + 35
		            },
		            content = {body: trans.sp.sp.packageCrashTooltip, title: trans.sp.sp.packageCrashTitle};
		
		        createFixedTooltip("sanguCrashTooltip", content, options);
		    }());
		
		    activator.click(function() {
		        var currentPageHtml = document.documentElement.innerHTML,
		            position = $("#storage").position(),
		            options = {
		                left: $(window).width() / 2 - 300,
		                top: position.top + 35,
		                width: 600,
		                showOnce: false
		            },
		            game_dataSubset = {
		                majorVersion: game_data.majorVersion,
		                market: game_data.market,
		                world: game_data.world,
		                sitter: game_data.player.sitter,
		                village_id: game_data.village.id,
		                player_id: game_data.player.id,
		                player_name: game_data.player.name,
		                ally_id: game_data.player.ally_id,
		                villages: game_data.player.villages,
		                premium: game_data.player.premium/*,
		                 account_manager: game_data.player.account_manager,
		                 farm_manager: game_data.player.farm_manager*/
		            },
		            content = {
		                title: trans.sp.sp.packageCrashTitle,
		                body: trans.sp.sp.packageCrash
		                    .replace("{forum-url}", server_settings.helpdeskUrl)
		                    .replace("{title}", title)
		                    .replace(/\{error\}/g, e.message)
		                    .replace("{page}", JSON.stringify(current_page))
		                    .replace("{url}", document.location.href)
		                    .replace("{version}", sangu_version)
		                    .replace("{browser}", JSON.stringify($.browser))
		                    .replace("{game_data}", JSON.stringify(game_dataSubset))
		                    .replace("{stacktrace}", e.stack ? e.stack + "\n\n" + e.stacktrace : "assertion?")
		                    .replace("{email}", server_settings.sanguEmail)
		                    .replace("{html}", currentPageHtml)
		            };
		
		        createFixedTooltip("sanguCrash", content, options);
		        $("#crashArea").val($("#crashArea").val() + currentPageHtml);
		
		        return false;
		    });
		
		    for(i = 0; i < 7; i++) {
		        activator.fadeTo('slow', 0.2).fadeTo('slow', 1.0);
		    }
		    if (sangu_crash) {
		        activator.click();
		    }
		}
		
		/**
		 * Failed assertions show the crash report!
		 */
		function assert(shouldBeTruthy, message) {
			if (!shouldBeTruthy) {
		        sangu_alert({message: message || "(broken assertion)"});
			}
		}
		
		/**
		 * Show crash report
		 */
		function handleException(e, title) {
		    sangu_alert(e, title);
		}
	function pad(number, length) {
		var str = '' + number;
		while (str.length < length) {
			str = '0' + str;
		}
		return str;
	}
	
	/**
	 * Gets a value from the querystring (or returns "")
	 * @param {string} name the name of the querystring parameter
	 * @param {string} [url] when omitted, the current location.url is assumed
	 */
	function getQueryStringParam(name, url) {
		name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
		var regexS = "[\\?&]" + name + "=([^&#]*)";
		var regex = new RegExp(regexS);
		if( url == undefined && name == "village" ) {
			return game_data.village.id;
		} else {
			var results = regex.exec(url == undefined ? window.location.href : url);
			if (results == null) {
				return "";
			} else {
				return results[1];
			}
		}
	}
	
	/**
	 * Get a TW url taking account sitting etc in account
	 * @param {string} url provide the url starting from &screen=
	 * @param {number} [villageId] when omitted the current village is assumed
	 */
	function getUrlString(url, villageId) {
		if (url.indexOf("?") == -1) {
			var link = location.href.substr(0, location.href.indexOf("?"));
			link += "?village=" + (villageId ? villageId : getQueryStringParam("village"));
			var isSit = getQueryStringParam("t");
			if (isSit) {
				link += "&t=" + isSit;
			}
	
			if (url.indexOf("=") == -1) {
				return link + "&screen=" + url;
			} else {
				return link + "&" + url;
			}
		} else {
			return url;
		}
	}
	
	/**
	 * Perform an ajax call (if the server allows it)
	 * @param {string} screen passed to getUrlString. (start from &screen=)
	 * @param {function} strategy executed on success. Has parameter text (content of the parameter depends on opts.contentValue)
	 * @param {object} [opts] object with properties
	 *              {false|number} [villageId] passed to getUrlString. Default is false which defaults to current village. Otherwise pass a village id.
	 *              {boolean=true} [contentValue] true (default): only return the #content_value. false: return entire DOM HTML
	 *              {boolean=true} [async] defaults to true
	 */
	function ajax(screen, strategy, opts) {
		if (!server_settings.ajaxAllowed) {
			alert("Ajax is not allowed on this server.");
			return;
		}
		
		opts = $.extend({}, { villageId: false, contentValue: true, async: false }, opts);
	
		$.ajax({
			url: getUrlString(screen, opts.villageId),
			async: server_settings.asyncAjaxAllowed ? opts.async : false,
			success: function(text) {
				text = opts.contentValue ? $("#content_value", text) : text;
				strategy(text);
			}
		});
	}
	
	function spSpeedCookie(setter) {
		if (setter == undefined) {
			var speedCookie = pers.get("targetVillageSpeed");
			if (speedCookie == '') {
				speedCookie = 'ram';
			}
			return speedCookie;
		} else {
			if (setter.indexOf('_') == 4) {
				setter = setter.substr(setter.indexOf('_') + 1);
			}
			pers.set("targetVillageSpeed", setter);
			return setter;
		}
	}
	
	function spTargetVillageCookie(setter) {
		if (setter == undefined) {
			return pers.get("targetVillageCoord");
		} else {
			pers.set("targetVillageCoord", setter);
			return setter;
		}
	}
	
	function getDistance(x1, x2, y1, y2, speed) {
		var dist = {};
		dist.fields = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
		dist.travelTime = dist.fields * (speed == '' ? world_data.unitsSpeed.unit_ram : world_data.unitsSpeed['unit_' + speed]);
		dist.arrivalTime = getDateFromTW($("#serverTime").text(), true);
		dist.arrivalTime.setTime(dist.arrivalTime.getTime() + (dist.travelTime * 60 * 1000));
		dist.isNightBonus = isDateInNightBonus(dist.arrivalTime);
	
		if (speed == 'snob' && dist.travelTime > world_config.maxNobleWalkingTime) {
			dist.html = "<font color='" + user_data.colors.error + "'><b>" + twDurationFormat(dist.travelTime) + "</b></font>";
			dist.isNightBonus = true;
		} else {
			var displayTime = twDateFormat(dist.arrivalTime);
			if (speed != 'merchant' && dist.isNightBonus) {
				displayTime = "<font color='" + user_data.colors.error + "'><b>" + displayTime + "</b></font>";
			}
			dist.html = user_data.walkingTimeDisplay
	            .replace("{duration}", twDurationFormat(dist.travelTime))
	            .replace("{arrival}", displayTime);
		}
		if (dist.fields == 0) {
			dist.html = "";
		}
	
		return dist;
	}
	
	_gaq.push(['b._setAccount', 'UA-30075487-3']);
	
	/**
	 * Send click to google analytics
	 * @param {string} action
	 */
	function trackClickEvent(action) {
		trackEvent("ButtonClick", action);
	}
	
	/**
	 * google analytics event tracking
	 */
	function trackEvent(category, action, label) {
		// category: clicks (downloads, ...)
		// action: which button clicked
		if (typeof label === 'undefined') {
			label = getQueryStringParam("screen");
			var mode = getQueryStringParam("mode");
			if (mode) label += "-" + mode;
		}
		
		//_gaq.push(['b._setAccount', 'UA-30075487-3']);
		//_gaq.push(['b._trackPageview']);
		// _gat._getTrackerByName('b')._trackEvent("SanguPackage", "Loaded", "withGetB");
	    try
	    {
	        _gat._getTrackerByName('b')._trackEvent(category, action, label);
	    }
		catch (e) {
	        // no crash report for this
	    }
	}
	
	function fillRallyPoint(units) {
		var script = "";
		$.each(world_data.units, function (i, v) {
			if (units[v] != undefined && units[v] > 0) {
				script += "document.forms[0]." + v + ".value=\"" + units[v] + "\";";
			} else {
				script += "document.forms[0]." + v + ".value=\"\";";
			}
		});
	
		return script;
	}
	
	/**
	 * Tries to find village coords in str and convert it to a 'village' object
	 * @param {string} str the string to be converted to a village object
	 * @param {true|} looseMatch !!!Do not provide a value for looseMatch when converting a real village name.!!!
	 *          It should be set to true when it was the user that provided the input str. When true,
	 *          a str like 456-789 would also match. (so that Sangu Package users don't have to use | but can instead
	 *          use anything to seperate the 2 coordinates).
	 * @returns {object} object with parameters isValid: false when the string could not be matched and true with extra properties
	 * x, y, coord, validName (=html friendly id name) and continent
	 */
	function getVillageFromCoords(str, looseMatch) {
		// if str is "villageName (X|Y) C54" then the villageName could be something like "456-321"
		// the regex then thinks that the villageName are the coords
		// looseMatch
		var targetMatch = looseMatch != undefined ? str.match(/(\d+)\D(\d+)/g) : str.match(/(\d+)\|(\d+)/g);
		if (targetMatch != null && targetMatch.length > 0) {
			var coordMatch = targetMatch[targetMatch.length - 1].match(/(\d+)\D(\d+)/);
			var village = { "isValid": true, "coord": coordMatch[1] + '|' + coordMatch[2], "x": coordMatch[1], "y": coordMatch[2] };
	
			village.validName = function () { return this.x + '_' + this.y; };
			village.continent = function () { return this.y.substr(0, 1) + this.x.substr(0, 1); };
	
			return village;
		}
		return { "isValid": false };
	}
	
	function buildAttackString(villageCoord, unitsSent, player, isSupport, minimum, haulDescription) {
		var seperator = " ";
		if (minimum == undefined) {
			minimum = 0;
		}
		
		var totalPop = 0;
		var renamed = villageCoord == null ? "" : villageCoord + seperator;
		var sent = "";
		$.each(world_data.units, function (i, val) {
			var amount = unitsSent[val];
			if (amount != 0) {
				if (val == "snob") {
					renamed += trans.tw.units.names[val] + "! ";
				}
				else if (amount >= minimum) {
					sent += ", " + trans.tw.units.shortNames[val] + "=" + amount;
				}
				
				totalPop += amount * world_data.unitsPositionSize[i];
			}
		});
	
		if (player) {
			renamed += '(' + player + ')' + seperator;
		}
		if (sent.length > 2) {
			sent = sent.substr(2);
		}
	
		if (isSupport) {
			sent += seperator + "(" + trans.sp.all.populationShort + ": " + formatNumber(totalPop) + ")";
		}
		
		if (user_data.attackAutoRename.addHaul && typeof haulDescription !== 'undefined') {
			sent += " (" + trans.tw.command.haul + " " + haulDescription + ")";
		}
	
		return renamed + sent;
	}
	
	function calcTroops(units) {
		// units is an array of numbers; keys are the unit names (without unit_)
		var x = {};
		x.totalDef = 0;
	
		function removeElement(arr, element) {
			var idx = arr.indexOf(element);
			if (idx != -1) {
				arr.splice(idx, 1);
			}
			return arr;
		}
	
		// heavy doesn't count in determining whether the village is def/off (since you got some crazy guys using hc as offense and defense:)
		$.each(removeElement(world_data.units_def, 'heavy'), function (i, v) { x.totalDef += units[v] * world_data.unitsSize['unit_' + v]; });
		x.totalOff = 0;
		$.each(removeElement(world_data.units_off, 'heavy'), function (i, v) { x.totalOff += units[v] * world_data.unitsSize['unit_' + v]; });
	
		x.isDef = x.totalDef > x.totalOff;
		x.isScout = units.spy * world_data.unitsSize.unit_spy > x.totalDef + x.totalOff;
		x.isMatch = function (type) { return (type == 'all' || (type == 'def' && this.isDef) || (type == 'off' && !this.isDef)); };
	
		x.getSlowest = 
			function () {
				var slowest_unit = null;
				$.each(world_data.units, function (i, v) {
					if (units[v] > 0 && (slowest_unit == null || world_data.unitsSpeed["unit_" + slowest_unit] < world_data.unitsSpeed["unit_" + v])) {
						slowest_unit = v;
					}
				});
				return slowest_unit;
			};
	
		x.colorIfNotRightAttackType =
			function (cell, isAttack) {
				var isSet = false;
				if (units.snob != undefined && units.snob > 0) {
					if (isAttack) {
						if (units.snob > 1) {
							isSet = true;
							cell.css("background-color", user_data.colors.error).css("border", "1px solid black");
							cell.animate({
									width: "70%",
									opacity: 0.4,
									marginLeft: "0.6in",
									fontSize: "3em",
									borderWidth: "10px"
								}, 5000, function () {
									// Animation complete.
							});
						} else {
							return;
						}
					} else {
						isSet = true;
					}
				}
				else if (x.totalDef + x.totalOff < user_data.command.filterFakeMaxPop) {
					// fake
					return;
				}
	
				if (!isSet && (x.isScout || x.isMatch(isAttack ? 'off' : 'def'))) {
					return;
				}
				cell.css("background-color", user_data.colors.error);
			};
			
		return x;
	}
	
	
	function stackDisplay(totalFarm, stackOptions) {
		// TODO: this function is only used on main village overview
		if (stackOptions == undefined) {
			stackOptions = {};
		}
		var farmSize = game_data.village.buildings.farm * world_config.farmLimit;
	
		var stackDesc = '<b>' + formatNumber(totalFarm);
		if (stackOptions.showFarmLimit && world_config.farmLimit > 0) {
			stackDesc += ' / ' + formatNumber(farmSize);
		}
	
		if (stackOptions.percentage) {
			stackDesc += ' (' + stackOptions.percentage + ')</b>';
		}
	
		var bgColor = getStackColor(totalFarm, farmSize);
		if (stackOptions.cell == undefined) {
			return {
				color: bgColor,
				desc: stackDesc,
				cssColor: "style='background-color:" + bgColor + "'"
			};
		} else {
			if (stackOptions.appendToCell) {
				stackOptions.cell.append(" &raquo; " + stackDesc);
			} else {
				stackOptions.cell.html(stackDesc);
			}
			if (!stackOptions.skipColoring) {
				stackOptions.cell.css("background-color", bgColor);
			}
		}
	}
	
	/**
	 * Gets the configured stack backgroundcolor for the given stackTotal
	 * @param stackTotal {number}
	 * @returns {color}
	 */
	function getStackColor(stackTotal) {
		var color = null,
	        arrayToIterate,
	        farmLimitModifier;
	
	    if (world_config.farmLimit > 0) {
	        arrayToIterate = user_data.farmLimit.acceptableOverstack;
	        farmLimitModifier = 30 * world_config.farmLimit;
	    } else {
	        arrayToIterate = user_data.farmLimit.unlimitedStack;
	        farmLimitModifier = 1; // = No modifier
	    }
	
	    if (arrayToIterate.length > 0) {
	        $.each(arrayToIterate, function (index, configValue) {
	            if (color == null && stackTotal < farmLimitModifier * configValue) {
	                if (index === 0) {
	                    color = "";
	                } else {
	                    color = user_data.farmLimit.stackColors[index - 1];
	                    //q(stackTotal +"<"+ farmLimitModifier +"*"+ configValue);
	                    //q("return " + (index - 1) + "->" + color);
	                }
	                return false;
	            }
	        });
	
	        if (color != null) {
	            //q(stackTotal + " -> " + color);
	            return color;
	        }
	        return user_data.farmLimit.stackColors[user_data.farmLimit.stackColors.length - 1];
	    }
	
		return "";
	}
	var modernizr = (function () {
		// Difference in capital letter with the Modernizr library
		// So nothing will break should TW start making use of it
		return {
			localstorage: (function supports_html5_storage() {
				try {
					return 'localStorage' in window && window['localStorage'] !== null;
				} catch (e) {
					return false;
				}
			})()
		};
	})();
	
	var pers;
	(function (pers) {
	    function getKey(key) {
	        return 'sangu_' + key;
	    }
	
		function getWorldKey(key) {
			return 'sangu_' + game_data.world + '_' + key;
		}
	
		function getCookie(key) {
			key = getWorldKey(key);
			return (function() {
				var x, cooks, cookie;
				if (document.cookie.match(/;/)) {
					cooks = document.cookie.split("; ");
					for (x = 0; x < cooks.length; x++) {
						cookie = cooks[x];
						if (cookie.match(key + "=")) {
							return cookie.replace(key + "=", "");
						}
					}
				} else {
					if (document.cookie.match(key + "=")) {
						return document.cookie.replace(key + "=", "");
					}
				}
	
				return '';
			})();
		}
		
		function getGlobal(key) {
	        key = getKey(key);
			if (modernizr.localstorage) {
				var value = localStorage[key];
				return typeof value === 'undefined' ? '' : value;
			} else {
				return getCookie(key);
			}
		}
		
		function getSession(key) {
			key = getWorldKey(key);
			if (modernizr.localstorage) {
				var value = sessionStorage[key];
				return typeof value === 'undefined' ? '' : value;
			} else {
				return getCookie(key);
			}
		}
		
		function get(key) {
			return getGlobal(key);
		}
		
		function setCookie(key, value, expireMinutes) {
			key = getWorldKey(key);
			(function() {
				var date_obj = new Date(),
					time = date_obj.getTime();
				if (typeof expireMinutes === 'undefined') {
					time += 60 * 1000 * 24 * 356;
				} else {
					time += expireMinutes * 1000 * 60;
				}
				date_obj.setTime(time);
	
				document.cookie = key + "=" + value + ";expires=" + date_obj.toGMTString() + ";";
			})();
		}
		
		function setGlobal(key, value) {
	        key = getKey(key);
			if (modernizr.localstorage) {
				localStorage[key] = value;
			} else {
				setCookie(key, value);
			}
		}
		
		function setSession(key, value) {
			key = getWorldKey(key);
			if (modernizr.localstorage) {
				sessionStorage[key] = value;
			} else {
				setCookie(key, value);
			}
		}
	
	    function set(key, value) {
	        setGlobal(key, value);
	    }
		
		function removeSessionItem(key) {
	        key = getKey(key);
			if (modernizr.localstorage) {
				sessionStorage.removeItem(key);
			}
			// fuck cookies
		}
	
	    function clear() {
	        if (modernizr.localstorage) {
	            sessionStorage.clear();
	            localStorage.clear();
	        }
	    }
		
		pers.removeSessionItem = removeSessionItem;
		pers.getWorldKey = getWorldKey;
	    pers.getKey = getKey;
		pers.set = set;
		pers.setCookie = setCookie;
		pers.setGlobal = setGlobal;
		pers.setSession = setSession;
		pers.get = get;
		pers.getCookie = getCookie;
		pers.getGlobal = getGlobal;
		pers.getSession = getSession;
	    pers.clear = clear;
	})(pers || (pers = {}));
	$.fn.sortElements = (function () {
		var sort = [].sort;
		return function (comparator, getSortable) {
			getSortable = getSortable || function () { return this; };
			var placements = this.map(function () {
				var sortElement = getSortable.call(this),
				parentNode = sortElement.parentNode,
				// Since the element itself will change position, we have
				// to have some way of storing its original position in
				// the DOM. The easiest way is to have a 'flag' node:
				nextSibling = parentNode.insertBefore(
					document.createTextNode(''),
					sortElement.nextSibling
				);
	
				return function () {
					if (parentNode === this) {
						throw new Error("You can't sort elements if any one is a descendant of another.");
					}
	
					// Insert before flag:
					parentNode.insertBefore(this, nextSibling);
					// Remove flag:
					parentNode.removeChild(nextSibling);
				};
			});
	
			return sort.call(this, comparator).each(function (i) {
				placements[i].call(getSortable.call(this));
			});
		};
	})();
	
	$.fn.outerHTML = 
		function () { 
			return $('<div>').append(this.clone()).remove().html();
		};
	
	/**
	 * Create a dialog box on a fixed position with self closing functionality
	 * @param {string} id The DOM ID of the div
	 * @param content .title: Short title. Defaults to Sangu Package.
	 *                .body: The HTML to show in the body of the tooltip
	 * @param options .top: CSS top in px
	 *                .left: CSS left in px
	 *                .width: CSS width in px. Defaults to 350.
	 *                .showOnce: If true the tooltip will never be shown again once closed. Defaults to true.
	 */
	function createFixedTooltip(id, content, options) {
		if (typeof options.width === 'undefined') {
			options.width = 350;
		}
		if (typeof options.showOnce === 'undefined') {
			options.showOnce = true;
		}
		if (typeof content.title === 'undefined') {
			content.title = "Sangu Package";
		}
		
		var persKey = "fixedToolTip_"+id; // Other implementations depend on this naming
		if (!options.showOnce || pers.getGlobal(persKey) == '') {
			content_value.after('<div id="' + id + '" class="vis" style="z-index: 100001; margin: 2px; '
				+ 'width: '+options.width+'px; display: block; position:absolute; top: '+options.top+'px; left: '+options.left+'px; border: 1px solid black; background-color: #F4E4BC">'
				+ '<h4>' + '<img class="'+id+'closeTooltip" style="float: right; cursor: pointer;" src="graphic/minus.png">' + content.title + '</h4>'
				+ '<div style="display: block; text-align: left; margin: 2px;">' + content.body + '</div>'
				+ '</div>');
	
			$("."+id+"closeTooltip", "#" + id).click(function() {
				$("#" + id).hide();
				if (options.showOnce) {
					pers.setGlobal(persKey, "1");
				}
			});
		}
	}
	
	function createSpoiler(button, content, opened) {
		return "<div id='spoiler'><input type='button' value='" + button + "' onclick='toggle_spoiler(this)' /><div><span style='display:" + (opened ? 'block' : 'none') + "'>" + content + "</span></div></div>";
	}
	
	function createMoveableWidget(id, title, content) {
		return '<div id=' + id + '+ class="vis moveable widget"><h4><img style="float: right; cursor: pointer;"'
				+ ' onclick="return VillageOverview.toggleWidget(\'' + id + '\', this);" src="graphic/minus.png">'
				+ title + '</h4><div style="display: block;">' + content + '</div></div>';
	}
	
	function printCoord(village, desc) {
		if (server_settings.coordinateLinkAllowed) {
			return "<a href=# onclick=\"$('#inputx').val("+village.x+"); $('#inputy').val("+village.y+"); return false;\">" + desc + "</a>";
		} else {
			return "<b>" + desc + "</b> <input type=text onclick='this.select(); this.focus()' size=7 value='" + village.x + '|' + village.y + "'>";
		}
	}

	// Activate / deactivate the tool
	var isSanguActive = pers.get("sanguActive") == "true";
	if (location.href.indexOf('changeStatus=') > -1) {
		isSanguActive = location.href.indexOf('changeStatus=true') > -1;
		pers.set("sanguActive", isSanguActive);
		pers.setGlobal("fixedToolTip_sanguActivatorTooltip", 1);
	}
	
	var activatorImage = isSanguActive ? "green" : 'red';
	var activatorTitle = (!isSanguActive ? trans.sp.sp.activatePackage : trans.sp.sp.deactivatePackage) + " (v" + sangu_version + ")";
	
	function isSanguCompatible() {
	    return sangu_version.indexOf(game_data.majorVersion) === 0;
	}
	
	// Check for new version
	var loginMonitor = pers.get("sanguLogin");
	if (typeof GM_xmlhttpRequest !== "undefined" && !isSanguCompatible() && loginMonitor !== '') {
	    var parts = loginMonitor.match(/(\d+)/g);
	    if (parseInt(parts[2], 10) != (new Date()).getDate()) {
	        GM_xmlhttpRequest({
	            method: "GET",
	            url: "http://www.sangu.be/api/sangupackageversion.php",
	            onload: function (response) {
	                console.log(response.status, response.responseText.substring (0, 80));
	            }
	        });
	
	    }
	}
	
	if (pers.get("forceCompatibility") === '' || pers.get("forceCompatibility") === 'false') {
	    if (isSanguActive) {
	        // Check compatibility with TW version
	        if (!isSanguCompatible()) {
	            try {
	                ScriptAPI.register('Sangu Package', sangu_version, 'Laoujin', server_settings.sanguEmail);
	            } catch (e) {
	                $("#script_list a[href$='mailto:"+server_settings.sanguEmail+"']").after(" &nbsp;<a href='' id='removeScriptWarning'>"+trans.sp.sp.removeScriptWarning+"</a>");
	                $("#removeScriptWarning").click(function() {
	                    pers.set("forceCompatibility", "true");
	                });
	            }
	        }
	    }
	
	    // gray icon when tw version doesn't match
	    if (!isSanguCompatible()) {
	        activatorImage = "grey";
	        activatorTitle = trans.sp.sp.activatePackageWithCompatibility.replace("{version}", sangu_version);
	    }
	}
	
	$("#storage").parent()
		.after(
			"<td class='icon-box' nowrap><a href=" + location.href.replace("&changeStatus=" + isSanguActive, "") 
			+ "&changeStatus=" + (!isSanguActive) + "><img src='graphic/dots/" + activatorImage 
			+ ".png' title='" + activatorTitle 
			+ "' id='sangu_activator' /></a>&nbsp;</td>");
	
	// First time run message - Position beneath resource/storage display
	if (!isSanguActive) {
	    (function() {
	        var position = $("#storage").position(),
	            options = {
	                left: position.left - 150,
	                top: position.top + 35
	            },
	            content = {body: trans.sp.sp.firstTimeRun.replace("{img}", "<img src='graphic/dots/red.png' />")};
	
	        createFixedTooltip("sanguActivatorTooltip", content, options);
	    }());
	} else {
	    (function() {
	        var position = $("#storage").position(),
	            options = {
	                left: position.left - 150,
	                top: position.top + 35
	            },
	            content = {body: '<b>Sangu stelt zijn nieuwste tool voor: <a href="http://sangu.be">TW Tactics</a>!</b><br><br>Probeer het zeker eens voordat je vijanden het tegen jou beginnen te gebruiken!'};
	
	        createFixedTooltip("twTacticsTooltip", content, options);
	    }());
	}

    // User config
	// Configure the Sangu Package
	
	/*
	user_data = pers.get('sangusettings');
	if (user_data !== '') {
	    user_data = JSON.parse(user_data);
	
	} else {*/
	    user_data = {
	        proStyle: true,
	        displayDays: false, /* true: display (walking)times in days when > 24 hours. false: always displays in hours */
	        walkingTimeDisplay: "{duration} || {arrival}",
	
	        colors: {
	            error: "#FF6347",
	            good: "#32CD32",
	            special: "#00FFFF",
	            neutral: "#DED3B9"
	        },
	
	        global: {
	            resources: {
	                active: true, /* All pages: true/false: color the resources based on how much the storage is filled */
	                backgroundColors: ['#ADFF2F', '#7FFF00', '#32CD32', '#3CB371', '#228B22', '#FFA500', '#FF7F50', '#FF6347', '#FF4500', '#FF0000'], /* All pages: Colors used for the previous setting. First is least filled, last is most filled storage place */
	                blinkWhenStorageFull: true /* All pages: Blink the resources if the storage is full */
	            },
	            incomings: {
	                editLinks: true, /* All pages: Edit the incoming attacks/support links: add "show all groups" and "show all pages" to the original links */
	                track: true,
	                indicator: "({current} <small>{difference}</small>)",
	                indicatorTooltip: "Laatste tijdcheck: {elapsed} geleden",
	                lastTimeCheckWarning: "Aanvallen: {difference}. Laatste tijdcheck: {elapsed} geleden"
	            },
	            visualizeFriends: true,
	            duplicateLogoffLink: false
	        },
	
	        scriptbar: {
	            editBoxCols: 700,
	            editBoxRows: 12
	        },
	
	        main: {
	            villageNames: [], /* Add village names to the village headquarters to quickly edit the village name to a preset name. Set to [] or null to disable, for 1 village name use ['MyVillageName'] or for more names: ['name1', 'name2', 'name3'] */
	            villageNameClick: true, /* true: one of the previous button clicked automatically changes the village name. false: only fills in the name in the textbox but does not click the button */
	            ajaxLoyalty: true /* Get the loyalty at the building construction/destruction page */
	        },
	
	        other: {
	            calculateSnob: true, /* nobles: calculates how many nobles can be produced immediately */
	            reportPublish: ["own_units", "own_losses", "opp_units", "opp_losses", "carry", "buildings", "own_coords", "opp_coords", "belief"] /* Publishing report: automatically check the 'show' checkboxes */
	        },
	
	        market: {
	            resizeImage: true,
	            autoFocus: true
	        },
	
	        farmLimit: {
	            stackColors: ['#DED3B9', '#3CB371', '#FF6347'],
	            acceptableOverstack: [0.5, 1.2, 1.35], /* Different pages: % of acceptable overstack (only relevant for farmlimit worlds) */
	            unlimitedStack: [24000, 60000, 100000] /* Different pages: Calculate stacks based on total troops (for non farmlimit worlds) */
	        },
	
	        command: { /* features for the own troops overview page */
	            changeTroopsOverviewLink: true, /* Change the link to the own troops overview */
	            middleMouseClickDeletesRow2: false, /* Let the new default overwrite the old one */
	
	            filterMinPopulation: 18000, /* Default number filled in to filter on village stack */
	            filterMinDefaultType: 'axe', /* This unit type is by default selected in the filter dropdown */
	            filterMinDefault: 5000, /* The default number filled in to filter on troop amounts */
	            filterMin: { axe: 7000, spear: 3000, archer: 3000, heavy: 500, catapult: 50, spy: 50, light: 2000, marcher: 2000, ram: 1, catapult: 50, snob: 2 }, /* Default filter numbers for the other units */
	            filterMinOther: 5000, /* Use this number as the default when the unit is not present in filterMin */
	            filterAutoSort: true, /* Automatically sort the list on walking distance when entering a target village */
	
	            /* These features apply to the commands overview page */
				sumRow: true, /* Add a totalrow between different villages */
	            filterFakeMaxPop: 300, /* Commands fake filter: Everything below 300 pop is considered a fake attack */
	            bbCodeExport: { /* BB code export */
	                requiredTroopAmount: 100
	            }
	        },
	
	        incomings: {
	            attackIdDescriptions: [
	                {minValue: 10, text: "&nbsp;"},
	                {minValue: 50, text: "10-50"},
	                {minValue: 100, text: "50-100"},
	                {minValue: 200, text: "100-200"},
	                {minValue: 500, text: "200-500"},
	                {minValue: 1000, text: "500-1000"},
	                {minValue: 5000, text: "1000-5000"}
	            ],
	            attackIdHigherDescription: "5000+"
	        },
	
	
	        overviews: {
	            addFancyImagesToOverviewLinks: true
	        },
	
	        incoming: { /* Features for the built in TW tagger */
	            autoOpenTagger: true, 		/* Open the tagger automatically if the incoming attack has not yet been renamed */
	            forceOpenTagger: true, 	/* Always open the tagger automatically */
	            renameInputTexbox: "{unit} ({xy}) {player} F{fields}{night}", /* Possibilities: {id}:internal tw attack id {unit}: short unitname {xy}: coordinates {player} {village}: full village name {c}: continent {fields} distance between the villages {night} indication when attack arrives during the nightbonus. Set to "" to disable. */
	            villageBoxSize: 600, 			/* Adjust the width of the table with the village information (support for 2-click) */
	            invertSort: true		/* true=noblemen at the top and scouts at the bottom of the table */
	        },
	
	        overview: { /* The default village overview page */
	            ajaxSeperateSupport: true, /* Village overview: Seperate own and supported troops */
	            ajaxSeperateSupportStacks: true, /* Village overview: Calculate stacks for own and supported troops */
	            canHideDiv: true
	        },
	
	        mainTagger2: {
	            active: true,
	            autoOpen: true,
	            inputBoxWidth: 300,
	            defaultDescription: "{xy} OK",
	            otherDescs:
	                [
	                    { active: true, name: "Dodgen", hitKey: "D", renameTo: "{xy}----------------------------------------- DODGE THIS" },
			    { active: true, name: "Nacht", hitKey: "N", renameTo: "{xy} NIGHTBONUS" },
			    { active: true, name: "Check stack", hitKey: "P", renameTo: "{xy}----------------------------------------- CHECK STACK" },
			    { active: true, name: "Timen!", hitKey: "T", renameTo: "{xy}***************************************** TIME IT!" },
			    { active: true, name: "Edelen!", hitKey: "E", renameTo: "{xy}----------------------------------------- NOBLE!!" },
			    { active: false, name: "Leeg1", hitKey: "L", renameTo: "It has to be, automatically" },
			    { active: false, name: "Leeg2", hitKey: "U", renameTo: "Check it out, you'd better work it out" },
			    { active: false, name: "Leeg3", hitKey: "Y", renameTo: "Change to another route" },
			    { active: false, name: "Leeg4", hitKey: "O", renameTo: "My techniques, strategies, abilities" }
	                ],
	            keepReservedWords: true,
	            reservedWords: [
	                "Edel.", "Edelman",
	                "Ram", "Kata.", "Katapult",
	                "Zcav.", "Zware cavalerie",
	                "Lcav.", "Lichte Cavalerie", "Bereden boog", "Bboog.",
	                "Verk.", "Verkenner",
	                "Bijl", "Zwaard", "Speer", "Boog",
	                "Ridder"
	                ],
	            autoOpenCommands: false,
	            minutesDisplayDodgeTimeOnMap: 3,
	            minutesWithoutAttacksDottedLine: 3 * 60,
	            colorSupport: '#FFF5DA' /* Main village overview: give incoming support a different background color */
	        },
	
	        villageInfo4: [
	            {
	                /* On info_village page add extra link to attack. */
	                active: true,
	                off_link: {
	                    name: "Aanvalleuh!",
	                    group: 0,
	                    filter: {
	                        active: true,
	                        unit: "axe",
	                        amount: 5000
	                    },
	                    sort: true,
	                    changeSpeed: "ram",
	                    icon: "graphic/unit/unit_knight.png"
	                },
	                def_link: {
	                    name: "Verdedigen!",
	                    group: 0,
	                    filter: {
	                        active: true,
	                        unit: "spear",
	                        amount: 4000
	                    },
	                    sort: true,
	                    changeSpeed: "spear",
	                    icon: "graphic/command/support.png"
	                }
	            },
	            {
	                /* On info_village page add extra link to attack. */
	                active: false,
	                off_link: {
	                    name: "&raquo; off2",
	                    group: 0,
	                    filter: {
	                        active: false,
	                        unit: "axe",
	                        amount: 4000
	                    },
	                    sort: true,
	                    changeSpeed: "ram"
	                },
	                def_link: {
	                    name: "&raquo; Snelle Os!",
	                    group: 0,
	                    filter: {
	                        active: true,
	                        unit: "spear",
	                        amount: 1000
	                    },
	                    sort: true,
	                    changeSpeed: "spear"
	                }
	            }
	        ],
	
	        resources: {
	            requiredResDefault: 250000,
	            requiredMerchants: 50,
	            filterMerchants: true,
	            filterRows: false,
	            bbcodeMinimumDiff: 50000,
				highlightColor: "#FF7F27"
	        },
	
	        jumper: {
	            enabled: true,
	            autoShowInputbox: false
	        },
	
	        attackAutoRename: {
	            active: true,
	            addHaul: false
	        },
	
	        confirm: {
	            addExtraOkButton: false,
	            replaceNightBonus: true,
	            replaceTribeClaim: true,
	            addCatapultImages: true
	        },
	
	        place: {
	            attackLinks: {
	                scoutVillage: 100,
	                scoutPlaceLinks: [5, 100, 500],
					scoutPlaceLinksName: "Scout{amount}",
					
	                fakePlaceLink: true,
	                fakePlaceExcludeTroops: [],
					fakePlaceLinkName: "Fake",
					
	                noblePlaceLink: true, /* (de)Activate all noble links */
					noblePlaceLinkFirstName: "NobleFirst", /* Name for the first noble which has most troops */
					
					noblePlaceLinkSupportName: "NobleMin", /* snob with only minimal support */
					noblePlaceLinksForceShow: true, /* Show NobleMin also where is only one 1 snob in the village */
					nobleSupport: [
						{ amount: 50, unit: 'light', villageType: 'off' }, 
						{ amount: 50, unit: 'heavy', villageType: 'def'}
					],
					
					noblePlaceLinkDivideName: "NobleDivide",
	                noblePlaceLinkDivideAddRam: false /* false: Rams are not sent along with NobleDivide */
	            },
	            customPlaceLinks:
	                [
	                    // use minus zero numbers to leave so many units at home
	                    { active: true, type: 'def', name: 'AllDef', spear: 25000, heavy: 5000, archer: 25000, sword: 25000, sendAlong: 0 },
	                    { active: true, type: 'def', name: '1/2-Zc', spear: 4000, heavy: 1000, sendAlong: 500 },
	                    { active: true, type: 'off', name: 'Smart'/*, spear: 25000*/, sword: -10, axe: 25000, spy: 1, light: 5000/*, heavy: 5000*/, marcher: 5000, ram: 5000, catapult: 5000, sendAlong: 0 },
	                    { active: true, type: 'off', name: 'Bijl', spear: 25000, axe: 25000, spy: 1, light: 5000, heavy: 5000, marcher: 5000, sendAlong: 0 },
	                    { active: true, type: 'off', name: 'Zwaard', spear: 25000, sword: -10, axe: 25000, spy: 1, light: 5000, heavy: 5000, marcher: 5000, sendAlong: 0, required: ['sword', 1] },
	
	                    { active: false, type: 'def', name: 'AlleDef', spear: 25000, sword: 25000, heavy: 5000, archer: 25000, sendAlong: 0 },
	                    { active: false, type: 'def', name: '3deZc', spear: 2500, heavy: 650, sendAlong: 0 },
	                    { active: false, type: 'def', name: '4deZc', spear: 2000, heavy: 500, sendAlong: 0 },
	                    { active: false, type: 'def', name: 'HelftZw', spear: 5000, sword: 5000, sendAlong: 500 },
	                    { active: false, type: 'def', name: '3deZw', spear: 3300, sword: 3300, sendAlong: 0 },
	                    { active: false, type: 'def', name: '4deZw', spear: 2500, sword: 2500, sendAlong: 0 }
	                ]
	        },
	
	        /**
	         * units_support_detail: options on the 2 def troop overview pages
	         * on bbcode restack - and others!!)
	         */
	        restack: {
	            to: 72000,
	            requiredDifference: 1000,
	            fieldsDistanceFilterDefault: 30,
	            filterReverse: true,
	            autohideWithoutSupportAfterFilter: true,
	            calculateDefTotalsAfterFilter: true,
	            defaultPopulationFilterAmount: 80000, /* this isn't related to restack */
	            removeRowsWithoutSupport: false
	        },
	
	        showPlayerProfileOnVillage: false,
	        profile: {
	            show: true,
	            moveClaim: true,
	            mapLink: { 
					show: true, 
					fill: '#000000', 
					zoom: '200', 
					grid: true, 
					playerColor: '#ffff00', 
					tribeColor: '#0000FF', 
					centreX: 500, 
					centreY: 500, 
					ownColor: '#FFFFFF', 
					markedOnly: true, 
					yourTribeColor: "#FF0000"
				},
	            playerGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false]], // small / big / false
	            tribeGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false], ["members", 'big', true]],
	            twMapPlayerGraph: { player: [true, true], p_player: [false, false], oda_player: [true, false], odd_player: [true, false], ods_player: [true, false] },
	            twMapTribeGraph: { tribe: [true, true], p_tribe: [false, false], oda_tribe: [true, false], odd_tribe: [true, false] },
	
	            popup: { 
					show: true, 
					width: 900, 
					height: 865,
					left: 50,
					top: 50
				}
	        },
	        smithy:
	            [
	                ['offense', { spear: [3, 3], sword: [1, 1], axe: [3, 3], spy: [0, 0], light: [3, 3], heavy: [3, 3], ram: [2, 2], catapult: [0, 0]}],
	                ['defense', { spear: [3, 3], sword: [1, 1], axe: [0, 3], spy: [0, 3], light: [0, 3], heavy: [3, 3], ram: [0, 1], catapult: [1, 3]}],
	                ['catapult', { spear: [2, 3], sword: [1, 1], axe: [3, 3], spy: [0, 3], light: [2, 3], heavy: [3, 3], ram: [0, 0], catapult: [2, 3]}]
	            ],
	        buildings: {
	            main: [20, 20],
	            barracks: [25, 25],
	            stable: [20, 20],
	            garage: [1, 5],
	            church: [0, 1],
	            church_f: [0, 1],
	            snob: [1, 3],
	            smith: [20, 20],
	            place: [1, 1],
	            statue: [0, 1],
	            market: [10, 20],
	            wood: [30, 30],
	            stone: [30, 30],
	            iron: [30, 30],
	            farm: [30, 30],
	            storage: [30, 30],
	            hide: [0, 10],
	            wall: [20, 20]
	        }
	    };
	//}
	
	(function() {
	    var saved_data = pers.get('sangusettings');
	    if (saved_data !== '') {
	        user_data = $.extend(true, user_data, JSON.parse(saved_data));
	    }
	}());

    if (isSanguActive) {
		// world config: global game settings
		world_config = {
			hasMilitia: false,
			nightbonus: {
				active: false,
				from: 0, 
				till: 0
				},
			smithyLevels: true,
			hasChurch: false,
			hasArchers: false,
			hasKnight: false,
			speed: 1,
			unitSpeed: 1,
			farmLimit: 0,
			minFake: 0,
			hasMinFakeLimit: false,
			coins: false,
			maxNobleWalkingTime: 999
		};
		
		if (pers.get('worldconfig') !== '') {
			world_config = JSON.parse(pers.get("worldconfig"));
			
		} else {
			// load new world through tw API
			if (server_settings.ajaxAllowed) {
				function world_config_setter_unit(configBag, unitInfoXml) {
					configBag.hasMilitia = $("config militia", unitInfoXml).length !== 0;
				}
				
				function world_config_setter(configBag, infoXml) {
					configBag.nightbonus = {
						active: $("night active", infoXml).text() === "1",
						from: parseInt($("night start_hour", infoXml).text(), 10),
						till: parseInt($("night end_hour", infoXml).text(), 10)
						};
					configBag.smithyLevels = $("game tech", infoXml).text() === "1" || $("game tech", infoXml).text() === "0";
					configBag.hasChurch = $("game church", infoXml).text() !== "0";
					configBag.hasArchers = $("game archer", infoXml).text() !== "0";
					configBag.hasKnight = $("game knight", infoXml).text() !== "0";
					configBag.speed = parseFloat($("config speed", infoXml).text());
					configBag.unitSpeed = parseFloat($("config unit_speed", infoXml).text());
					configBag.farmLimit = parseInt($("game farm_limit", infoXml).text(), 10);
					configBag.minFake = parseInt($("game fake_limit", infoXml).text(), 10) / 100;
					configBag.hasMinFakeLimit = configBag.minFake > 0;
					configBag.coins = $("snob gold", infoXml).text() === "1";
					configBag.maxNobleWalkingTime = parseInt($("snob max_dist", infoXml).text(), 10) * configBag.speed * configBag.unitSpeed;
				}
				
				function world_config_getter(world) {
					// world nl: http://nl16.tribalwars.nl/
					// world de: http://de90.die-staemme.de/
					if (typeof world === 'undefined') world = '';
					
					var world_config = {};
					$.ajax({
						url: world + "interface.php?func=get_unit_info",
						async: false,
						success: function(xml) {
							world_config_setter_unit(world_config, xml);
						}
					});
				
					$.ajax({
						url: world + "interface.php?func=get_config",
						async: false,
						success: function(xml) {
							world_config_setter(world_config, xml);
						}
					});
					return world_config;
				}
				world_config = world_config_getter();
				
			} else {
				// Not allowed to get data with ajax: need to store the configuration here
				//world_config = (function() {
					// paste the world configurations for all worlds on servers that disallow ajax
				//})();
		        alert("No configurations present for this server! (see world_config.js)\nContinueing with default settings.");
			}
			
			pers.set("worldconfig", JSON.stringify(world_config));
		}
		// world config
		// RESOURCES
		world_data.resources = ['holz', 'lehm', 'eisen'];
		world_data.resources_en = ['wood', 'stone', 'iron'];
		
		// BUILDINGS
		world_data.buildingsSize =
			[
			["main", [5, 6, 7, 8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99, 116, 135, 158, 185, 216, 253, 296, 347, 406, 475]],
			["barracks", [7, 8, 10, 11, 13, 15, 18, 21, 25, 29, 34, 39, 46, 54, 63, 74, 86, 101, 118, 138, 162, 189, 221, 259, 303]],
			["stable", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99, 115, 135, 158]],
			["garage", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72]],
			["snob", [80, 94, 110]],
			["smith", [20, 23, 27, 32, 37, 44, 51, 60, 70, 82, 96, 112, 132, 154, 180, 211, 247, 289, 338, 395]],
			["place", [0]],
			["market", [20, 23, 27, 32, 37, 44, 51, 60, 70, 82, 96, 112, 132, 154, 180, 211, 247, 289, 338, 395, 462, 541, 633, 740, 866]],
			["wood", [5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 21, 24, 28, 33, 38, 43, 50, 58, 67, 77, 89, 103, 119, 138, 159, 183, 212, 245, 283, 326]],
			["stone", [10, 11, 13, 15, 17, 19, 22, 25, 29, 33, 37, 42, 48, 55, 63, 71, 81, 93, 106, 121, 137, 157, 179, 204, 232, 265, 302, 344, 392, 447]],
			["iron", [10, 12, 14, 16, 19, 22, 26, 30, 35, 41, 48, 56, 66, 77, 90, 105, 123, 144, 169, 197, 231, 270, 316, 370, 433, 507, 593, 696, 811, 949]],
			["farm", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
			["storage", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
			["hide", [2, 2, 3, 3, 4, 4, 5, 6, 7, 8]],
			["wall", [5, 6, 7, 8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99]]
			];
		
		world_data.buildingsPoints =
			[
			["main", [10, 12, 14, 17, 21, 25, 30, 36, 43, 52, 62, 74, 89, 107, 128, 145, 185, 222, 266, 319, 383, 460, 552, 662, 795, 954, 1145, 1648, 1978]],
			["barracks", [16, 19, 23, 28, 33, 40, 48, 57, 69, 83, 99, 119, 143, 171, 205, 247, 296, 355, 426, 511, 613, 736, 883, 1060, 1272]],
			["stable", [20, 24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308, 370, 444, 532, 639]],
			["garage", [24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308]],
			["snob", [512, 614, 737]],
			["smith", [19, 23, 27, 33, 39, 47, 57, 68, 82, 98, 118, 141, 169, 203, 244, 293, 351, 422, 506, 607]],
			["place", [0]],
			["market", [10, 12, 14, 17, 21, 25, 30, 36, 43, 52, 62, 74, 89, 107, 128, 154, 185, 222, 266, 319, 383, 460, 552, 662, 795]],
			["wood", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
			["stone", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
			["iron", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
			["farm", [5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989]],
			["storage", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
			["hide", [5, 6, 7, 9, 10, 12, 15, 18, 21, 26]],
			["wall", [8, 10, 12, 14, 17, 20, 24, 29, 34, 41, 50, 59, 71, 86, 103, 123, 148, 177, 213, 256]]
			];
		
		world_data.buildings = ["main", "barracks", "stable", "garage"];
		if (world_config.hasChurch) {
			world_data.buildingsSize.push(["church", [5000, 7750, 12013]]);
			world_data.buildingsSize.push(["church_f", [5]]);
			world_data.buildings.push("church");
		}
		world_data.buildings = world_data.buildings.concat(["snob", "smith", "place"]);
		if (world_config.hasKnight) {
			world_data.buildingsSize.push(["statue", [10]]);
			world_data.buildingsPoints.push(["statue", [24]]);
			world_data.buildings.push("statue");
		}
		world_data.buildings = world_data.buildings.concat(["market", "wood", "stone", "iron", "farm", "storage", "hide", "wall"]);
			
			
		// UNITS
		world_data.unitsSize = { "unit_spear": 1, "unit_sword": 1, "unit_axe": 1, "unit_spy": 2, "unit_light": 4, "unit_heavy": 6, "unit_ram": 5, "unit_catapult": 8, "unit_snob": 100 };
		world_data.unitsSpeed = { "unit_spear": 18, "unit_sword": 22, "unit_axe": 18, "unit_spy": 9, "unit_light": 10, "unit_heavy": 11, "unit_ram": 30, "unit_catapult": 30, "unit_snob": 35, "unit_merchant": 6 };
		
		world_data.units_def = ["spear", "sword", "heavy"];
		world_data.units_off = ["axe", "light", "heavy"];
		if (!world_config.hasArchers && !world_config.hasKnight) {
			world_data.unitsPositionSize = [1, 1, 1, 2, 4, 6, 5, 8, 100];
			world_data.units = ["spear", "sword", "axe", "spy", "light", "heavy", "ram", "catapult", "snob"];
		} else {
			world_data.units = ["spear", "sword", "axe"];
			world_data.unitsPositionSize = [1, 1, 1];
			if (world_config.hasArchers) {
				world_data.units_off.push("marcher");
				world_data.units_def.push("archer");
				$.extend(world_data.unitsSize, { "unit_archer": 1 }, { "unit_marcher": 5 });
				$.extend(world_data.unitsSpeed, { "unit_archer": 18 }, { "unit_marcher": 10 });
				world_data.units.push("archer");
				world_data.unitsPositionSize.push(1);
			}
			world_data.units.push("spy");
			world_data.unitsPositionSize.push(2);
			world_data.units.push("light");
			world_data.unitsPositionSize.push(4);
			if (world_config.hasArchers) {
				world_data.units.push("marcher");
				world_data.unitsPositionSize.push(5);
			}
			world_data.units.push("heavy");
			world_data.unitsPositionSize.push(6);
			world_data.units.push("ram");
			world_data.unitsPositionSize.push(5);
			world_data.units.push("catapult");
			world_data.unitsPositionSize.push(8);
			if (world_config.hasKnight) {
				$.extend(world_data.unitsSize, { "unit_knight": 10 });
				$.extend(world_data.unitsSpeed, { "unit_knight": 10 });
				world_data.units.push("knight");
				world_data.unitsPositionSize.push(10);
			}
			world_data.units.push("snob");
			world_data.unitsPositionSize.push(100);
		}
		
		// Unit speed adjustments
		world_config.maxNobleWalkingTime *= world_data.unitsSpeed.unit_snob;
		var speedModifier = world_config.speed * world_config.unitSpeed;
		if (speedModifier != 1) {
			$.each(world_data.unitsSpeed, function (index, value) {
				world_data.unitsSpeed[index] = world_data.unitsSpeed[index] / speedModifier;
			});
		}

		/**
		 * Adds a . thousands separator
		 */
		function formatNumber(nStr) {
			nStr += '';
			var x = nStr.split('.');
			var x1 = x[0];
			var x2 = x.length > 1 ? '.' + x[1] : '';
			var rgx = /(\d+)(\d{3})/;
			while (rgx.test(x1)) {
				x1 = x1.replace(rgx, '$1' + '.' + '$2');
			}
			return x1 + x2;
		}
		// DATETIME FUNCTIONS
		function prettyDate(diff, showSeconds) {
			diff = diff / 1000;
			if (diff < 0) {
				return "&nbsp;";
			}
			if (diff < 60) {
				if (showSeconds) {
					return diff + " " + trans.sp.tagger.sentSeconds;
				}
				return trans.sp.tagger.sentNow;
			}
			if (diff < 120) {
				return trans.sp.tagger.sent1Minute;
			}
			if (diff < 3600) {
				return Math.floor(diff / 60) + " " + trans.sp.tagger.sentMinutes;
			}
			if (diff < 7200) {
				return trans.sp.tagger.sent1Hour + ", " + Math.floor((diff - 3600) / 60) + " " + trans.sp.tagger.sentMinutes;
			}
			return Math.floor(diff / 3600) + " " + trans.sp.tagger.sentHours + ", " + Math.floor((diff % 3600) / 60) + " " + trans.sp.tagger.sentMinutes;
		}
		
		function twDurationFormat(num) {
			var days = 0;
			if (user_data.displayDays) {
				days = Math.floor(num / 1440);
			}
			num -= days * 1440;
			var hours = Math.floor(num / 60);
			num -= hours * 60;
			var mins = Math.floor(num);
			num -= mins;
			var secs = Math.round(num * 60);
		
			if (days > 0) {
				return days + '.' + pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2);
			} else {
				return pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2);
			}
		}
		
		function twDateFormat(dat, alwaysPrintFullDate, addYear) {
			var day = dat.getDate();
			var cur = new Date().getDate();
		
			if (!alwaysPrintFullDate && day == cur) {
				return trans.tw.all.today + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2);
			}
			else if (!alwaysPrintFullDate && day == cur + 1) {
				return trans.tw.all.tomorrow + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2);
			}
			else if (addYear) {
				return trans.tw.all.dateOn + " " + dat.getDate() + "." + pad(dat.getMonth() + 1, 2) + "." + (dat.getFullYear() + '').substr(2) + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2); // + "(" + dat.getFullYear() + ")";
			} else {
				return trans.tw.all.dateOn + " " + dat.getDate() + "." + pad(dat.getMonth() + 1, 2) + ". " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2); // + "(" + dat.getFullYear() + ")";
			}
		}
		
		function getTimeFromTW(str) {
			// NOTE: huh this actually returns the current date
			// with some new properties with the "str" time
			//17:51:31
			var timeParts = str.split(":");
			var seconds = timeParts[2];
			var val = {};
			val.hours = parseInt(timeParts[0], 10);
			val.minutes = parseInt(timeParts[1], 10);
			if (seconds.length > 2) {
				var temp = seconds.split(".");
				val.seconds = parseInt(temp[0], 10);
				val.milliseconds = parseInt(temp[1], 10);
			} else {
				val.seconds = parseInt(seconds, 10);
			}
			val.totalSecs = val.seconds + val.minutes * 60 + val.hours * 3600;
			return val;
		}
		
		function getDateFromTW(str, isTimeOnly) {
			//13.02.11 17:51:31
			var timeParts, seconds;
			if (isTimeOnly) {
				timeParts = str.split(":");
				seconds = timeParts[2];
				var val = new Date();
				val.setHours(timeParts[0]);
				val.setMinutes(timeParts[1]);
				if (seconds.length > 2) {
					var temp = seconds.split(".");
					val.setSeconds(temp[0]);
					val.setMilliseconds(temp[1]);
				} else {
					val.setSeconds(seconds);
				}
				return val;
			} else {
				var parts = str.split(" ");
				var dateParts = parts[0].split(".");
				timeParts = parts[1].split(":");
				seconds = timeParts[2];
				var millis = 0;
				if (seconds.length > 2) {
					var temp = seconds.split(".");
					seconds = temp[0];
					millis = temp[1];
				} if (dateParts[2].length == 2) {
					dateParts[2] = (new Date().getFullYear() + '').substr(0, 2) + dateParts[2];
				}
		
				return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0], timeParts[0], timeParts[1], seconds, millis);
			}
		}
		
		function getDateFromTodayTomorrowTW(str) {
			var currentT = new Date();
			var dateParts = [];
			var parts = $.trim(str).split(" ");
			if (str.indexOf(trans.tw.all.tomorrow) != -1) {
		        // morgen om 06:35:29 uur
				dateParts[0] = currentT.getDate() + 1;
				dateParts[1] = currentT.getMonth();
			} else if (str.indexOf(trans.tw.all.today) != -1) {
		        // vandaag om 02:41:40 uur
				dateParts[0] = currentT.getDate();
				dateParts[1] = currentT.getMonth();
			} else {
		        // op 19.05. om 11:31:51 uur
				dateParts = parts[1].split(".");
				dateParts[1] = parseInt(dateParts[1], 10) - 1;
			}
		
		    // last part is "hour" but there is a script from lekensteyn that
		    // corrects the projected arrival time each second
		    // the script has not been updated to add the word "hour" after the time.
			var timeParts = parts[parts.length - 2].split(":");
		    if (timeParts.length === 1) {
		        timeParts = parts[parts.length - 1].split(":");
		    }
		
			var seconds = timeParts[2];
			var millis = 0;
			if (seconds.length > 2) {
				var temp = seconds.split(".");
				seconds = temp[0];
				millis = temp[1];
			}
		
			return new Date(new Date().getFullYear(), dateParts[1], dateParts[0], timeParts[0], timeParts[1], seconds, millis);
		}
		
		function isDateInNightBonus(date) {
			if (!world_config.nightbonus.active) return false;
			return date.getHours() >= world_config.nightbonus.from && date.getHours() < world_config.nightbonus.till;
		}
		function getBuildingSpace() {
			var total = 0;
			for (var building = 0; building < world_data.buildingsSize.length; building++) {
				var b = world_data.buildingsSize[building];
				if (parseInt(game_data.village.buildings[b[0]], 10) > 0) {
					total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1];
				}
			}
			return total;
		}
		
		function getBuildingPoints() {
			var total = 0;
			for (var building = 0; building < world_data.buildingsPoints.length; building++) {
				var b = world_data.buildingsPoints[building];
				if (parseInt(game_data.village.buildings[b[0]], 10) > 0) {
					total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1];
				}
			}
			return total;
		}
		
		if (user_data.jumper.enabled) {
		    (function() {
		        //console.time("jumper");
		        try {
		            var cell = "<span style='display: none;' id=sanguJumperFrame>";
		            cell += "<input type=text type=text size=6 id=sangujumper style='height: 16px; border: 0; top: -2px; position: relative'>";
		            cell += "</span>";
		            cell += "&nbsp;<a href=# id=sangujumperOpen><span class='icon ally internal_forum' title='" + trans.sp.jumper.goToMap + "'></span></a>";
		            $("#menu_row2").append("<td>" + cell + "</td>");
		
		            $("#sangujumper").keyup(function (e) {
		                if (e.which == 13) {
		                    $("#sangujumperOpen").click();
		                }
		            });
		
		            $("#sangujumperOpen").click(function () {
		                var input = $("#sangujumper");
		                if ($("#sanguJumperFrame").is(":visible")) {
		                    var village = getVillageFromCoords(input.val(), true);
		                    if (village.isValid) {
		                        trackClickEvent("JumperOpen_RealValue");
		                        // Jump to coordinates on the map
		                        location.href = getUrlString("&screen=map&x=" + village.x + "&y=" + village.y);
		
		                    } else {
		                        // incorrect coordinates
		                        if (!$("#sangujumperpos").is(":visible")) {
		                            $("#sangujumperpos").show();
		                            input.css("border", "1px solid red");
		                        } else
		                            $("#sangujumperpos").hide();
		                    }
		                } else {
		                    // activate mapJumper
		                    var input = $("#sangujumper");
		                    if (input.val() == "") {
		                        $("#sanguJumperFrame").fadeIn();
		                    } else {
		                        $("#sanguJumperFrame").show();
		                        $("#sangujumperOpen").click();
		                    }
		                }
		
		                return false;
		            });
		
		            if (user_data.jumper.autoShowInputbox) {
		                $("#sangujumperOpen").click();
		            }
		        } catch (e) { handleException(e, "jumper"); }
		        //console.timeEnd("jumper");
		    }());
		}
		// Send usage statistics to GA once/day
		(function() {
		    //console.time("ga");
		    try {
		        var loginMonitor = pers.get("sanguLogin");
		        if (loginMonitor !== '') {
		            var parts = loginMonitor.match(/(\d+)/g);
		            loginMonitor = new Date(parts[0], parts[1]-1, parts[2]);
		
		            //if (Math.abs(loginMonitor.getTime() - (new Date()).getTime()) > 1000 * 3600 * 24) {
		            if (parseInt(parts[2], 10) != (new Date()).getDate()) {
		                loginMonitor = '';
		            }
		        }
		        if (loginMonitor === '') {
		            loginMonitor = new Date();
		            loginMonitor.setHours(0, 0, 0);
		            loginMonitor = loginMonitor.getFullYear() + '-' + pad(loginMonitor.getMonth()+1, 2) + '-' +  pad(loginMonitor.getDate(), 2);
		            trackEvent("ScriptUsage", "DailyUsage", loginMonitor);
		            pers.set("sanguLogin", loginMonitor);
		
		            // also log world/tribe usage
		            trackEvent("ScriptUsage", "WorldUsage", game_data.world);
		            trackEvent("ScriptUsage", "TribeUsage", game_data.world + " " + game_data.player.ally_id);
		            trackEvent("ScriptUsage", "HasPremium", game_data.player.premium ? "Yes" : "No");		// Do we need to support non PA users?
		            trackEvent("ScriptUsage", "HasAM", game_data.player.account_manager ? "Yes" : "No");	// Do we need to do stuff on the AM pages?
		        }
		    } catch (e) { handleException(e, "ga"); }
		    //console.timeEnd("ga");
		}());
		
		q("-------------------------------------------------------------------- Start: "+sangu_version);

        // BEGIN PAGE PROCESSING
        switch (current_page.screen) {
            case "overview":
                // MAIN VILLAGE OVERVIEW
                (function() {
                    /**
                     * The slowest unit in the village in the form unit_spear
                     */
                    var slowest_unit = null;

				(function() {
				        /**
				         * Each key is in the form unit_sword and holds the total amount of the type in the village
				         * (own and supporting troops combined)
				         */
				    var totalUnits = {},
				        /**
				         * Total population of all units (own + supporting)
				         */
				         totalFarm = 0,
				        /**
				         * Own population only (total - supporting)
				         */
				         ownFarmTotal = 0,
				        /**
				         * jQuery div with the troops in the village (becomes the own troops only div)
				         */
				         unitTable = $("#show_units"),
				        /**
				         * HTML table builder string for the supporting troops div
				         */
				         supportingTroopsTable = "<table class=vis width='100%'>";
				
				    try {
				        $("#show_units > h4").prepend(trans.sp.main.unitsReplacement);
				
				        // calculate current stack
				        $("table:first td", unitTable).not(":last").each(function () {
				            var unit = $('img', this)[0].src,
				                unitsSize,
				                unitAmount;
				
				            unit = unit.substr(unit.lastIndexOf('/') + 1);
				            unit = unit.substr(0, unit.lastIndexOf('.'));
				            unitsSize = world_data.unitsSize[unit];
				            unitAmount = $('strong', this);
				            unitAmount[0].id = "spAmount" + unit;
				            unitAmount = unitAmount[0].innerHTML;
				            if( unit.match("knight") && !unitAmount ) {
				                unitAmount = 1;
				            }
				            totalUnits[unit] = unitAmount;
				            totalFarm += unitsSize * unitAmount;
				
				            if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) {
				                slowest_unit = unit;
				            }
				        });
				
				        // fetch own troops
				        if (user_data.overview.ajaxSeperateSupport && totalFarm > 0) {
				            if (server_settings.ajaxAllowed) {
				                ajax("place",
				                    function (placeText) {
				                        if (placeText.find(".unitsInput").size() > 0) {
				                            slowest_unit = null;
				                            placeText.find(".unitsInput").each(function () {
				                                // separate own / supporting troops
				                                var unit = 'unit_' + this.id.substr(this.id.lastIndexOf("_") + 1);
				                                var unitAmount = $(this).next().text().substr(1);
				                                unitAmount = parseInt(unitAmount.substr(0, unitAmount.length - 1), 10);
				                                var unitsSize = world_data.unitsSize[unit];
				                                ownFarmTotal += unitsSize * unitAmount;
				
				                                var unitLabel = $("#spAmount" + unit);
				                                var supportingTroopsAmount = totalUnits[unit] - unitAmount;
				                                if (supportingTroopsAmount > 0) {
				                                    var unitDesc = $.trim(unitLabel.parent().text());
				                                    unitDesc = unitDesc.substr(unitDesc.indexOf(" ") + 1);
				                                    supportingTroopsTable +=
				                                        "<tr><td>" + unitLabel.prev().outerHTML()
				                                            + " <b>" + formatNumber(supportingTroopsAmount)
				                                            + "</b> "
				                                            + unitDesc + "</td></tr>";
				                                }
				
				                                if (unitAmount > 0) {
				                                    unitLabel.text(unitAmount);
				                                    if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) {
				                                        slowest_unit = unit;
				                                    }
				                                } else {
				                                    unitLabel.parent().parent().hide();
				                                }
				                            });
				
				                        } else {
				                            ownFarmTotal = totalFarm; // No rally point
				                        }
				                    }, {async: false});
				
				            } else {
				                ownFarmTotal = totalFarm; // No ajax
				            }
				
				            if (slowest_unit != null) {
				                $("#slowestUnitCell").html("<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png'>").attr("slowestUnit", slowest_unit);
				            }
				
				            if (ownFarmTotal > 0 && user_data.overview.ajaxSeperateSupportStacks) {
				                // stack in the village
				                unitTable.find("table:first").append("<tr><td><span class='icon header population' title='" + trans.sp.main.ownStackTitle + "'></span>" + stackDisplay(ownFarmTotal).desc + "</td></tr>");
				            }
				            if (totalFarm - ownFarmTotal > 0) {
				                // stack from other villages
				                supportingTroopsTable += "<tr><td><a href='" + getUrlString("screen=place&mode=units") + "'>&raquo; " + trans.sp.main.rallyPointTroops + "</a></td></tr>";
				                if (user_data.overview.ajaxSeperateSupportStacks) {
				                    (function() {
				                        var supportDisplay = stackDisplay(totalFarm - ownFarmTotal, { showFarmLimit: true });
				                        supportingTroopsTable +=
				                            '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + supportDisplay.color + '">'
				                                + '<span class="icon header population" title="' + trans.sp.main.supportingStackTitle
				                                + '"></span>'
				                                + '<b>' + supportDisplay.desc + '</b>' + '</td></tr>';
				                    }());
				                }
				
				                unitTable.after(createMoveableWidget("os_units", trans.sp.main.unitsOther, supportingTroopsTable + "</table>"));
				            }
				
				            // total stack
				            (function() {
				                var cell = $("#order_level_farm"),
				                    isClassicOverview = cell.length !== 0,
				                    percentage,
				                    stackDetails,
				                    cellContent;
				
				                if (isClassicOverview) {
				                    cell = cell.parent();
				                    if (game_data.player.premium) {
				                        cell = cell.next();
				                    }
				                    percentage = world_config.farmLimit == 0 ? "" : cell.children().html();
				                    stackDisplay(
				                        totalFarm, {
				                            showFarmLimit: true,
				                            percentage: percentage ? percentage.substr(0, percentage.indexOf('%') + 1) : "",
				                            cell: cell,
				                            appendToCell: !game_data.player.premium
				                        });
				
				                } else {
				                    stackDetails = stackDisplay(
				                        totalFarm, {
				                            showFarmLimit: true,
				                            percentage: $("#l_farm .building_extra").html()
				                        });
				
				                    //cellContent = '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + stackDetails.color + '">' + '<b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>' + '</td></tr>';
				                    cellContent = ' | <b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>';
				                    $("#show_units tbody:first td:last").append(cellContent).css("border-top", "1px solid #85550d").css("background-color", stackDetails.color);
				                }
				            }());
				        }
				    }
				    catch (e) {
				        handleException(e, "supportingunits");
				    }
				}());
				// Incoming/outgoing attacks
				var mainTable = $("#overviewtable");
				var incomingTable = $("#show_incoming_units table.vis:first");
				var outgoingTable = $("#show_outgoing_units");
				if (incomingTable.size() == 1 || outgoingTable.size() == 1) {
					if (incomingTable.size() == 1) {
						// tagger - add header
				        // inputBoxWidth : clicking the button focusses the newly created inputbox
				        //                 solution is to no longer show inputboxes on screen load
				        /*if (user_data.mainTagger2.inputBoxWidth != null) {
				            $("a.rename-icon", incomingTable).click();
				            $("span.quickedit", incomingTable).each(function() {
				                var renameSpan = this;
				                //setTimeout(function() {
				                $("span.quickedit-edit input:first", renameSpan).width(user_data.mainTagger2.inputBoxWidth);
				                //}, 1);
				            });
				        }*/
				
						if (user_data.mainTagger2.active && incomingTable.has("img[src*='attack']").size() != 0) {
							$("th:first", incomingTable).append("<input type=button value='" + trans.sp.tagger.openButton + "' id=openTaggerButton>");
							$("#openTaggerButton").click(function () {
								$(this).hide();
				
								incomingTable.click(function (e) {
									if (e.target.nodeName === 'IMG') {
										var direction = $(e.target).attr("direction");
										if (direction.length > 0) {
											var rowIndex = parseInt($(e.target).attr("rowIndex"), 10);
											direction = direction == "up";
											$("input.incAt", incomingTable).each( function () {
												var rowIndexAttributeValue = parseInt($(this).attr("rowIndex"), 10);
												if ((direction && rowIndexAttributeValue <= rowIndex) || (!direction && rowIndexAttributeValue >= rowIndex)) {
													$(this).prop("checked", true);
												} else {
													$(this).prop("checked", false);
												}
											});
										}
									}
								});
				
								var rows = $("tr", incomingTable);
								var dodgeMenu = "<tr><td>";
								dodgeMenu += '<img src="graphic/command/support.png" alt="" id="checkSupport" title="' + trans.sp.tagger.checkAllSupport + '" />';
								dodgeMenu += "&nbsp;";
								dodgeMenu += '<img src="graphic/command/return.png" alt="" id="uncheckSupport" title="' + trans.sp.tagger.uncheckAllSupport + '" />';
								dodgeMenu += "<th colspan=3>";
								dodgeMenu += trans.sp.tagger.renameTo + "<input type=textbox size=30 id=commandInput value='" + user_data.mainTagger2.defaultDescription + "'></th>";
								dodgeMenu += "<th>" + trans.sp.tagger.slowest + "</th>";
								dodgeMenu += "</td>";
								dodgeMenu += "<td colspan=1 id=slowestUnitCell>";
								if (slowest_unit != null) {
									dodgeMenu += "<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png' slowestunit='" + slowest_unit + "'>";
								}
								dodgeMenu += "</td></tr>";
								incomingTable.find("tbody:first").prepend(dodgeMenu);
				
								// checkbox manipulation
								$("#uncheckSupport").click(function () {
									$("input.incSupport", incomingTable).prop("checked", false);
								});
				
								$("#checkSupport").click(function () {
									$("input.incSupport", incomingTable).prop("checked", true);
								});
				
								var buttonParent = $("#commandInput").parent();
				                var commandIdToCoordCache = []; // No Ajax call on multiple renames with {xy}
								function renameCommand(commandName) {
				                    var dodgeCell; // capture last cell for dodgeCell coloring
				
				                    function getCommandIdFromDodgeCell(dodgeCell) {
				                        return Number(dodgeCell.find("span.quickedit").first().attr("data-id"));
				                    }
				
				                    function getVillageCoordsFromCommandId(commandId, callback) {
				                        if (server_settings.ajaxAllowed) {
				                            if (commandIdToCoordCache[commandId]) {
				                                callback(commandIdToCoordCache[commandId]);
				
				                            } else {
				                                ajax('screen=info_command&type=other&id='+commandId, function (overview) {
				                                    var originVillageLink = $(".village_anchor:first", overview).find("a[href]"),
				                                        originVillageDesc = originVillageLink.html(),
				                                        originVillage = getVillageFromCoords(originVillageDesc);
				
				                                    commandIdToCoordCache[commandId] = originVillage.coord;
				
				                                    callback(originVillage.coord);
				                                });
				                            }
				                        }
				                        callback('');
				                    }
				
				                    function executeRename(dodgeCell, commandName) {
				                        function keepTwIcon(dodgeCell, commandName) {
				                            var oldName = $(".quickedit-label", dodgeCell).text().toUpperCase(),
				                                newName = commandName,
				                                i,
				                                unitName;
				
				                            for (i = 0; i < user_data.mainTagger2.reservedWords.length; i++) {
				                                unitName = user_data.mainTagger2.reservedWords[i];
				                                if (oldName.indexOf(unitName.toUpperCase()) !== -1) {
				                                    newName = unitName + ' ' + newName;
				                                    return newName; // Only one icon possible
				                                }
				                            }
				                            return newName;
				                        }
				
				                        var button = dodgeCell.find("input[type='button']"),
				                            newName =  user_data.mainTagger2.keepReservedWords ? keepTwIcon(dodgeCell, commandName) : commandName;
				
				                        button.prev().val(newName);
				                        button.click();
				                    }
				
									$("input.taggerCheckbox", incomingTable).each(function () {
				                        var openRenameButton;
				
										if ($(this).is(":checked")) {
											dodgeCell = $(this).parent().next();
				
				                            openRenameButton = $("a.rename-icon", dodgeCell);
				                            if (openRenameButton.is(":visible")) {
				                                openRenameButton.click();
				                            }
				
				                            if (commandName.indexOf("{xy}") !== -1) {
				                                getVillageCoordsFromCommandId(getCommandIdFromDodgeCell(dodgeCell), function(vilCoords) {
				                                    var nameWithCoords = commandName.replace("{xy}", vilCoords);
													
				                                    setTimeout(executeRename(dodgeCell, nameWithCoords),150);
				                                });
				
				                            } else {
				                                setTimeout(executeRename(dodgeCell, commandName),150);
				                            }
										}
									});
				
									if (dodgeCell != null) {
										var unitSpeed = $("#slowestUnitCell img").attr("slowestunit");
										if (unitSpeed != undefined) {
											dodgeCell = dodgeCell.parent().find("td").last().prev();
											pers.setCookie("sanguDodge" + getQueryStringParam("village"), unitSpeed + "~" + dodgeCell.text(), user_data.mainTagger2.minutesDisplayDodgeTimeOnMap);
				
											$(".dodgers", incomingTable).css("background-color", "").attr("title", "");
											dodgeCell.css("background-color", user_data.colors.good).attr("title", trans.sp.tagger.activeDodgeTime);
										}
									}
								}
				
								// std tag button
								var button = $("<input type=button title='" + trans.sp.tagger.renameTooltip + "' value='" + trans.sp.tagger.rename + "' onclick='select();'>");
								button.click(function () {
									trackClickEvent("MainTagger-CustomRename");
									var tagName = $("#commandInput").val();
									renameCommand(tagName);
								});
								buttonParent.append(button);
				
								if (user_data.mainTagger2.otherDescs != null && user_data.mainTagger2.otherDescs != false) {
									$.ctrl = function(key, callback, args) {
									    $(document).keydown(function(e) {
										if(!args) args=[]; // IE barks when args is null 
										if(e.keyCode == key.charCodeAt(0) && e.ctrlKey) {
										    e.preventDefault();
										    e.stopPropagation();
										    callback.apply(this, args);
										    return false;
										}
									    });        
									};
									// custom buttons
									$.each(user_data.mainTagger2.otherDescs, function (index, val) {
									    if (val.active) {
										var button = $("<input type=button title='" + trans.sp.tagger.renameButtonShortcutTooltip.replace("{hitkey}", val.hitKey)
				                            + "' data-rename-to='" + val.renameTo + "' value='" + val.name
				                            + "' class=\"mainTaggerButtons\">").click(
										    function () {
				                                // Cannot use input:checked : this works for Firefox but there is a bug in Opera
				                                trackClickEvent("MainTagger-ConfigRename");
				                                renameCommand($(this).attr("data-rename-to"));
										    });
						    
										    buttonParent.append(button);
									    }
									    $.ctrl(val.hitKey, function(s) {
				                            trackClickEvent("MainTagger-ConfigRename");
				                            renameCommand(val.renameTo);
									    });
									});
								}
				
								// add checkboxes
								var lastRowIndex = rows.size(),
				                    lastSend = 0,
				                    prevSendTime = 0,
								    firstNight = true,
								    amountOfAttacks = 0;
				
								rows.each(function (rowIndex, rowValue) {
									var row = $(rowValue);
									if (rowIndex == 0) {
										// headerrow
										var header = "<td width=1% nowrap>";
										header += "<img src='graphic/command/attack.png' title='" + trans.sp.tagger.checkAllAttacks + "' id=checkAll>&nbsp;<img src='graphic/command/cancel.png' title='" + trans.sp.tagger.uncheckAllAttacks + "' id=uncheckAll>";
										header += "</td>";
				
										row.replaceWith("<tr>" + header + "<th width='68%'>" + trans.sp.tagger.incomingTroops + "</th><th width='30%'>" + trans.sp.tagger.arrival + "</th><th width='10%'>" + trans.sp.tagger.arrival + "</th><th width=10% nowrap>" + trans.sp.tagger.dodgeTime + "</th><th width='1%'>&nbsp;</th>" + "</tr>");
				
										$("#checkAll").click(function () {
											$("input.incAt", incomingTable).prop("checked", true);
										});
				
										$("#uncheckAll").click( function () {
											$("input.incAt", incomingTable).prop("checked", false);
										});
										
									} else {
										// non header row types
										if (row.find("th").size() != 0) {
											// this part is only executed when attacks can be ignored
											// select all checkbox row (right above link rows)
											$("th:first", row).replaceWith("<th><input type=checkbox id=selectAllIgnore> " + $("th:first", row).text() + "</th>");
											$("#selectAllIgnore").click(function () {
												var ingoreBoxes = $("input[name^='id_']", incomingTable);
												var isChecked = $("#selectAllIgnore").is(":checked");
												ingoreBoxes.each(function() {
													$(this).attr("checked", isChecked);
												});
											});
				
											row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>").find("td:last").attr("colspan", 4);
											
										} else if (row.find("td").size() == 1) {
											// link-rows (bottom)
											if ($("#switchModus").size() == 0) {
												if ($("#selectAllIgnore").size() == 0) {
													// attack hiding disabled in tw settings -> there is not yet a totalrow
													row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>");
												} else {
				                                    row.prepend("<td>&nbsp;</td>");
				                                }
				
												row.before("<tr><td>&nbsp;</td><td colspan=5><a href='' id=switchModus>" + trans.sp.tagger.switchModus + "</a></td></tr>");
												$("#switchModus").click(function () {
													trackClickEvent("MainTagger-OpenClose");
													var editSpans = $("input.incAt", incomingTable).parent().parent().find("span.quickedit"),
				                                        isInDisplayMode = function (editSpan) {
				                                            return editSpan.find("span:first").is(":visible");
				                                        },
				                                        switchToOpen = isInDisplayMode(editSpans.first());
				
				                                    editSpans.each(function() {
				                                        var editSpan = $(this),
				                                            isDisplayMode = isInDisplayMode(editSpan);
				
				                                        if (switchToOpen && isDisplayMode) {
				                                            // make input form visible
				                                            $("a.rename-icon", editSpan).click();
				                                            //setTimeout(function() {
				                                            $("span.quickedit-edit input:first", editSpan).width(user_data.mainTagger2.inputBoxWidth);
				                                            //}, 1);
				
				                                        } else if (!switchToOpen && !isDisplayMode) {
				                                            // make label display visible
				                                            editSpan.find("span:first").show();
				                                            editSpan.find("span:last").remove();
				                                        }
				                                    });
				
													return false;
												});
											} else {
				                                row.prepend("<td>&nbsp;</td>");
				                            }
											row.find("td:last").attr("colspan", 5);
										} else {
											// normal incoming rows
											var checkboxCell = "<td><input type=checkbox rowIndex=" + rowIndex + " class='taggerCheckbox ";
											var incomingType = $("img[src*='graphic/command/support.png']", this).size() == 1 ? 'incSupport' : "incAt";
											checkboxCell += incomingType + "'";
											if (rowIndex == 1) {
												checkboxCell += " id=checkFirst";
											}
				
											var currentArrivalTime = getDateFromTodayTomorrowTW($("td:eq(1)", this).text());
											if (incomingType == 'incAt' && isDateInNightBonus(currentArrivalTime)) {
												// nightbonus
												row.find("td:eq(1)").css("background-color", user_data.colors.error);
											}
				
											// extra column with dodge time
											if (incomingType == 'incAt') {
												var dodgeTime = getTimeFromTW($("td:eq(2)", this).text());
												row.find("td:last").before("<td class=dodgers>" + twDurationFormat(dodgeTime.totalSecs / 2 / 60) + "</td>");
												amountOfAttacks++;
											} else {
												row.append("<td>&nbsp;</td>");
											}
				
											// dotted line after x hours no incomings
											if (prevSendTime == 0 || (currentArrivalTime - prevSendTime) / 1000 / 60 > user_data.mainTagger2.minutesWithoutAttacksDottedLine) {
												if (prevSendTime != 0) {
													row.find("td").css("border-top", "1px dotted black");
												}
												
												prevSendTime = currentArrivalTime;
											}
											
											// black line after each nightbonus
											if (lastSend == 0 || currentArrivalTime > lastSend) {
												if (lastSend != 0) {
													row.find("td").css("border-top", "1px solid black");
													firstNight = false;
												}
				
												lastSend = new Date(currentArrivalTime);
												if (lastSend.getHours() >= world_config.nightbonus.till) {
													lastSend.setDate(lastSend.getDate() + 1);
													lastSend.setHours(world_config.nightbonus.from);
													lastSend.setMinutes(0);
													lastSend.setSeconds(0);
												} else if (lastSend.getHours() < world_config.nightbonus.from) {
													lastSend.setHours(world_config.nightbonus.from);
													lastSend.setMinutes(0);
													lastSend.setSeconds(0);
												} else {
													lastSend.setHours(world_config.nightbonus.till);
													lastSend.setMinutes(0);
													lastSend.setSeconds(0);
												}
											}
				
											// Automatically select?
											if (incomingType == "incAt") {
												if (firstNight) {
													var isDefaultDesc = false;
													if (!isDefaultDesc) {
														checkboxCell += " checked=true";
													}
												}
				
												$("span:eq(2)", row).find("input:first").click(function () {
													$(this).select();
												});
				
												// extra buttons
												$("td:eq(0)", row).append("<img src='graphic/oben.png' title='" + trans.sp.tagger.allAbove + "' rowIndex=" + rowIndex + " direction='up'> <img src='graphic/unten.png' title='" + trans.sp.tagger.allBelow + "' rowIndex=" + rowIndex + " direction='down'>");
											}
				
											row.prepend(checkboxCell + "></td>");
				
											if (user_data.mainTagger2.colorSupport != null && incomingType != "incAt") {
												row.find("td").css("background-color", user_data.mainTagger2.colorSupport);
											}
										}
									}
								});
							});
						}
					}
				
					// show tagger?
					if (user_data.mainTagger2.autoOpen) {
						$("#openTaggerButton").click();
					}
					
					// Show attack rename inputboxes 
					if (user_data.mainTagger2.autoOpenCommands) {
						$("#switchModus").click();
					}
				
				    // BUG: This breaks the TW remembering of the div positions!!
					var newLayout = "<tbody><tr><td colspan=2><div class='outerBorder' id=myprettynewcell>";
					newLayout += "</div></td></tr></tbody>";
					mainTable.append(newLayout);
				
					var prettyCell = $("#myprettynewcell");
					prettyCell.append($("#show_incoming_units"));
					prettyCell.append($("#show_outgoing_units"));
				}
				if (user_data.overview.canHideDiv) {
				    //console.time("main_overview_deletebuttons");
				
				    /**
				     * Array with domIds of the hideable divs
				     * @type {Array}
				     */
				    var currentlyHidden = pers.get("mainvillage_hiddendivs");
				    currentlyHidden = currentlyHidden ? JSON.parse(currentlyHidden) : [];
				
				    // add the X images
				    $("#leftcolumn,#rightcolumn").find("div.moveable").each(function() {
				        var self = $(this),
				            domId = this.id;
				
				        if (!self.hasClass("hidden_widget")) {
				            if (currentlyHidden.indexOf(domId) !== -1) {
				                self.hide();
				            } else {
				                var header = self.find("h4:first");
				                header.prepend(
				                    '<span class="sanguHide" '
				                        + " title='" + trans.sp.main.hideDiv + "'"
				                        + ' data-divid="' + domId + '"></span>');
				            }
				        }
				    });
				
				    // X image event
				    $(".sanguHide", content_value).click(function() {
				        var toHideId = $(this).attr("data-divid");
				        currentlyHidden.push(toHideId);
				        $("#" + toHideId).hide();
				        q(currentlyHidden);
				
				        pers.set("mainvillage_hiddendivs", JSON.stringify(currentlyHidden));
				    });
				
				    // css for X image
				    var deleteImage = "data:image/png;base64,"
				        + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
				        + "jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41"
				        + "LjExR/NCNwAAAT5JREFUOE9jmBqv1R8uD0F9oTI9wZJdAaLI7A5fwTYv3g4fgU4/4VZ3Lgag6OYV"
				        + "fUd3zj13aAkeBFQAVFZrx8DQGyIN5Nw6t+7p9W14EFABUFm9AwMD0GqgAUChDw/340FABUBljY5M"
				        + "DN0BYsRrADkJ6Bs0DZe2NL68sfHN3R1XtrfCBSEaKm0YGIAeR9awoj22M1p5z+SIHX0hczI0t/fF"
				        + "oGtodGJG1vD8+ubqYPXOEMnJMTI9EYqPz69E1oDFDw/PreyPUkw1YiiwYV9Z5fDq1lZkDVj8sKgh"
				        + "NFiTIcdHPd5RIc2Se/eUZGQNWPwARH1VMU+vbb51akV7UQhcEKEBzQ+4EERDqRUDA9BZxGsotGBg"
				        + "AMY28UkDpKHJmYX4xAfSAPQH0GXlNlAGEBVbMQAlkNn55gz5QNKCIdOUAQAxTOqhn6cegQAAAABJ"
				        + "RU5ErkJggg==";
				
				    var css = document.createElement("style");
				    css.type = "text/css";
				    css.innerHTML = ".sanguHide { margin-left: 2px; float: right; cursor: pointer; "
				        + "background: url(" + deleteImage + "); width: 16px; height: 16px; }";
				    document.body.appendChild(css);
				
				    // show everything link
				    content_value.append(
				        "<br><a href='#' id='resetSanguMenu'>"
				            + trans.sp.main.showHiddenDivs.replace("{amount}", currentlyHidden.length)
				            + "</a>"
				    );
				
				    $("#resetSanguMenu").click(function() {
				        pers.set("mainvillage_hiddendivs", "");
				        location.reload();
				    });
				
				
				
				    //console.timeEnd("main_overview_deletebuttons");
				}
                }());
                break;

            case "map":
			(function() {
			    //console.time("dodge_fromMainTagger");
			    try {
			        var isDodge = pers.getCookie("sanguDodge" + getQueryStringParam("village"));
			        if (isDodge) {
			            // Display dodge time and slowest unit in the village (cookied from the mainTagger)
			            isDodge = isDodge.split("~");
			            var header = $("h2:first", content_value);
			            $("tbody:first", content_value)
			                .prepend(
			                    "<tr><td><table width=100% cellpadding=0 cellspacing=0><tr><td width=99% style='font-size: 18pt'><b>" + header.html()
			                        + "</b></td><td nowrap width=250><div title='" + trans.sp.map.dodgeLastTagged + "' style='border: 1px solid black; padding: 2px; background-color: "
			                        + (isDodge[0] == 'unit_snob' ? user_data.colors.special : user_data.colors.good) + "'><img src=graphic/unit/" + isDodge[0] + ".png> <b>" + isDodge[1]
			                        + "</b></div></td></tr></table></td></tr>");
			            header.remove();
			        }
			    } catch (e) { handleException(e, "dodge_fromMainTagger-"); }
			    //console.timeEnd("dodge_fromMainTagger");
			}());
                break;

            case "report":
                if (current_page.mode === 'publish') {
			// Nice to haves when publishing a report
			(function() {
			    try {
			        if (location.href.indexOf('published=1') == -1 && user_data.other.reportPublish != null) {
			            $.each(user_data.other.reportPublish, function (i, v) { $("#" + v).prop("checked", true); });
			        } else {
			            $("h3~p:nth-child(4)").each(function () {
			                var input = $("h3~p a")[0].href;
			                if (input.indexOf("?t=") != -1) {
			                    input = input.substr(0, input.indexOf("?"));
			                }
			                $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[url]' + input + '[/url]" />');
			                input = input.substr(input.lastIndexOf('/') + 1);
			                $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report_display]' + input + '[/report_display]" />');
			                $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report]' + input + '[/report]" />');
			            });
			        }
			    } catch (e) { handleException(e, "report"); }
			}());
                }
                break;

            case "main":
			// Alternating row colors
			$("#buildings,#build_queue").find("tr:odd").addClass("row_b");
			(function() {
			    //console.time("main-renamevillage");
			    try {
			        if (user_data.main.villageNames != null && user_data.main.villageNames.length > 0) {
			            var showButtons = true;
			            $.each(user_data.main.villageNames, function (i, v) { if (game_data.village.name == v) showButtons = false; });
			
			            if (showButtons) {
			                var submitButton = $("input[type='submit']:last");
			                $.each(user_data.main.villageNames, function (i, v) {
			                    // rename village to one of the provided villageNames options
			                    var button = $("<input type=button class='btn' value='" + v + "'>")
			                        .click(function () {
			                            trackClickEvent("RenameVillage");
			                            $("input[name='name']").val(v);
			                            if (user_data.main.villageNameClick) {
			                                $("input[type='submit']").click();
			                            }
			                        });
			                    var input = submitButton.parent().append(button);
			                });
			            }
			        }
			    } catch (e) { handleException(e, "place-"); }
			    //console.timeEnd("main-renamevillage");
			}());
			// show loyalty when building
			// destroy button is disabled now (but for how long?)
			if (server_settings.ajaxAllowed && user_data.main.ajaxLoyalty) {
				ajax("overview", function (overview) {
					var loyalty = $("#show_mood div.vis_item", overview);
					if (loyalty.size() == 1) {
						$(".modemenu tr:first").append("<td><b>" + trans.tw.main.loyaltyHeader + "</b> " + loyalty.html() + "</td>");
					}
				});
			}
                break;

            case "snob":
                if (current_page.mode === "train" || current_page.mode === null || current_page.mode === "produce") {
			if (user_data.other.calculateSnob && !world_config.coins) {
				// Calculate for how many nobles/snobs we've got packages
			    (function() {
			        try {
			            //var table = $("table.vis:eq(1)", content_value);
			            var table = $("table.vis[width='100%']", content_value).first();
			            var cost = $("td:eq(1)", table).html();
			            cost = parseInt(cost.substr(0, cost.indexOf(" ")), 10);
			            var stored = $("tr:eq(1) td:eq(1)", table).html();
			            stored = parseInt(stored.substr(0, stored.indexOf(" ")), 10);
			            var canProduce = 0;
			            while (stored > cost) {
			                stored -= cost;
			                cost++;
			                canProduce++;
			            }
			
			            var sumtable = $("table.main #content_value > table table.vis:last");
			            assert(sumtable.length, "no snob sumtable");
			            sumtable.append("<tr><th>" + trans.sp.snob.canProduce
			                + "</th><td style='border: 1px solid black'><img src='/graphic/unit/unit_snob.png'><b>"
			                + canProduce + "</b> " +
			                "+ <img src='graphic/res.png'>"
			                + stored + "</td></tr>");
			
			        } catch (e) { handleException(e, "snob"); }
			    }());
			}
                }
                break;

            case "info_command":
			if ($("#running_times").size() > 0) {
				// ---------------------------------------INCOMING ATTACK
			    (function() {
			        //console.time("info_command-incoming");
			        try {
			            var link = $("#contentContainer tr:eq(10) a:last");
	link.one('click', function () {
		var infoTable = $("#contentContainer");
		var table = $("#running_times");
	
		// convert runningtime to seconds
		// TODO: there is a function for this: getTimeFromTW
		function convertTime(cell) {
			var time = $(cell).find("td:eq(1)").text();
			time = time.match(/(\d+):(\d+):(\d+)/);
	
			var obj = {};
			obj.hours = parseInt(time[1], 10);
			obj.minutes = parseInt(time[2], 10);
			obj.seconds = parseInt(time[3], 10);
			obj.totalSeconds = obj.hours * 3600 + obj.minutes * 60 + obj.seconds;
	
			return obj;
		}
	
		// Sort on runningtime
		var unitRows = $("tr:gt(1)", table);
		unitRows.sortElements(function (a, b) {
				return convertTime(a).totalSeconds > convertTime(b).totalSeconds ? 1 : -1;
			});
	
		// header sent times
		$("th:first", table).attr("colspan", 5);
		$("th:eq(2)", table).after("<th>" + trans.sp.tagger.sentOn + "</th><th>" + trans.sp.tagger.ago + "</th>");
	
		var infoCell = $("td", infoTable);
		var attacker = infoCell.eq(5).text();
		var attackerVillageName = infoCell.eq(7).text();
		var attackerVillage = getVillageFromCoords(attackerVillageName);
		var defender = infoCell.eq(10).text();
		var defenderVillage = getVillageFromCoords(infoCell.eq(12).text());
		var arrivalTime = getDateFromTW(infoCell.eq(14).text());
		var fields = parseInt(getDistance(attackerVillage.x, defenderVillage.x, attackerVillage.y, defenderVillage.y).fields, 10);
	
		var isNightbonus = isDateInNightBonus(arrivalTime);
		if (isNightbonus) {
			infoCell.eq(14).css("background-color", user_data.colors.error);
		}
	
		var remainingRunningTime = convertTime($("tr:eq(9)", infoTable)),
		    plausibleSpeedFound = false;
	
		unitRows.each(function () {
			var unit = $("img:first", this).attr("src");
			unit = unit.substr(unit.lastIndexOf("unit_") + 5);
			unit = unit.substr(0, unit.indexOf("."));
	
			if (unit == "spear") {
				$(this).hide();
			} else {
				var runningTime = convertTime(this),
				    newDate = new Date(arrivalTime.getTime() - runningTime.totalSeconds * 1000),
				    sendAt = prettyDate((new Date()).getTime() - newDate.getTime()),
	                troopsRow = this,
	                str;
	
				// Extra column with time sent
				$("td:eq(2)", troopsRow).before("<td>" + twDateFormat(newDate, true) + "</td><td>" + sendAt + "</td>");
	
	            // Rename default command name for each speed
	            if (user_data.incoming.renameInputTexbox) {
	                str = user_data.incoming.renameInputTexbox;
	
	                var attackId = $("span.quickedit", this).attr("data-id");
	                str = str.replace("{village}", attackerVillageName).replace("{c}", attackerVillage.continent()).replace("{id}", attackId);
	                str = str.replace("{player}", attacker).replace("{xy}", attackerVillage.coord).replace("{unit}", trans.tw.units.twShortNames[unit]);
	                str = str.replace("{fields}", fields);
	                if (str.indexOf("{night}") != -1) {
	                    if (isNightbonus) {
	                        str = str.replace("{night}", trans.sp.tagger.arrivesInNightBonus);
	                    } else {
	                        str = str.replace("{night}", "");
	                    }
	                }
	
	                if (false) {
	                    // don't show rename inputs, just the labels
	                    $("span.quickedit-label", troopsRow).text(str).show();
	                } else {
	                    // show the rename inputboxes on form load
	                    $("span.quickedit-label", troopsRow).text(str);
	                    setTimeout(function() {
	                        $("a.rename-icon", troopsRow).click();
	                        $("#focusPlaceHolder").focus();
	                    }, 1);
	                }
	
	                if (runningTime.totalSeconds > remainingRunningTime.totalSeconds && !plausibleSpeedFound) {
	                    plausibleSpeedFound = true;
	
	                    $("table:first", content_value).prepend(
	                        "<input type=submit class='btn' id=focusPlaceHolder value='"
	                            + trans.sp.tagger.tagIt
	                            + " (" + trans.tw.units.twShortNames[unit] + ")'"
	                            + " data-command-name='" + str + "'"
	                            + ">");
	
	                    $("#focusPlaceHolder").click(function () {
	                        trackClickEvent("TagDefault");
	                        $("#command_comment").text($(this).attr("data-command-name"));
	                        $("#command_comment+a").click();
	                        setTimeout(function() {
	                            $("#quickedit-rename input:last").click();
	                        }, 1);
	                        $(this).val(trans.sp.tagger.tagged).attr("disabled", "disabled");
	                    });
	
	                    if (unit == "snob") {
	                        $("tr:last td", table).css("background-color", user_data.colors.error);
	                    }
	                }
	            }
	
				// Possible send times (now) in bold
				if (runningTime.totalSeconds > remainingRunningTime.totalSeconds) {
					$(this).css("font-weight", "bold");
				}
			}
		});
	
		// nobles can only walk so far
		var nobles = $("tr:last", table);
		if (convertTime(nobles).totalSeconds / 60 > world_config.maxNobleWalkingTime) {
			nobles.find("td").css("text-decoration", "line-through");
		}
	
		if (user_data.incoming.invertSort) {
			unitRows.sortElements(function (a, b) {
				return convertTime(a).totalSeconds < convertTime(b).totalSeconds ? 1 : -1;
	        });
	    }
	});
			
			            // AUTO OPEN TAGGER
			            if (user_data.incoming.forceOpenTagger || (user_data.incoming.autoOpenTagger && $("#labelText").text() == trans.tw.incoming.defaultCommandName)) {
			                link.click();
			            }
			
			            if (user_data.proStyle && user_data.incoming.villageBoxSize != null && user_data.incoming.villageBoxSize != false) {
			                $("table:first", content_value).css("width", user_data.incoming.villageBoxSize);
			            }
			
			        } catch (e) { handleException(e, "info_command-incoming"); }
			        //console.timeEnd("info_command-incoming");
			    }());
				
			} else {
			    (function() {
			        //console.time("info_command-command");
			        try {
			            // Own attack/support/return ---------------------------------------------------------------------------------- Own attack/support/return
			            var infoTable = $("table.vis:first", content_value);
			            var type = $("h2:first", content_value).text();
			            var catapultTargetActive = infoTable.find("tr:eq(5) td:eq(0)").text() == trans.tw.command.catapultTarget;
			
			            infoTable.width(600);
			
			            // Add troop returntime and annulation return time
			            var isSupport = type.indexOf(trans.tw.command.support) == 0;
			            var offset = 5;
			            if (catapultTargetActive) {
			                offset += 1;
			            }
			            var arrivalCell = infoTable.find("tr:eq(" + (offset + 1) + ") td:last");
			
			            if (type.indexOf(trans.tw.command.returnText) == -1
			                && type.indexOf(trans.tw.command.abortedOperation) == -1) {
			
			                var duration = getTimeFromTW(infoTable.find("tr:eq(" + offset + ") td:last").text());
			                var imgType = !isSupport ? "attack" : "support";
			                arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'>&nbsp; " + trans.tw.all.dateOn + " ").css("font-weight", "bold");
			                var stillToRun = getTimeFromTW(infoTable.find("tr:eq(" + (offset + 2) + ") td:last").text());
			
			                var cancelCell = infoTable.find("tr:last").prev();
			                var canStillCancel = cancelCell.has("a").length;
			                if (canStillCancel) {
			                    cancelCell.find("td:first").attr("colspan", "1").attr("nowrap", "nowrap");
			                    var returnTime = getDateFromTW($("#serverTime").text(), true);
			                    returnTime = new Date(returnTime.valueOf() + (duration.totalSecs - stillToRun.totalSecs) * 1000);
			                    cancelCell.append("<td>" + trans.sp.command.returnOn + "</td><td id=returnTimer>" + twDateFormat(returnTime, true, true).substr(3) + "</td>");
			
			                    setInterval(function timeCounter() {
			                        var timer = $("#returnTimer");
			                        var newTime = new Date(getDateFromTW(timer.text()).valueOf() + 2000);
			                        timer.text(twDateFormat(newTime, true, true).substr(3));
			                    }, 1000);
			
			                    cancelCell = cancelCell.prev();
			                }
			
			                if (type.indexOf(trans.tw.command.attack) == 0) {
			                    var returnTimeCell = cancelCell.find("td:last");
			                    returnTimeCell.html("<img src='graphic/command/return.png' title='" + cancelCell.find("td:first").text() + "'>&nbsp; <b>" + returnTimeCell.text() + "</b>");
			                }
			            } else {
			                var imgType = type.indexOf(trans.tw.command.abortedOperation) == 0 ? imgType = "cancel" : "return";
			                arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'>&nbsp; " + trans.tw.all.dateOn + " ").css("font-weight", "bold");
			            }
			
			            var player = infoTable.find("td:eq(7) a").text();
			            var village = getVillageFromCoords(infoTable.find("td:eq(9) a").text());
			            var second = infoTable.find("td:eq(" + (13 + (catapultTargetActive ? 2 : 0)) + ")").text();
			            var haulDescription = "";
			
			            if (type.indexOf(trans.tw.command.returnText) == 0) {
			                infoTable = $("> table.vis:last", content_value);
			                if (infoTable.find("td:first").text() == trans.tw.command.haul) {
			                    haulDescription = infoTable.find("td:last").text().match(/\s(\d+)\/(\d+)$/);
			                    if (haulDescription) {
			                        haulDescription = formatNumber(haulDescription[1]) + " / " + formatNumber(haulDescription[2]);
			                    } else {
			                        assert(infoTable.find("td:last").text() + " didn't match regexp for tw.command.haul");
			                    }
			                    infoTable = infoTable.prev();
			                }
			                infoTable = infoTable.find("tr:last");
			            } else {
			                infoTable = $("> table.vis:last", content_value);
			            }
			
			            var unitsSent = {};
			            $.each(world_data.units, function (i, val) {
			                unitsSent[val] = parseInt($("td:eq(" + i + ")", infoTable).text(), 10);
			            });
			            var unitsCalc = calcTroops(unitsSent);
			            unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), !isSupport);
			
			            if (user_data.attackAutoRename.active) {
			                $.each($('.quickedit'), function(){
			                    var renamed = buildAttackString(village.coord, unitsSent, player, isSupport, 0, haulDescription),
			                        commandID = $(this).attr('data-id'),
			                        $this = $(this);
			
			                    if (server_settings.ajaxAllowed) {
			                        $.ajax({
			                           url: game_data.link_base_pure+'info_command&ajaxaction=edit_other_comment&id='+commandID+'&h='+game_data.csrf+'&',
			                           method: 'post',
			                           data: { text: renamed },
			                           success:function() {
			                               $this.find(".quickedit-label:first").text(renamed);
			                           }
			                        });
			                    }
			                });
			            }
			
			            /*if (server_settings.ajaxAllowed) {
			             ajax("overview", function(overviewtext) {
			             var idnumberlist = [];
			             var index = 0;
			             var links = $(overviewtext).find("#show_outgoing_units").find("table").find("td:first-child").find("a:first-child").find("span");
			             //^enkel 'find codes, dus alles wegselecteren wat onnodig is.
			
			             links.each(function(){
			             var idgetal = $(this).attr('id').match(/\d+/);
			             idnumberlist[index]=idgetal[0];
			             index++;
			             $.trim(idnumberlist[index]);
			             });
			
			             idthisattack= location.href.match(/id=(\d+)/);// deze aanval ophalen
			             var idthisattacktrim = $.trim(idthisattack[1]); //eerste callback: Datgeen tussen haakjes dus. En gelijk maar trimmen, voor het geval dat.
			             var counter=$.inArray(idthisattacktrim, idnumberlist);
			             var arraylength = idnumberlist.length;
			             var arraylengthminusone = arraylength -1;
			             if (counter != arraylengthminusone) {
			             var nextcommandID = idnumberlist[(counter +1)];}
			             if (counter != 0) {
			             var lastcommandID = idnumberlist[(counter - 1)];
			             }
			             villageid = location.href.match(/village=(\d+)/);
			             //alert(villageid[1]);
			             if (counter != 0) {
			             content_value.find("h2").after('<table><tr><td id="lastattack" style="width:83%"><a href="/game.php?village=' + villageid + '&id=' + lastcommandID + '&type=own&screen=info_command">'+ trans.sp.command.precedingAttack + '</a></td> </tr> </table>');
			             }
			             else {
			             content_value.find("h2").after('<table><tr><td id="lastattack" style="width:83%"><b> XX</b></td> </tr> </table>');
			             }
			             if (counter != arraylengthminusone){
			             $("#lastattack").after('<td id="nextcommand" ><a href="/game.php?village=' + villageid + '&id=' + nextcommandID + '&type=own&screen=info_command">'+ trans.sp.command.nextAttack+ '</a></td>');
			             }
			             else {
			             $("#lastattack").after('<td id="nextcommand"><b>XX</b></td>');
			             }
			
			             //alert("Hoi");
			             }, {});
			             }*/
			
			            // When sending os, calculate how much population in total is sent
			            if (isSupport) {
			                var totalPop = 0;
			                $.each(world_data.units, function (i, val) {
			                    var amount = unitsSent[val];
			                    if (amount != 0) {
			                        totalPop += amount * world_data.unitsPositionSize[i];
			                    }
			                });
			
			                var unitTable = $("table.vis:last", content_value);
			                unitTable.find("tr:first").append('<th width="50"><span class="icon header population" title="' + trans.sp.all.population + '"></span></th>');
			                unitTable.find("tr:last").append('<td>' + formatNumber(totalPop) + '</td>');
			            }
			        } catch (e) { handleException(e, "info_command-command"); }
			        //console.timeEnd("info_command-command");
			    }());
			}
                break;

            case "market":
			(function() {
			    try {
			        if (location.href.indexOf('try=confirm_send') > -1) {
			            if (user_data.proStyle && user_data.market.autoFocus) {
			                $("input[type='submit']").focus();
			            }
			        }
			        else if (location.href.indexOf('&mode=') == -1 || location.href.indexOf('&mode=send') > -1) {
			            if (location.href.indexOf('try=confirm_send') == -1) {
			                // Spice up market:
			                // 120 x 106 pixels: There are market images that are smaller
			                // Making all images equally large results in the OK button remaining on the same place
			                if (user_data.proStyle && user_data.market.resizeImage) {
			                    $("img[src*='big_buildings/market']").width(120).height(106);
			                }
			
			                // New last village:
			                $("input[type='submit']").click(function () {
			                    var village = getVillageFromCoords($("#inputx").val() + "|" + $("#inputy").val());
			                    if (village.isValid) {
			                        pers.set("lastVil", village.coord);
			                    }
			                });
			
			                // Add last & target
			                var vilHome = getVillageFromCoords(game_data.village.coord);
			
			                var targetLocation = $("#inputx").parent().parent().parent();
			                var cookie = pers.get("lastVil");
			                var coord = getVillageFromCoords(cookie);
			                var htmlStr = '';
			                if (coord.isValid) {
			                    var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, 'merchant');
			                    htmlStr = printCoord(coord, "&raquo; " + trans.sp.all.last + ": " + coord.x + "|" + coord.y);
			                    htmlStr += "&nbsp; <span id=lastVilTime>" + dist.html + "</span>";
			                }
			
			                // Add target village
			                var target = getVillageFromCoords(spTargetVillageCookie());
			                if (target.isValid) {
			                    var dist = getDistance(target.x, vilHome.x, target.y, vilHome.y, 'merchant');
			                    if (htmlStr.length > 0) {
			                        htmlStr += "<br>";
			                    }
			                    htmlStr += printCoord(target, "&raquo; " + trans.sp.all.target + ": " + target.x + "|" + target.y) + " &nbsp;<span id=targetVilTime>" + dist.html + "</span>";
			                }
			
			                if (htmlStr.length > 0) {
			                    targetLocation.append("<tr><td colspan=2>" + htmlStr + "</td></tr>");
			                }
			
			                // Calculate total resources sent
			                var table = $("table.vis:last");
			                if (table.prev().text() == trans.tw.market.incomingTransports) {
			                    var sent = { stone: 0, wood: 0, iron: 0 };
			                    table.find("tr:gt(0)").each(function () {
			                        var cell = $(this).find("td:eq(1)");
			                        var resources = $.trim(cell.text().replace(/\./g, "").replace(/\s+/g, " ")).split(" ");
			
			                        for (var i = 0; i < resources.length; i++) {
			                            if (resources[i]) {
			                                var restype = cell.find("span.icon:eq(" + i + ")");
			                                for (var resIndex = 0; resIndex < world_data.resources_en.length; resIndex++) {
			                                    if (restype.hasClass(world_data.resources_en[resIndex])) {
			                                        sent[world_data.resources_en[resIndex]] += parseInt(resources[i], 10);
			                                    }
			                                }
			                            }
			                        }
			                    });
			
			                    table.append("<tr><th>" + trans.sp.all.total + ":</th><td colspan=3><img src=graphic/holz.png> " + formatNumber(sent.wood) + "&nbsp; <img src=graphic/lehm.png> " + formatNumber(sent.stone) + "&nbsp; <img src=graphic/eisen.png> " + formatNumber(sent.iron) + "</td></tr>");
			                }
			            }
			        }
			    } catch (e) { handleException(e, "market"); }
			}());
                break;

            case "settings":
                // Add sangu to the menu
			(function() {
			    var settingsMenu = $("table.vis:first", content_value);
			    settingsMenu.append(
			        "<tr><td>&nbsp;</td></tr><tr><th><a href='"
			            + getUrlString("screen=settings&mode=sangu")
			            + "'>Sangu Package</a></th></tr>");
			
			    settingsMenu.append(
			        "<tr id='sanguImportRow'><td>"
			            + "<a href='#' id='sanguImport'>" + trans.sp.sp.settings.importSettings + "</a>"
			            + "</td></tr>"
			            + "<tr id='sanguExportRow'><td>"
			            + "<a href='#' id='sanguExport'>" + trans.sp.sp.settings.exportSettings + "</a>"
			            + "</td></tr>");
			
			    settingsMenu.after(
			        "<br>"
			            + "<a target='_blank' href='http://"+server_settings.sangu+"'>"
			            + "<div style='width: 100%; text-align: center; border: 1px solid black; background-color: yellow; padding: 10px 0 10px;'>"
			            + "Sangu Website"
			            + "</div>"
			            + "</a>");
			
			    /**
			     * Creates the textarea (and other UI elements) for displaying the user_data
			     * @param activate {string} either Import or Export
			     * @param deactivate {string} either Export or Import
			     * @param textAreaValue {string} the content to assign to the textarea
			     */
			    function importExportHandler(activate, deactivate, textAreaValue) {
			        var settingsContainer = $("#sanguSettingsTextArea");
			        $("#sangu"+activate+"Row").addClass("row_b");
			        $("#sangu"+deactivate+"Row").hide();
			
			        $("#sanguSettingsForm").hide();
			        if (settingsContainer.length === 0) {
			            //sanguConfigTitle is the h3 defined in inject.js
			            $("#sanguConfigTitle").parent().append(
			                trans.sp.sp.settings.importSettingsDesc + "<br><br>"
			                    + "<textarea id='sanguSettingsTextArea' style='width: 100%; height: 500px'>"
			                    + textAreaValue
			                    + "</textarea>");
			        } else {
			            if (textAreaValue.length > 0) {
			                settingsContainer.val(textAreaValue);
			            }
			        }
			    }
			
			    $("#sanguExport").click(function() {
			        importExportHandler("Export", "Import", JSON.stringify(user_data, null, 4));
			        $("#sanguSettingsTextArea").select();
			        return false;
			    });
			
			    $("#sanguImport").click(function() {
			        var importSanguSettings = $("#importSanguSettings");
			        importExportHandler("Import", "Export", "");
			
			        if (importSanguSettings.length === 0) {
			            $("#sanguSettingsTextArea")
			                .after("<br><input type='button' id='importSanguSettings' value='" + trans.sp.sp.settings.importSettings + "'>");
			
			            $("#importSanguSettings").click(function() {
			                var overwriteCurrentSettings = true,
			                    newUserData;
			
			                try {
			                    newUserData = JSON.parse($("#sanguSettingsTextArea").val());
			
			                    if (typeof newUserData.proStyle === 'undefined') {
			                        overwriteCurrentSettings = confirm(trans.sp.sp.settings.importError + trans.sp.sp.settings.importErrorContinueAnyway);
			                    }
			
			                    if (overwriteCurrentSettings) {
			                        user_data = $.extend({}, user_data, newUserData);
			                        pers.set("sangusettings", JSON.stringify(user_data));
			                        alert(trans.sp.sp.settings.importSettingsSuccess);
			                    }
			
			                } catch (ex) {
			                    alert(trans.sp.sp.settings.importError + "\n" + ex.message);
			                }
			            });
			        }
			        $("#sanguSettingsTextArea").focus();
			
			        return false;
			    });
			})();

                switch (current_page.mode) {
                    case "vacation":
				var maxSitDays = server_settings.maxSitDays;
				var daysTable = $("table.vis:eq(1)", content_value);
				var days = $("td:last", daysTable).text();
				days = maxSitDays - parseInt(days.substr(0, days.indexOf(" ")), 10);
				if (days > 0) {
					var tillTime = new Date();
					tillTime.setDate(tillTime.getDate() + days);
					daysTable.append("<tr><td>" + trans.sp.rest.sittingAttackTill + "</td><td>" + (tillTime.getDate() + "." + pad(tillTime.getMonth() + 1, 2) + "." + tillTime.getFullYear()) + "</td></tr>");
				} else {
					daysTable.find("td:last").css("background-color", user_data.colors.error);
				}
                        break;

                    case "quickbar_edit":
				if (user_data.scriptbar.editBoxCols != null && user_data.scriptbar.editBoxCols != false) {
					// TODO: textareaIfy: This might be useful on other places aswell. Move to func/UI?
					function textareaIfy(element) {
						var textarea = 
							$('<textarea>')
								.attr('cols', Math.round(user_data.scriptbar.editBoxCols / 9))
								.attr('rows', user_data.scriptbar.editBoxRows)
								.val($(element).val());
				
						textarea.change(function () {
							element.val($(this).val());
						});
				
						element.before(textarea);
						$(element).hide();
					}
				
					var url = $("form :input[type='text']").css("width", user_data.scriptbar.editBoxCols).last();
					textareaIfy(url);
				}
                        break;
                }

                // SANGU SETTING EDITOR
                if (location.href.indexOf('mode=sangu') > -1) {
				
				
				// settings.editor: : delimited: "array:string" or "required:boolean" etc
				
				function createArraySettingType(inputHandler, index, editor) {
				    var propertyValueType = editor.split("|")[0];
				
				    function deleter() {
				        inputHandler.getValue().splice(index, 1);
				    }
				
				    switch (propertyValueType) {
				        case "number":
				            return new FormInputHandler(inputHandler.formConfig, {
				                getter: function() {
				                    return inputHandler.getValue()[index];
				                },
				                setter: function(value) {
				                    value = parseInt(value, 10);
				                    if (!isNaN(value)) {
				                        inputHandler.getValue()[index] = value;
				                    } else {
				                        inputHandler.getValue()[index] = 0;
				                    }
				                },
				                deleter: deleter,
				                editor: editor
				            });
				
				        case "text":
				        case "color":
				            return new FormInputHandler(inputHandler.formConfig, {
				                getter: function() {
				                    return inputHandler.getValue()[index];
				                },
				                setter: function(value) {
				                    inputHandler.getValue()[index] = value;
				                },
				                deleter: deleter,
				                editor: editor
				            });
				
				        case "float":
				            return new FormInputHandler(inputHandler.formConfig, {
				                getter: function() {
				                    return inputHandler.getValue()[index];
				                },
				                setter: function(value) {
				                    value = parseFloat(value.replace(",", "."));
				                    if (!isNaN(value)) {
				                        inputHandler.getValue()[index] = value;
				                    } else {
				                        inputHandler.getValue()[index] = 0;
				                    }
				                },
				                deleter: deleter,
				                editor: editor
				            });
				    }
				
				    alert(propertyValueType + " not supported");
				}
				
				/**
				 * Factory for creating different representations of a property
				 * @type {string}
				 */
				function createSettingType(inputHandler, editors, editorIndex, arrayOptions) {
				    var value = inputHandler.getValue(),
				        decorators,
				        inputType,
				        propName;
				
				    //array|addNew:number|delete|step=1000
				    //color=color+number=stack
				
				    //q("with -> " + editors + ". isArray: " + isArrayType);
				    //q(arrayOptions);
				
				    if (!arrayOptions.isArrayType) {
				        decorators = editors.split("|");
				        inputType = decorators[0];
				        if (inputType.indexOf("=") > -1) {
				            propName = inputType.split("=")[1];
				            inputType = inputType.split("=")[0];
				        }
				
				        //q("isArray: " + propName + "=> " + inputType);
				        //q(decorators);
				
				        switch (inputType) {
				            case "bool":
				                return {
				                    build: function(id) {
				                        //assert(typeof value === 'boolean', (typeof value) + ": not a boolean");
				                        return "<input type='checkbox' id='"+id+"' "+(value ? " checked" : "")+" />";
				                    },
				                    bind: function(id) {
				                        $("#" + id).click(function() {
				                            inputHandler.setValue($(this).is(":checked"));
				                        });
				                    }
				                };
				            case "unit":
				                return {
				                    build: function(id) {
				                        var i,
				                            html = "<select id='"+id+"'>";
				
				                        for (i = 0; i < world_data.units.length; i++) {
				                            html += "<option "+(value == world_data.units[i] ? " selected" : "")+">"+world_data.units[i]+"</option>";
				                        }
				                        html += "</select>";
				
				                        return html;
				                    },
				                    bind: function(id) {
				                        $("#" + id).click(function() {
				                            inputHandler.setValue($(this).val());
				                        });
				                    }
				                };
				            case "text":
				            case "color":
				            case "number":
				            case "float":
				                return (function() {
				                    var htmlString = "",
				                        index,
				                        inputBoxSize = 13,
				                        extraInputAttributes = "",
				                        extraHtml = "",
				                        inputTypeAttribute = inputType === "float" ? "number" : inputType;
				
				                    switch (inputType) {
				                        case "text":
				                            if (typeof value === 'string') {
				                                value = value.toString().replace(/'/g, "&#39;");
				                            }
				                            inputBoxSize = 50;
				                            break;
				                    }
				                    if (decorators.length > 1) {
				                        (function() {
				                            var keyValuePair;
				                            for (index = 0; index < decorators.length; index++) {
				                                keyValuePair = decorators[index].split("=");
				                                switch (keyValuePair[0]) {
				                                    case "delete":
				                                        extraHtml += " &nbsp;<a href='#' id='{domId}_delete'><img src='graphic/delete.png' title='"+trans.sp.sp.settings.deleteTooltip+"' /></a>";
				                                        break;
				                                    case "step":
				                                        assert(inputType === "float" || inputType === "number", "step only works with numeric inputs");
				                                        assert(keyValuePair.length === 2, "expected input: step=value");
				                                        extraInputAttributes += " step='"+keyValuePair[1]+"'";
				                                        break;
				                                    case "width":
				                                        inputBoxSize = keyValuePair[1];
				                                        break;
				                                }
				                            }
				                        })();
				                    }
				
				                    htmlString +=
				                        "<input type='" + inputTypeAttribute + "' id='{domId}' size='" + inputBoxSize +"' "
				                            + (typeof value !== 'undefined' ? " value='"+value+"'" : "")
				                            + extraInputAttributes +" />"
				                            + extraHtml;
				
				                    return {
				                        build: function(id) {
				                            return htmlString.replace(/\{domId\}/g, id);
				                        },
				                        bind: function(id) {
				                            $("#" + id).change(function() {
				                                var newValue = $("#" + id).val();
				                                inputHandler.setValue(newValue, editorIndex);
				                                return false;
				                            });
				
				                            $("#" + id + "_delete").click(function() {
				                                inputHandler.deleteValue();
				                                location.reload(false);
				                            });
				                        }
				                    };
				                })();
				        }
				
				    } else {
				        return (function() {
				            var typesArray = [],
				                arrayIndex,
				                canAddNew = false,
				                inlineDiv = false;
				
				            decorators = arrayOptions.decorators;
				
				            //q(editors);
				            //q(decorators);
				            //q("----");
				
				            if (decorators.length > 0) {
				                for (arrayIndex = 0; arrayIndex < decorators.length; arrayIndex++) {
				                    switch (decorators[arrayIndex]) {
				                        case "addNew":
				                            canAddNew = true;
				                            break;
				                        case "inline":
				                            inlineDiv = true;
				                            break;
				                    }
				                }
				            }
				
				            for (arrayIndex = 0; arrayIndex < value.length; arrayIndex++) {
				                (function() {
				                    var fixedArrayIndex = arrayIndex;
				                    //q("createArraySettingType for" + fixedArrayIndex + "=" +editors);
				                    typesArray.push(createArraySettingType(inputHandler, fixedArrayIndex, editors));
				                })();
				            }
				
				            return {
				                build: function(id) {
				                    var htmlString = "",
				                        arrayIndex,
				                        domId;
				
				                    assert(typeof value === 'object', (typeof value) +  ": not an object (array)");
				
				                    for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) {
				                        domId = id + "_" + arrayIndex;
				
				                        htmlString += "<div" + (inlineDiv ? " style='display: inline'> &nbsp;" : ">");
				                        htmlString += typesArray[arrayIndex].build(domId);
				                        htmlString += "</div>";
				                    }
				
				                    if (canAddNew) {
				                        htmlString += "<a href='#' id='"+id+"_new'>" + trans.sp.sp.settings.addRecord + "</a>";
				                    }
				
				                    return htmlString;
				                },
				                bind: function(id) {
				                    var domId,
				                        arrayIndex;
				
				                    if (canAddNew) {
				                        $("#" + id + "_new").click(function() {
				                            var domId = id + "_" + typesArray.length,
				                                newType;
				
				                            newType = createArraySettingType(inputHandler, typesArray.length, editors);
				                            $(this).before("<div>" + newType.build(domId) + "</div>");
				                            newType.bind(domId);
				                            typesArray.push(newType);
				
				                            $("#"+domId).focus();
				                            return false;
				                        });
				                    }
				
				                    if (typesArray.length === 0 && canAddNew) {
				                        $("#" + id + "_new").click();
				                    } else {
				                        for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) {
				                            domId = id + "_" + arrayIndex;
				                            typesArray[arrayIndex].bind(domId);
				                        }
				                    }
				                }
				            };
				        })();
				    }
				
				    assert(false, editors + " is not a valid editor");
				    return;
				}
				
				/**
				 *	@constructor
				 */
				function FormInputHandler(propertyFormConfig, propSettings, editorIndex) {
				    var arraySplit = propSettings.editor.split(":"),
				        editors,
				        arrayOptions = {isArrayType: arraySplit[0].indexOf('array') === 0},
				        strategy;
				
					assert(typeof propSettings.getter === 'function', 'getter should be a function');
					assert(typeof propSettings.setter === 'function', 'setter should be a function');
				
				    if (arrayOptions.isArrayType) {
				        editors = arraySplit[1].split("+");
				    } else {
				        editors = arraySplit[0].split("+");
				    }
				
				    //q(editors);
				
				    this.formConfig = propertyFormConfig;
				    if (typeof propertyFormConfig.save === 'undefined') {
				        this.setValue = propSettings.setter;
				        this.deleteValue = propSettings.deleter;
				    } else {
				        this.setValue = function(value, editorIndex) {
				            propSettings.setter(value, editorIndex);
				            propertyFormConfig.save();
				        };
				
				        this.deleteValue = function() {
				            propSettings.deleter();
				            propertyFormConfig.save();
				        };
				    }
				
				    this.getValue = propSettings.getter;
				    if (true) {
				        //q("createSettingType for " + editors[0] + " index " + editorIndex);
				            if (arrayOptions.isArrayType) {
				                arrayOptions.decorators = arraySplit[0].split("|");
				                arrayOptions.decorators.splice(0, 1);
				            }
				
				            strategy = createSettingType(this, editors[0], editorIndex, arrayOptions);
				            this.build = strategy.build;
				            this.bind = strategy.bind;
				    } else {
				        (function(inputHandler) {
				            var handlers = [],
				                index;
				
				            for (index = 0; index < editors.length; index++) {
				                handlers.push(new FormInputHandler(propertyFormConfig, propSettings, index));
				            }
				
				            inputHandler.build = function(id) {
				                var i, htmlString = "";
				                for (i = 0; i < handlers.length; i++) {
				                    htmlString += handlers[i].build(id + '_col' + i);
				                    htmlString += " &nbsp;";
				                }
				                return htmlString;
				            };
				
				            inputHandler.bind = function(id) {
				                var i;
				                for (i = 0; i < handlers.length; i++) {
				                    handlers[i].bind(id + '_col' + i);
				                }
				            };
				        })(this);
				    }
				}
				
				function buildConfigForm(contentPage, propertyFormConfig) {
				    var config = propertyFormConfig.properties,
				        prop,
				        properties = [],
				        propIndex,
				        form = "",
				        formRow,
				        container;
				
				    // show only relevant properties
				    // has side-effects
				    for (prop in config) {
				        if (config.hasOwnProperty(prop)) {
				            if (typeof config[prop].show === "undefined" || config[prop].show) {
				                config[prop].ownName = prop;
				                if (typeof config[prop].type === 'undefined') {
				                    // this is a variable <-> input form mapping
				                    config[prop].type = "propertyEditor";
				                    config[prop].propUI = new FormInputHandler(propertyFormConfig, config[prop].propUI);
				
				                } else {
				                    // these are other visual indications
				                    // ui is handled with if / else below
				                }
				
				                properties.push(config[prop]);
				            }
				        }
				    }
				
				    // build form
				    form = "<table class='vis' width='100%'>";
				    form += "<tr><th colspan='2'>" + propertyFormConfig.title + "</th>";
				    form += "</table>";
				    form = $(form);
				
				    container = $("<div class='propertyEditFormContainer' id='"+propertyFormConfig.id+"' style='display: none' />");
				    container.append(form).append("<br>");
				
				    contentPage.append(container);
				
				    for (propIndex = 0; propIndex < properties.length; propIndex++) {
				        var propUI = properties[propIndex];
				        if (propUI.type === 'propertyEditor') {
				            formRow = "<tr>";
				
				            // label
				            formRow += "<td width='25%'>";
				            if (typeof propUI.tooltip !== "undefined") {
				                formRow += "<img src='graphic/questionmark.png' title='"+propUI.tooltip+"' /> &nbsp; ";
				            }
				            formRow += propUI.label;
				            formRow += "</td>";
				
				            //editor
				            if(propUI.label == sangu_trans.mainTagger.otherButtons.hitKey) {
						formRow += "<td width='75%'>ctrl + ";
					    } else {
						formRow += "<td width='75%'>";
					    }
				            formRow += propUI.propUI.build(propertyFormConfig.id+"_"+propUI.ownName);
				            formRow += "</td>";
				
				            formRow += "</tr>";
				
				            form.append(formRow);
				
				            // bind the form to the js variable
				            if (typeof propUI.propUI.bind === 'function') {
				                propUI.propUI.bind(propertyFormConfig.id+"_"+propUI.ownName);
				            }
				        } else {
				            switch (propUI.type) {
				                case "subtitle":
				                    form.append("<tr class='row_b'><td colspan='2'><b>"+propUI.label+"</b></td></tr>");
				                    break;
				            }
				        }
				    }
				}
				/**
				 * Contains all translations for the property setting editors
				 */
				var sangu_trans = (function() {
				    var sangu_trans = {};
				    sangu_trans.nl = {
				        main: {
				            title: "Hoofdgebouw",
				            villageNames: "Standaard dorpsnamen:",
				            villageNamesTooltip: "Voeg je veelgebruikte dorpsnamen toe om een dorp met 1 klik te hernoemen.",
				            villageNameClick: "Autoclick?",
				            villageNameClickTooltip: "Schakel deze feature uit indien je bijvoorbeeld nog een nummer aan een standaard dorpsnaam wil toevoegen.",
				            ajaxLoyalty: "Toestemming tonen?"
				        },
				        global: {
				            title: "Op alle pagina's",
				            tw_version: "Compatibiliteit met TW versie {version} afdwingen",
				            tw_versionTooltip: "Dit gaat enkel de grijze Sangu bol niet meer tonen. Bugs door de TW update gaan niet op een magische manier opgelost zijn!",
				            resources: {
				                title: "Met kleuren aanduiden hoe vol de opslagplaats is",
				                activate: trans.sp.sp.settings.activate,
				                blinkWhenStorageFull: "Grondstoffen knipperen wanneer de opslagplaats vol is",
				                colors: "Kleurenschakering"
				            },
				            incomingsTitle: "Binnenkomende aanvallen/ondersteuning links",
				            incomingsEditLinks: "Linkdoelwit wijzigen",
				            incomingsEditLinksTooltip: "De binnenkomende aanval/ondersteuning link wijzigen zodat de eerste 1000 bevelen getoond worden.",
				            incomingsTrack: "Tijdchecker activeren",
				            incomingsIndicator: "Tijdchecker tekst",
				            incomingsIndicatorTooltip: "Gebruik {current} voor het huidig aantal binnenkomende aanvallen. "
				                + "{difference} voor het aantal nieuwe aanvallen. "
				                + "{saved} voor het laatst opgeslaan aantal aanvallen.",
				            incomingsIndicatorTooltip2: "Tijdchecker tooltip",
				            incomingsLastTimeCheckWarning: "Tijdchecker tooltip",
				            incomingsLastTimeCheckWarningTooltip: "Gebruik {elapsed} voor de verstreken tijd. Gebruik {time} voor de laatste tijdcheck.",
				            otherSettingsTitle: "Overige configuratie",
				            visualizeFriends: "Aangeven welke vrienden momenteel online zijn",
				            duplicateLogoffLink: "Voeg links onderaan een extra 'Afmelden' link toe.",
				            colorsTitle: "Sangu achtergrondkleuren",
				            colorsError: "Waarschuwingen",
				            colorsNeutral: "Neutrale indicaties",
				            colorsGood: "Positieve indicaties",
				            colorsSpecial: "Speciale indicaties",
				            jumperTitle: "Kaartspringer",
				            jumperAutoOpen: "Het inputveld om coördinaten in te geven direct openen"
				        },
				        incoming: {
				            title: "De standaard TW binnenkomende aanvallen tagger",
				            autoOpenTagger: "De tagger direct openen indien het bevel nog niet hernoemd is",
				            forceOpenTagger: "De tagger altijd openen",
				            renameInputTexbox: "De standaard hernoemde bevelnaam",
				            renameInputTexboxTooltip: "Legende: {unit}: korte eenheidnaam; {xy} coördinaten; {player}; {village}; {c} Continent; {fields} Afstand in velden; {night} Indicatie wanneer in nachtbonus. Maak leeg om te deactiveren.",
				            invertSort: "De snelheid mogelijkheden sorteren",
				            invertSortTooltip: "Vink dit aan om de traagste eenheid bovenaan te plaatsen"
				        },
				        overviews: {
				            addFancyImagesToOverviewLinks: "Icons toevoegen aan de overzichtslinks",
				            command: {
				                title: "Overzichtsscherm: Troepenoverzicht",
				                titleOwnTroopsPage: "Pagina's 'Eigen' en 'In het dorp'",
				                middleMouseClickDeletesRow: "Actie bij <img src='graphic/command/attack.png'>"
				                    + " aanklikken met de middelste muisknop: Aangevinkt=rij verwijderen. Uitgevinkt: rode rand rond de \"Opdracht\" cell.",
				                middleMouseClickDeletesRowTooltip: "Dit werkt enkel in Opera. Vink dit NIET AAN in Firefox of Chrome!! (De rode rand werkt ook niet in Firefox)",
				                titleDefensePage: "Pagina's 'Verdediging' en 'Ondersteuning'",
				                changeTroopsOverviewLink: "Link wijzigen om direct 'Eigen troepen' te openen",
				                filterMinPopulation: "De standaard ingevulde waarde om te filteren op populatie",
				                filterOnUnitTypeSeperator: "Eigen/In het dorp: Filteren op aantal eenheden",
				                filterMinDefaultType: "De eenheid om te filteren die standaard geselecteerd is",
				                filterMinDefault: "Het aantal eenheden om te filteren dat standaard ingevuld is",
				                filterMinDefaultTooltip: "Dit aantal wordt ingevuld wanneer de pagina opent. Bij het selecteren van een andere eenheid worden de waarden hieronder gebruikt.",
				                filterMinOther: "De standaard waarde voor de overige eenheden",
				                filterAutoSort: "De dorpenlijst automatisch sorteren na het ingeven van een doeldorp"
				            },
				            troopsRestack: {
				                title: "Alle pagina's: Stack BBCodes generatie",
				                to: "Stack een dorp tot hoeveel populatie",
				                requiredDifference: "Vereist verschil in huidige populatie in het dorp en de waarde hierboven",
				                fieldsDistanceFilterDefault: "Het standaard ingevuld aantal velden waarop gefilterd wordt",
				                filterReverse: "Aangevinkt: Rijen die voldoen aan de zoekopdracht tonen. Anders de rijen verbergen.",
				                filterReverseTooltip: "Dit kan op de pagina zelf nog aangepast worden",
				                defaultPopulationFilterAmount: "Het standaard ingevuld aantal voor de populatie filter",
				                removeRowsWithoutSupport: "Bij het berekenen van de totalen dorpen zonder ondersteuning direct verbergen",
				                autohideWithoutSupportAfterFilter: "Automatisch dorpen zonder overige ondersteuning wegfilteren na het toepassen van een filter",
				                autohideWithoutSupportAfterFilterTooltip: "Bij de aanvalsfilter worden de dorpen die niet onder aanval zijn sowieso verborgen.",
				                calculateDefTotalsAfterFilter: "Automatisch de totale ondersteuning per dorp berekenen na het toepassen van een filter",
				                calculateDefTotalsAfterFilterTooltip: "Voor sommige filters moeten de totalen sowieso toch eerst berekend worden."
				            },
				            commands: {
				                title: "Overzichtsscherm: Bevelen",
				                sumRow: "Een scheidingsrij tussen verschillende dorpen toevoegen",
				                filterFakeMaxPop: "Een bevel met minder dan deze populatie is een fake aanval (en wordt verborgen)",
				                requiredTroopAmount: "Bij de export naar BBCodes worden bevelen met minder dan deze populatie overgeslagen."
				            },
				            resources: {
				                title: "Overzichtsscherm: Productie",
				                requiredResDefault: "Het aantal grondstoffen dat standaard in het invoerveld ingevuld is",
				                requiredMerchants: "Het aantal handelaren dat standaard ingevuld is",
				                filterMerchants: "Ook filteren op aantal beschikbare handelaren",
				                filterRows: "Aanvinken om rijen te verbergen. Wanneer uitgevinkt wordt achtergrondkleur van de grondstoffen gewijzigd",
				                bbcodeMinimumDiff: "Het minimum verschil in grondstoffen tussen het aantal in het dorp en het aantal waarop gefilterd wordt voordat het dorp in de BBcode export opgenomen wordt",
				                highlightColor: "De achtergrondkleur die gebruikt wordt om de grondstoffen aan te duiden die voldoen aan de filtercriteria"
				            },
				            buildings: {
				                title: "Overzichtsscherm: Gebouwen",
				                minMaxTitle: "Geef de laagst en hoogst aanvaardbare levels voor je gebouwen",
				                minLevel: "Min {building}",
				                maxLevel: "Max {building}"
				            },
				            incomings: {
				                title: "Overzichtsscherm: Aankomend",
				                attackIdTitle: "Groeperen op aanvalsid",
				                minValueTooltip: "De te tonen tekst wanneer het verschil in aanvalsid tussen de vorige binnenkomende aanval meer is dan het aangegeven verschil",
				                seperatorTitle: "Bij verschil &lt; {minValue}",
				                minValue: "Minimum verschil",
				                text: "Tekst",
				                attackIdHigherDescription: "Te tonen tekst bij groter verschil in aanvalsid"
				            }
				        },
				        place: {
				            title: "Plaats: Speciale troepen invul links",
				            titleCustom: "Plaats: Extra troepen invul links",
				            linkText: "Link tekst",
				            link: "Link: {name}",
				
				            scoutTitle: "Verkenner links",
				            scoutVillage: "Een dorp krijgt verkenner links als er meer verkenners zijn dan dit",
				            scoutPlaceLinks: "Links om zoveel verkenners in te vullen",
				
				            fakePlaceLinkTitle: "Fake troepen link",
				            fakePlaceExcludeTroops: "Type troepen te negeren bij selecteren",
				            fakePlaceExcludeTroopsTooltip: "Gebruik de namen: spear, sword, axe, archer, sword, spy, light, marcher, heavy, ram, catapult",
				
				            noblePlaceLinkTitle: "Edel links",
				            noblePlaceLinkFirstTitle: "Edel link met het meeste troepen",
				            noblePlaceLinkFirstNameTooltip: "Er blijven genoeg troepen thuis om voor de resterende edels nog ondersteuning te kunnen sturen. Maak leeg om deze link niet te tonen.",
				
				            noblePlaceLinkSupportTitle: "Edel link met minimale ondersteuning",
				            noblePlaceLinksForceShow: "Ook tonen wanneer er slechts 1 edel in het dorp is",
				            nobleSupportOffTitle: "Edel ondersteuning voor offensief dorp",
				            nobleSupportDefTitle: "Edel ondersteuning voor defensief dorp",
				            nobleSupportUnit: "Eenheid",
				            nobleSupportAmount: "Aantal eenheden",
				
				            noblePlaceLinkDivideTitle: "Edel link met gelijk verdeelde ondersteuning",
				            noblePlaceLinkDivideAddRam: "Rammen mee selecteren",
				
				            customPlaceLinksTitle: "Andere links",
				            customPlaceOneTimeTooltip: "Vul een getal in om zoveel te sturen. Vul een negatief getal om zoveel te laten staan.",
				            customPlaceSendAlong: "Meesturen tot",
				            customPlaceSendAlongTooltip: "Indien er na selectie van bovenstaande troepen minder dan zoveel troepen in het dorp zou overblijven, selecteer dan alle troepen"
				        },
				        profile: {
				            title: "Verfraaien van het profiel van spelers en stammen",
				            moveClaim: "Verplaats dorpsclaim zodat alle andere links op dezelfde plaats blijven staan",
				            mapLink: {
				                title: "Kaarteigenschappen van link naar TWMaps kaart generator",
				                fill: "Achtergrondkleur",
				                zoom: 'Inzoom niveau',
				                grid: 'Continentlijnen',
				                gridContinentNumbers: "Continent nummers",
				                playerColor: 'Spelerskleur',
				                tribeColor: 'Zijn stam kleur',
				                centreX: "Centreren op X coördinaat",
				                centreY: "Centreren op Y coördinaat",
				                ownColor: 'Eigen kleur',
				                markedOnly: "Alleen gemarkeerde",
				                yourTribeColor: "Eigen stam kleur",
				                bigMarkers: "Grotere aanduidingen"
				            },
				            popup: {
				                title: "Overnames popup",
				                width: "Breedte van de popup",
				                height: "Hoogte van de popup",
				                left: "Horizontale positie",
				                top: "Verticale positie"
				            }
				        },
				        mainTagger: {
				            title: "Tagger op dorpsoverzicht",
				            autoOpen: "De tagger automatisch openen bij binnenkomende aanvallen",
				            inputBoxWidth: "De breedte van de bevel hernoemings inputvelden",
				            defaultDescription: "De naam die standaard in het hernoemings inputveld geplaatst wordt",
				            defaultDescriptionTooltip: "Gebruik {xy} voor de coordinaten van het herkomst dorp",
				            autoOpenCommands: "De bevel hernoemings inputvelden direct tonen",
				            minutesDisplayDodgeTimeOnMap: "Aantal minuten dat de laatste dodgetijd op de kaart getoond wordt",
				            minutesDisplayDodgeTimeOnMapTooltip: "De laatste dodgetijd is de tijd van het laatste bevel, aangeduidt met gewijzigde achtergrondkleur na het herbenoemen van binnenkomende aanvallen.",
				            minutesWithoutAttacksDottedLine: "Elke zoveel minuten zonder een tussenliggende binnenkomende aanval aanduiden met een stippelijn (180 = 3 uur)",
				            colorSupport: "Binnenkomende ondersteuning een andere achtergrondkleur geven",
				            keepReservedWords: "Tekst die vervangen wordt door een eenheid icon behouden bij hernoemen binnenkomende aanval",
				            keepReservedWordsTooltip: "Bijvoorbeeld \"Verk.\" wordt vervangen door een verkenners icon",
				            otherButtons: {
				                title: "Andere hernoemings knoppen",
				                renameTo: "Hernoemen naar",
				                button: "Tekst knop",
						        hitKey: "Sneltoets"
				            }
				        },
				        confirm: {
				            title: "Bevel comfirmatie pagina",
				            addExtraOkButton: "Links bovenaan de pagina een extra OK knop toevoegen",
				            replaceNightBonus: "Nachtbonus melding verwerken in de pagina titel",
				            replaceTribeClaim: "Dorpsclaim melding verwerken in de pagina titel",
				            addCatapultImages: "Gebouws iconen tonen om snel het katapult doelwit te wijzigen"
				        },
				        villageInfo: {
				            title: "Extra links naar het troepenoverzicht",
				            title2: "Twee extra links naar het troepenoverzicht op elke dorpsinformatie pagina toevoegen",
				            icon: "Kies een icoon",
				            off_title: "Extra link voor aanvallen",
				            def_title: "Extra link voor verdedigen",
				            linkName: "De link die toegevoegd wordt",
				            group: "Binnen welk groep id openen (kies 0 voor alle groepen)",
				            groupTitle: "Zodra je meer dan 1000 dorpen bezit worden enkel die eerste 1000 getoond & gefilterd. Door een groep id in te geven (vb je groep \"aanvalsdorpen\" of \"verdedigingsdorpen\") wordt de troepenlijst binnen deze groep geopend.",
				            activateFilter: "Filter activeren",
				            filter: {
				                title: "Direct filteren",
				                unit: "Eenheid",
				                amount: "Minimale hoeveelheid"
				            },
				            sort: "Dorpenlijst direct sorteren",
				            changeSpeed: "Traagste eenheid snelheid wijzigen"
				        },
				        other: {
				            title: "Overige configuratie",
				            proStyle: "Pro Style?",
				            proStyleTooltip: "Met deze setting worden een heleboel kleinere features aan of uitgeschakeld",
				            timeDisplayTitle: "Hoe looptijden weergeven",
				            displayDays: "Dagen tonen wanneer de troepen langer dan 24 uur lopen?",
				            displayDaysTooltip: "Voorbeeld: toon \"1.18:01:36\" wanneer aangevinkt, zoniet wordt die looptijd als \"42:01:36\" weergegeven",
				            walkingTimeDisplay: "Te tonen tekst",
				            walkingTimeDisplayTooltip: "Gebruik {duration} voor het aantal uren en {arrival} voor de aankomstdatum",
				            calculateSnob: "Berekenen hoeveel edels direct kunnen geproduceerd worden",
				            showPlayerProfileOnVillage: "Het uitgebreide spelersprofiel tonen op een dorpsinformatie pagina",
				            farmLimitTitle: "Dorpstacks achtergrondkleuren",
				            farmLimitStackColors: "Kleurenschakering",
				            farmLimitAcceptableOverstack: "Acceptabele overstack voor elke kleurschakering",
				            farmLimitAcceptableOverstackTooltip: "Boerderijlimiet: {farmlimit}",
				            farmLimitUnlimitedStack: "Aantal populatie voor elke kleurschakering",
				            ajaxSeperateSupport: "Dorpsoverzicht: Visualiseer het verschil tussen eigen en ondersteunende troepen in het dorpsoverzicht",
				            canHideDiv: "Dorpsoverzicht: Een extra X icon toevoegen om een info kader volledig te verwijderen",
				            commandRenamer: "Bevelen automatisch hernoemen",
				            commandRenamerActive: "De verzonden troepen in de bevelnaam weergeven",
				            commandRenamerAddHaul: "De buit aan de bevelnaam toevoegen"
				        }
				    };
				
				    //sangu_trans.de = {};
				
				    /*sangu_trans.en = {
				        main: {
				            title: "Main building",
				            villageNames: "Village names:",
				            villageNamesTooltip: "Add village names to the village headquarters to quickly edit the village name to a preset name.",
				            villageNameClick: "Autoclick?",
				            villageNameClickTooltip: "true: one of the previous button clicked automatically changes the village name. false: only fills in the name in the textbox but does not click the button",
				            ajaxLoyalty: "Show loyalty?",
				            ajaxLoyaltyTooltip: "Get the loyalty at the building construction/destruction page"
				        }
				    };*/
				
				    return sangu_trans[game_data.market];
				}());
				/**
				 * Configuration array containing the metadata for generating the different
				 * property editor UIs
				 */
				var user_data_configs = (function() {
				        /**
				         * Debug bool
				         */
				    var showConfigs = true,
				        user_data_configs = [],
				        sangu_saver = function() {
				            pers.set('sangusettings', JSON.stringify(user_data));
				            trackEvent("ScriptUsage", "SettingEdit", "1");
				        };
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "global",
				            title: sangu_trans.global.title,
				            save: sangu_saver,
				            properties: {
				                twVersion: {
				                    label: sangu_trans.global.tw_version.replace("{version}", game_data.majorVersion),
				                    tooltip: sangu_trans.global.tw_versionTooltip,
				                    propUI: {
				                        getter: function() { return pers.get("forceCompatibility") !== '' && pers.get("forceCompatibility") === 'true'; },
				                        setter: function(value) { pers.set("forceCompatibility", value); },
				                        editor: "bool"
				                    }
				                },
				                resourcesTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.global.resources.title
				                },
				                resourcesActivate: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.global.resources.active; },
				                        setter: function(value) { user_data.global.resources.active = value; },
				                        editor: "bool"
				                    }
				                },
				                resourceColors: {
				                    label: sangu_trans.global.resources.colors,
				                    propUI: {
				                        getter: function() { return user_data.global.resources.backgroundColors; },
				                        setter: function(value) { user_data.global.resources.backgroundColors = value; },
				                        editor: "array|inline:color"
				                    }
				                },
				                resourcesBlinkWhenFull: {
				                    label: sangu_trans.global.resources.blinkWhenStorageFull,
				                    propUI: {
				                        getter: function() { return user_data.global.resources.blinkWhenStorageFull; },
				                        setter: function(value) { user_data.global.resources.blinkWhenStorageFull = value; },
				                        editor: "bool"
				                    }
				                },
				                incomingsTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.global.incomingsTitle
				                },
				                incomingsEditLinks: {
				                    label: sangu_trans.global.incomingsEditLinks,
				                    tooltip: sangu_trans.global.incomingsEditLinksTooltip,
				                    propUI: {
				                        getter: function() { return user_data.global.incomings.editLinks; },
				                        setter: function(value) { user_data.global.incomings.editLinks = value; },
				                        editor: "bool"
				                    }
				                },
				                incomingsTrack: {
				                    label: sangu_trans.global.incomingsTrack,
				                    propUI: {
				                        getter: function() { return user_data.global.incomings.track; },
				                        setter: function(value) { user_data.global.incomings.track = value; },
				                        editor: "bool"
				                    }
				                },
				                incomingsIndicator: {
				                    label: sangu_trans.global.incomingsIndicator,
				                    tooltip: sangu_trans.global.incomingsIndicatorTooltip,
				                    propUI: {
				                        getter: function() { return user_data.global.incomings.indicator; },
				                        setter: function(value) { user_data.global.incomings.indicator = value; },
				                        editor: "text"
				                    }
				                },
				                incomingsIndicatorTooltip2: {
				                    label: sangu_trans.global.incomingsIndicatorTooltip2,
				                    propUI: {
				                        getter: function() { return user_data.global.incomings.indicatorTooltip; },
				                        setter: function(value) { user_data.global.incomings.indicatorTooltip = value; },
				                        editor: "text"
				                    }
				                },
				                lastTimeCheckWarning: {
				                    label: sangu_trans.global.incomingsLastTimeCheckWarning,
				                    tooltip: sangu_trans.global.incomingsLastTimeCheckWarningTooltip,
				                    propUI: {
				                        getter: function() { return user_data.global.incomings.lastTimeCheckWarning; },
				                        setter: function(value) { user_data.global.incomings.lastTimeCheckWarning = value; },
				                        editor: "text"
				                    }
				                },
				                jumperTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.global.jumperTitle
				                },
				                jumperActivate: {
				                    label: trans.sp.sp.settings.activate,
				                    propUI: {
				                        getter: function() { return user_data.jumper.enabled; },
				                        setter: function(value) { user_data.jumper.enabled = value; },
				                        editor: "bool"
				                    }
				                },
				                jumperAutoOpen: {
				                    label: sangu_trans.global.jumperAutoOpen,
				                    propUI: {
				                        getter: function() { return user_data.jumper.autoShowInputbox; },
				                        setter: function(value) { user_data.jumper.autoShowInputbox = value; },
				                        editor: "bool"
				                    }
				                },
				                colorsTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.global.colorsTitle
				                },
				                colorsError: {
				                    label: sangu_trans.global.colorsError,
				                    propUI: {
				                        getter: function() { return user_data.colors.error; },
				                        setter: function(value) { user_data.colors.error = value; },
				                        editor: "color"
				                    }
				                },
				                colorsGood: {
				                    label: sangu_trans.global.colorsGood,
				                    propUI: {
				                        getter: function() { return user_data.colors.good; },
				                        setter: function(value) { user_data.colors.good = value; },
				                        editor: "color"
				                    }
				                },
				                colorsNeutral: {
				                    label: sangu_trans.global.colorsNeutral,
				                    propUI: {
				                        getter: function() { return user_data.colors.neutral; },
				                        setter: function(value) { user_data.colors.neutral = value; },
				                        editor: "color"
				                    }
				                },
				                colorsSpecial: {
				                    label: sangu_trans.global.colorsSpecial,
				                    propUI: {
				                        getter: function() { return user_data.colors.special; },
				                        setter: function(value) { user_data.colors.special = value; },
				                        editor: "color"
				                    }
				                },
				                otherSettingsTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.global.otherSettingsTitle
				                },
				                visualizeFriends: {
				                    label: sangu_trans.global.visualizeFriends,
				                    propUI: {
				                        getter: function() { return user_data.global.visualizeFriends; },
				                        setter: function(value) { user_data.global.visualizeFriends = value; },
				                        editor: "bool"
				                    }
				                },
				                duplicateLogoffLink: {
				                    label: sangu_trans.global.duplicateLogoffLink,
				                    propUI: {
				                        getter: function() { return user_data.global.duplicateLogoffLink; },
				                        setter: function(value) { user_data.global.duplicateLogoffLink = value; },
				                        editor: "bool"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "main",
				            title: sangu_trans.main.title,
				            save: sangu_saver,
				            properties: {
				                villageNames: {
				                    tooltip: sangu_trans.main.villageNamesTooltip,
				                    label: sangu_trans.main.villageNames,
				                    propUI: {
				                        getter: function() { return user_data.main.villageNames; },
				                        setter: function(value) { user_data.main.villageNames = value; },
				                        editor: "array|addNew:text|delete"
				                    }
				                },
				                villageNameClick: {
				                    tooltip: sangu_trans.main.villageNameClickTooltip,
				                    label: sangu_trans.main.villageNameClick,
				                    propUI: {
				                        getter: function() { return user_data.main.villageNameClick; },
				                        setter: function(value) { user_data.main.villageNameClick = value; },
				                        editor: "bool"
				                    }
				                },
				                ajaxLoyalty: {
				                    label: sangu_trans.main.ajaxLoyalty,
				                    show: server_settings.ajaxAllowed,
				                    propUI: {
				                        getter: function() { return user_data.main.ajaxLoyalty; },
				                        setter: function(value) { user_data.main.ajaxLoyalty = value; },
				                        editor: "bool"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "incoming",
				            title: sangu_trans.incoming.title,
				            save: sangu_saver,
				            properties: {
				                autoOpenTagger: {
				                    label: sangu_trans.incoming.autoOpenTagger,
				                    propUI: {
				                        getter: function() { return user_data.incoming.autoOpenTagger; },
				                        setter: function(value) { user_data.incoming.autoOpenTagger = value; },
				                        editor: "bool"
				                    }
				                },
				                forceOpenTagger: {
				                    label: sangu_trans.incoming.forceOpenTagger,
				                    propUI: {
				                        getter: function() { return user_data.incoming.forceOpenTagger; },
				                        setter: function(value) { user_data.incoming.forceOpenTagger = value; },
				                        editor: "bool"
				                    }
				                },
				                renameInputTexbox: {
				                    label: sangu_trans.incoming.renameInputTexbox,
				                    tooltip: sangu_trans.incoming.renameInputTexboxTooltip,
				                    propUI: {
				                        getter: function() { return user_data.incoming.renameInputTexbox; },
				                        setter: function(value) { user_data.incoming.renameInputTexbox = value; },
				                        editor: "text"
				                    }
				                },
				                invertSort: {
				                    label: sangu_trans.incoming.invertSort,
				                    tooltip: sangu_trans.incoming.invertSortTooltip,
				                    propUI: {
				                        getter: function() { return user_data.incoming.invertSort; },
				                        setter: function(value) { user_data.incoming.invertSort = value; },
				                        editor: "bool"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        (function() {
				            var properties = {
				                activate: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.active; },
				                        setter: function(value) { user_data.mainTagger2.active = value; },
				                        editor: "bool"
				                    }
				                },
				                autoOpen: {
				                    label: sangu_trans.mainTagger.autoOpen,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.autoOpen; },
				                        setter: function(value) { user_data.mainTagger2.autoOpen = value; },
				                        editor: "bool"
				                    }
				                },
				                inputBoxWidth: {
				                    label: sangu_trans.mainTagger.inputBoxWidth,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.inputBoxWidth; },
				                        setter: function(value) { user_data.mainTagger2.inputBoxWidth = value; },
				                        editor: "number|step=5"
				                    }
				                },
				                autoOpenCommands: {
				                    label: sangu_trans.mainTagger.autoOpenCommands,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.autoOpenCommands; },
				                        setter: function(value) { user_data.mainTagger2.autoOpenCommands = value; },
				                        editor: "bool"
				                    }
				                },
				                minutesDisplayDodgeTimeOnMap: {
				                    label: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMap,
				                    tooltip: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMapTooltip,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.minutesDisplayDodgeTimeOnMap; },
				                        setter: function(value) { user_data.mainTagger2.minutesDisplayDodgeTimeOnMap = value; },
				                        editor: "number"
				                    }
				                },
				                minutesWithoutAttacksDottedLine: {
				                    label: sangu_trans.mainTagger.minutesWithoutAttacksDottedLine,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.minutesWithoutAttacksDottedLine; },
				                        setter: function(value) { user_data.mainTagger2.minutesWithoutAttacksDottedLine = value; },
				                        editor: "number|step=60"
				                    }
				                },
				                colorSupport: {
				                    label: sangu_trans.mainTagger.colorSupport,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.colorSupport; },
				                        setter: function(value) { user_data.mainTagger2.colorSupport = value; },
				                        editor: "color"
				                    }
				                },
				                defaultDescription: {
				                    label: sangu_trans.mainTagger.defaultDescription,
				                    tooltip: sangu_trans.mainTagger.defaultDescriptionTooltip,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.defaultDescription; },
				                        setter: function(value) { user_data.mainTagger2.defaultDescription = value; },
				                        editor: "text"
				                    }
				                },
				                keepReservedWords: {
				                    label: sangu_trans.mainTagger.keepReservedWords,
				                    tooltip: sangu_trans.mainTagger.keepReservedWordsTooltip,
				                    propUI: {
				                        getter: function() { return user_data.mainTagger2.keepReservedWords; },
				                        setter: function(value) { user_data.mainTagger2.keepReservedWords = value; },
				                        editor: "bool"
				                    }
				                },
				                otherButtonsTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.mainTagger.otherButtons.title
				                }
				            };
				
				            for (var i = 0; i < user_data.mainTagger2.otherDescs.length; i++) {
				                (function() {
				                    var otherDescription = user_data.mainTagger2.otherDescs[i];
				
				                    properties['otherButton'+i] = {
				                        type: "subtitle",
				                        label: sangu_trans.mainTagger.otherButtons.title + ": " + otherDescription.name
				                    }
				
				                    properties['otherButtonActive'+i] = {
				                        label: sangu_trans.global.resources.activate,
				                        propUI: {
				                            getter: function() { return otherDescription.active; },
				                            setter: function(value) { otherDescription.active = value; },
				                            editor: "bool"
				                        }
				                    }
				
				                    properties['otherButtonName'+i] = {
				                        label: sangu_trans.mainTagger.otherButtons.button,
				                        propUI: {
				                            getter: function() { return otherDescription.name; },
				                            setter: function(value) { otherDescription.name = value; },
				                            editor: "text|width=10"
				                        }
				                    }
				                    
				                    properties['otherButtonHitKey'+i] = {
				                        label: sangu_trans.mainTagger.otherButtons.hitKey,
				                        propUI: {
				                            getter: function() { return otherDescription.hitKey; },
				                            setter: function(value) { otherDescription.hitKey = value; },
				                            editor: "text|width=4"
				                        }
				                    }
				
				                    properties['otherButtonDesc'+i] = {
				                        label: sangu_trans.mainTagger.otherButtons.renameTo,
				                        propUI: {
				                            getter: function() { return otherDescription.renameTo; },
				                            setter: function(value) { otherDescription.renameTo = value; },
				                            editor: "text|width=50"
				                        }
				                    }
				                }());
				            }
				
				
				            user_data_configs.push({
				                id: "mainTagger",
				                title: sangu_trans.mainTagger.title,
				                save: sangu_saver,
				                properties: properties
				            });
				        }());
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "confirm",
				            title: sangu_trans.confirm.title,
				            save: sangu_saver,
				            properties: {
				                addExtraOkButton: {
				                    label: sangu_trans.confirm.addExtraOkButton,
				                    propUI: {
				                        getter: function() { return user_data.confirm.addExtraOkButton; },
				                        setter: function(value) { user_data.confirm.addExtraOkButton = value; },
				                        editor: "bool"
				                    }
				                },
				                replaceNightBonus: {
				                    label: sangu_trans.confirm.replaceNightBonus,
				                    show: world_config.nightbonus.active,
				                    propUI: {
				                        getter: function() { return user_data.confirm.replaceNightBonus; },
				                        setter: function(value) { user_data.confirm.replaceNightBonus = value; },
				                        editor: "bool"
				                    }
				                },
				                replaceTribeClaim: {
				                    label: sangu_trans.confirm.replaceTribeClaim,
				                    propUI: {
				                        getter: function() { return user_data.confirm.replaceTribeClaim; },
				                        setter: function(value) { user_data.confirm.replaceTribeClaim = value; },
				                        editor: "bool"
				                    }
				                },
				                addCatapultImages: {
				                    label: sangu_trans.confirm.addCatapultImages,
				                    propUI: {
				                        getter: function() { return user_data.confirm.addCatapultImages; },
				                        setter: function(value) { user_data.confirm.addCatapultImages = value; },
				                        editor: "bool"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "profile",
				            title: sangu_trans.profile.title,
				            save: sangu_saver,
				            properties: {
				                show: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.profile.show; },
				                        setter: function(value) { user_data.profile.show = value; },
				                        editor: "bool"
				                    }
				                },
				                moveClaim: {
				                    label: sangu_trans.profile.moveClaim,
				                    propUI: {
				                        getter: function() { return user_data.profile.moveClaim; },
				                        setter: function(value) { user_data.profile.moveClaim = value; },
				                        editor: "bool"
				                    }
				                },
				                mapLink: {
				                    type: "subtitle",
				                    label: sangu_trans.profile.mapLink.title
				                },
				                mapLinkShow: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.show; },
				                        setter: function(value) { user_data.profile.mapLink.show = value; },
				                        editor: "bool"
				                    }
				                },
				                mapLinkFill: {
				                    label: sangu_trans.profile.mapLink.fill,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.fill; },
				                        setter: function(value) { user_data.profile.mapLink.fill = value; },
				                        editor: "color"
				                    }
				                },
				                mapLinkZoom: {
				                    label: sangu_trans.profile.mapLink.zoom,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.zoom; },
				                        setter: function(value) { user_data.profile.mapLink.zoom = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                mapLinkGrid: {
				                    label: sangu_trans.profile.mapLink.grid,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.grid; },
				                        setter: function(value) { user_data.profile.mapLink.grid = value; },
				                        editor: "bool"
				                    }
				                },
				                mapLinkGridContinentNumbers: {
				                    label: sangu_trans.profile.mapLink.gridContinentNumbers,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.gridContinentNumbers; },
				                        setter: function(value) { user_data.profile.mapLink.gridContinentNumbers = value; },
				                        editor: "bool"
				                    }
				                },
				                mapLinkPlayerColor: {
				                    label: sangu_trans.profile.mapLink.playerColor,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.playerColor; },
				                        setter: function(value) { user_data.profile.mapLink.playerColor = value; },
				                        editor: "color"
				                    }
				                },
				                mapLinkTribeColor: {
				                    label: sangu_trans.profile.mapLink.tribeColor,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.tribeColor; },
				                        setter: function(value) { user_data.profile.mapLink.tribeColor = value; },
				                        editor: "color"
				                    }
				                },
				                mapLinkCentreX: {
				                    label: sangu_trans.profile.mapLink.centreX,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.centreX; },
				                        setter: function(value) { user_data.profile.mapLink.centreX = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                mapLinkCentreY: {
				                    label: sangu_trans.profile.mapLink.centreY,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.centreY; },
				                        setter: function(value) { user_data.profile.mapLink.centreY = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                mapLinkOwnColor: {
				                    label: sangu_trans.profile.mapLink.ownColor,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.ownColor; },
				                        setter: function(value) { user_data.profile.mapLink.ownColor = value; },
				                        editor: "color"
				                    }
				                },
				                mapLinkMarkedOnly: {
				                    label: sangu_trans.profile.mapLink.markedOnly,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.markedOnly; },
				                        setter: function(value) { user_data.profile.mapLink.markedOnly = value; },
				                        editor: "bool"
				                    }
				                },
				                mapLinkBigMarkers: {
				                    label: sangu_trans.profile.mapLink.bigMarkers,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.bigMarkers; },
				                        setter: function(value) { user_data.profile.mapLink.bigMarkers = value; },
				                        editor: "bool"
				                    }
				                },
				                mapLinkYourTribeColor: {
				                    label: sangu_trans.profile.mapLink.yourTribeColor,
				                    propUI: {
				                        getter: function() { return user_data.profile.mapLink.yourTribeColor; },
				                        setter: function(value) { user_data.profile.mapLink.yourTribeColor = value; },
				                        editor: "color"
				                    }
				                },
				                popup: {
				                    type: "subtitle",
				                    label: sangu_trans.profile.popup.title
				                },
				                popupShow: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.profile.popup.show; },
				                        setter: function(value) { user_data.profile.popup.show = value; },
				                        editor: "bool"
				                    }
				                },
				                popupTop: {
				                    label: sangu_trans.profile.popup.top,
				                    propUI: {
				                        getter: function() { return user_data.profile.popup.top; },
				                        setter: function(value) { user_data.profile.popup.top = value; },
				                        editor: "number|step=25"
				                    }
				                },
				                popupLeft: {
				                    label: sangu_trans.profile.popup.left,
				                    propUI: {
				                        getter: function() { return user_data.profile.popup.left; },
				                        setter: function(value) { user_data.profile.popup.left = value; },
				                        editor: "number|step=25"
				                    }
				                },
				                popupWidth: {
				                    label: sangu_trans.profile.popup.width,
				                    propUI: {
				                        getter: function() { return user_data.profile.popup.width; },
				                        setter: function(value) { user_data.profile.popup.width = value; },
				                        editor: "number|step=25"
				                    }
				                },
				                popupHeight: {
				                    label: sangu_trans.profile.popup.height,
				                    propUI: {
				                        getter: function() { return user_data.profile.popup.height; },
				                        setter: function(value) { user_data.profile.popup.height = value; },
				                        editor: "number|step=25"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "placeLinks",
				            title: sangu_trans.place.title,
				            save: sangu_saver,
				            properties: {
				                scoutTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.scoutTitle
				                },
				                scoutPlaceLinksName: {
				                    label: sangu_trans.place.linkText,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.scoutPlaceLinksName; },
				                        setter: function(value) { user_data.place.attackLinks.scoutPlaceLinksName = value; },
				                        editor: "text|width=23"
				                    }
				                },
				                scoutVillage: {
				                    label: sangu_trans.place.scoutVillage,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.scoutVillage; },
				                        setter: function(value) { user_data.place.attackLinks.scoutVillage = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                scoutPlaceLinks: {
				                    label: sangu_trans.place.scoutPlaceLinks,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.scoutPlaceLinks; },
				                        setter: function(value) { user_data.place.attackLinks.scoutPlaceLinks = value; },
				                        editor: "array|addNew:number|step=10|delete"
				                    }
				                },
				
				
				
				
				
				                fakePlaceLinkTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.fakePlaceLinkTitle
				                },
				                fakePlaceLinkName: {
				                    label: sangu_trans.place.linkText,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.fakePlaceLinkName; },
				                        setter: function(value) { user_data.place.attackLinks.fakePlaceLinkName = value; },
				                        editor: "text|width=23"
				                    }
				                },
				                fakePlaceLink: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.fakePlaceLink; },
				                        setter: function(value) { user_data.place.attackLinks.fakePlaceLink = value; },
				                        editor: "bool"
				                    }
				                },
				                fakePlaceExcludeTroops: {
				                    label: sangu_trans.place.fakePlaceExcludeTroops,
				                    tooltip: sangu_trans.place.fakePlaceExcludeTroopsTooltip,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.fakePlaceExcludeTroops; },
				                        setter: function(value) { user_data.place.attackLinks.fakePlaceExcludeTroops = value; },
				                        editor: "array|addNew:text|delete|width=7"
				                    }
				                },
				
				
				
				
				
				
				                noblePlaceLinkTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.noblePlaceLinkTitle
				                },
				                noblePlaceLinkDivideTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.noblePlaceLinkDivideTitle
				                },
				                noblePlaceLinkDivideName: {
				                    label: sangu_trans.place.linkText,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideName; },
				                        setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideName = value; },
				                        editor: "text|width=23"
				                    }
				                },
				                noblePlaceLink: {
				                    label: sangu_trans.global.resources.activate,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.noblePlaceLink; },
				                        setter: function(value) { user_data.place.attackLinks.noblePlaceLink = value; },
				                        editor: "bool"
				                    }
				                },
				                noblePlaceLinkDivideAddRam: {
				                    label: sangu_trans.place.noblePlaceLinkDivideAddRam,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideAddRam; },
				                        setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideAddRam = value; },
				                        editor: "bool"
				                    }
				                },
				                noblePlaceLinkFirstTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.noblePlaceLinkFirstTitle
				                },
				                noblePlaceLinkFirstName: {
				                    label: sangu_trans.place.linkText,
				                    tooltip: sangu_trans.place.noblePlaceLinkFirstNameTooltip,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.noblePlaceLinkFirstName; },
				                        setter: function(value) { user_data.place.attackLinks.noblePlaceLinkFirstName = value; },
				                        editor: "text|width=23"
				                    }
				                },
				                noblePlaceLinkSupportTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.noblePlaceLinkSupportTitle
				                },
				                noblePlaceLinkSupportName: {
				                    label: sangu_trans.place.linkText,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.noblePlaceLinkSupportName; },
				                        setter: function(value) { user_data.place.attackLinks.noblePlaceLinkSupportName = value; },
				                        editor: "text|width=23"
				                    }
				                },
				                noblePlaceLinksForceShow: {
				                    label: sangu_trans.place.noblePlaceLinksForceShow,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.noblePlaceLinksForceShow; },
				                        setter: function(value) { user_data.place.attackLinks.noblePlaceLinksForceShow = value; },
				                        editor: "bool"
				                    }
				                },
				                nobleSupportOffTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.nobleSupportOffTitle
				                },
				                nobleSupportOffUnit: {
				                    label: sangu_trans.place.nobleSupportUnit,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.nobleSupport[0].unit; },
				                        setter: function(value) { user_data.place.attackLinks.nobleSupport[0].unit = value; },
				                        editor: "unit"
				                    }
				                },
				                nobleSupportOffAmount: {
				                    label: sangu_trans.place.nobleSupportAmount,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.nobleSupport[0].amount; },
				                        setter: function(value) { user_data.place.attackLinks.nobleSupport[0].amount = value; },
				                        editor: "number|step=50"
				                    }
				                },
				                nobleSupportDefTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.place.nobleSupportDefTitle
				                },
				                nobleSupportDefUnit: {
				                    label: sangu_trans.place.nobleSupportUnit,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.nobleSupport[1].unit; },
				                        setter: function(value) { user_data.place.attackLinks.nobleSupport[1].unit = value; },
				                        editor: "unit"
				                    }
				                },
				                nobleSupportDefAmount: {
				                    label: sangu_trans.place.nobleSupportAmount,
				                    propUI: {
				                        getter: function() { return user_data.place.attackLinks.nobleSupport[1].amount; },
				                        setter: function(value) { user_data.place.attackLinks.nobleSupport[1].amount = value; },
				                        editor: "number|step=50"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        (function() {
				            var i,
				                properties = {};
				
				            for (i = 0; i < user_data.place.customPlaceLinks.length; i++) {
				                (function() {
				                    var unitTypeIndex,
				                        customPlaceLink = user_data.place.customPlaceLinks[i],
				                        oneTimeTooltip = i == 0 ? sangu_trans.place.customPlaceOneTimeTooltip : undefined,
				                        oneTimeTooltipSendAlong = i == 0 ? sangu_trans.place.customPlaceSendAlongTooltip : undefined;
				
				                    properties['customPlaceLink'+i+'Title'] = {
				                        type: "subtitle",
				                        label: sangu_trans.place.link.replace("{name}", customPlaceLink.name)
				                    };
				
				                    properties['customPlaceLink'+i+'Name'] = {
				                        label: sangu_trans.place.linkText,
				                        propUI: {
				                            getter: function() { return customPlaceLink.name; },
				                            setter: function(value) { customPlaceLink.name = value; },
				                            editor: "text|width=23"
				                        }
				                    };
				
				                    properties['customPlaceLink'+i+'Active'] = {
				                        label: sangu_trans.global.resources.activate,
				                        propUI: {
				                            getter: function() { return customPlaceLink.active; },
				                            setter: function(value) { customPlaceLink.active = value; },
				                            editor: "bool"
				                        }
				                    };
				
				                    for (unitTypeIndex = 0; unitTypeIndex < world_data.units.length; unitTypeIndex++) {
				                        (function() {
				                            var unit = world_data.units[unitTypeIndex],
				                                reallyOneTimeTooltip = unitTypeIndex == 0 && oneTimeTooltip ? oneTimeTooltip : undefined;
				
				                            properties['customPlaceLink'+i+unit] = {
				                                label: "<img src='graphic/unit/unit_"+unit+".png'/>",
				                                tooltip: reallyOneTimeTooltip,
				                                propUI: {
				                                    getter: function() { return customPlaceLink[unit]; },
				                                    setter: function(value) { customPlaceLink[unit] = value; },
				                                    editor: "number|step=100"
				                                }
				                            };
				                        })();
				                    }
				
				                    properties['customPlaceLink'+i+'SendAlong'] = {
				                        label: sangu_trans.place.customPlaceSendAlong,
				                        tooltip: oneTimeTooltipSendAlong,
				                        propUI: {
				                            getter: function() { return customPlaceLink.sendAlong; },
				                            setter: function(value) { customPlaceLink.sendAlong = value; },
				                            editor: "number|step=100"
				                        }
				                    };
				                })();
				            }
				
				            user_data_configs.push({
				                id: "placeLinksCustom",
				                title: sangu_trans.place.titleCustom,
				                save: sangu_saver,
				                properties: properties
				            });
				        }());
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "overviewsTroops",
				            title: sangu_trans.overviews.command.title,
				            save: sangu_saver,
				            properties: {
				                changeTroopsOverviewLink: {
				                    label: sangu_trans.overviews.command.changeTroopsOverviewLink,
				                    propUI: {
				                        getter: function() { return user_data.command.changeTroopsOverviewLink; },
				                        setter: function(value) { user_data.command.changeTroopsOverviewLink = value; },
				                        editor: "bool"
				                    }
				                },
				                defaultPopulationFilterAmount: {
				                    label: sangu_trans.overviews.troopsRestack.defaultPopulationFilterAmount,
				                    propUI: {
				                        getter: function() { return user_data.restack.defaultPopulationFilterAmount; },
				                        setter: function(value) { user_data.restack.defaultPopulationFilterAmount = value; },
				                        editor: "number|step=1000"
				                    }
				                },
				
				                titleOwnTroopsPage: {
				                    type: "subtitle",
				                    label: sangu_trans.overviews.command.titleOwnTroopsPage
				                },
				                middleMouseClickDeletesRow: {
				                    label: sangu_trans.overviews.command.middleMouseClickDeletesRow,
				                    tooltip: sangu_trans.overviews.command.middleMouseClickDeletesRowTooltip,
				                    propUI: {
				                        getter: function() { return user_data.command.middleMouseClickDeletesRow2; },
				                        setter: function(value) { user_data.command.middleMouseClickDeletesRow2 = value; },
				                        editor: "bool"
				                    }
				                },
				                filterAutoSort: {
				                    label: sangu_trans.overviews.command.filterAutoSort,
				                    propUI: {
				                        getter: function() { return user_data.command.filterAutoSort; },
				                        setter: function(value) { user_data.command.filterAutoSort = value; },
				                        editor: "bool"
				                    }
				                },
				
				
				                titleDefensePage: {
				                    type: "subtitle",
				                    label: sangu_trans.overviews.command.titleDefensePage
				                },
				                fieldsDistanceFilterDefault: {
				                    label: sangu_trans.overviews.troopsRestack.fieldsDistanceFilterDefault,
				                    propUI: {
				                        getter: function() { return user_data.restack.fieldsDistanceFilterDefault; },
				                        setter: function(value) { user_data.restack.fieldsDistanceFilterDefault = value; },
				                        editor: "number"
				                    }
				                },
				                filterReverse: {
				                    label: sangu_trans.overviews.troopsRestack.filterReverse,
				                    tooltip: sangu_trans.overviews.troopsRestack.filterReverseTooltip,
				                    propUI: {
				                        getter: function() { return user_data.restack.filterReverse; },
				                        setter: function(value) { user_data.restack.filterReverse = value; },
				                        editor: "bool"
				                    }
				                },
				                filterMinPopulation: {
				                    label: sangu_trans.overviews.command.filterMinPopulation,
				                    propUI: {
				                        getter: function() { return user_data.command.filterMinPopulation; },
				                        setter: function(value) { user_data.command.filterMinPopulation = value; },
				                        editor: "number|step=1000"
				                    }
				                },
				                removeRowsWithoutSupport: {
				                    label: sangu_trans.overviews.troopsRestack.removeRowsWithoutSupport,
				                    propUI: {
				                        getter: function() { return user_data.restack.removeRowsWithoutSupport; },
				                        setter: function(value) { user_data.restack.removeRowsWithoutSupport = value; },
				                        editor: "bool"
				                    }
				                },
				                autohideWithoutSupportAfterFilter: {
				                    label: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilter,
				                    tooltip: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilterTooltip,
				                    propUI: {
				                        getter: function() { return user_data.restack.autohideWithoutSupportAfterFilter; },
				                        setter: function(value) { user_data.restack.autohideWithoutSupportAfterFilter = value; },
				                        editor: "bool"
				                    }
				                },
				                calculateDefTotalsAfterFilter: {
				                    label: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilter,
				                    tooltip: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilterTooltip,
				                    propUI: {
				                        getter: function() { return user_data.restack.calculateDefTotalsAfterFilter; },
				                        setter: function(value) { user_data.restack.calculateDefTotalsAfterFilter = value; },
				                        editor: "bool"
				                    }
				                },
				
				                commandTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.overviews.command.filterOnUnitTypeSeperator
				                },
				                filterMinDefaultType: {
				                    label: sangu_trans.overviews.command.filterMinDefaultType,
				                    propUI: {
				                        getter: function() { return user_data.command.filterMinDefaultType; },
				                        setter: function(value) { user_data.command.filterMinDefaultType = value; },
				                        editor: "unit"
				                    }
				                },
				                filterMinDefault: {
				                    label: sangu_trans.overviews.command.filterMinDefault,
				                    tooltip: sangu_trans.overviews.command.filterMinDefaultTooltip,
				                    propUI: {
				                        getter: function() { return user_data.command.filterMinDefault; },
				                        setter: function(value) { user_data.command.filterMinDefault = value; },
				                        editor: "number|step=100"
				                    }
				                },
				                filterMinSpear: {
				                    label: "<img src='graphic/unit/unit_spear.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.spear; },
				                        setter: function(value) { user_data.command.filterMin.spear = value; },
				                        editor: "number|step=500"
				                    }
				                },
				                filterMinSword: {
				                    label: "<img src='graphic/unit/unit_sword.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.sword; },
				                        setter: function(value) { user_data.command.filterMin.sword = value; },
				                        editor: "number|step=500"
				                    }
				                },
				                filterMinAxe: {
				                    label: "<img src='graphic/unit/unit_axe.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.axe; },
				                        setter: function(value) { user_data.command.filterMin.axe = value; },
				                        editor: "number|step=500"
				                    }
				                },
				                filterMinArcher: {
				                    label: "<img src='graphic/unit/unit_archer.png' />",
				                    show: world_config.hasArchers,
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.archer; },
				                        setter: function(value) { user_data.command.filterMin.archer = value; },
				                        editor: "number|step=500"
				                    }
				                },
				                filterMinSpy: {
				                    label: "<img src='graphic/unit/unit_spy.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.spy; },
				                        setter: function(value) { user_data.command.filterMin.spy = value; },
				                        editor: "number|step=100"
				                    }
				                },
				                filterMinLight: {
				                    label: "<img src='graphic/unit/unit_light.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.light; },
				                        setter: function(value) { user_data.command.filterMin.light = value; },
				                        editor: "number|step=100"
				                    }
				                },
				                filterMinMarcher: {
				                    label: "<img src='graphic/unit/unit_marcher.png' />",
				                    show: world_config.hasArchers,
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.marcher; },
				                        setter: function(value) { user_data.command.filterMin.marcher = value; },
				                        editor: "number|step=100"
				                    }
				                },
				                filterMinHeavy: {
				                    label: "<img src='graphic/unit/unit_heavy.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.heavy; },
				                        setter: function(value) { user_data.command.filterMin.heavy = value; },
				                        editor: "number|step=100"
				                    }
				                },
				                filterMinRam: {
				                    label: "<img src='graphic/unit/unit_ram.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.ram; },
				                        setter: function(value) { user_data.command.filterMin.ram = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                filterMinCatapult: {
				                    label: "<img src='graphic/unit/unit_catapult.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.catapult; },
				                        setter: function(value) { user_data.command.filterMin.catapult = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                filterMinSnob: {
				                    label: "<img src='graphic/unit/unit_snob.png' />",
				                    propUI: {
				                        getter: function() { return user_data.command.filterMin.snob; },
				                        setter: function(value) { user_data.command.filterMin.snob = value; },
				                        editor: "number"
				                    }
				                },
				                filterMinOther: {
				                    label: sangu_trans.overviews.command.filterMinOther,
				                    propUI: {
				                        getter: function() { return user_data.command.filterMinOther; },
				                        setter: function(value) { user_data.command.filterMinOther = value; },
				                        editor: "number|step=500"
				                    }
				                },
				                restackTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.overviews.troopsRestack.title
				                },
				                troopsRestackTo: {
				                    label: sangu_trans.overviews.troopsRestack.to,
				                    propUI: {
				                        getter: function() { return user_data.restack.to; },
				                        setter: function(value) { user_data.restack.to = value; },
				                        editor: "number|step=1000"
				                    }
				                },
				                requiredDifference: {
				                    label: sangu_trans.overviews.troopsRestack.requiredDifference,
				                    propUI: {
				                        getter: function() { return user_data.restack.requiredDifference; },
				                        setter: function(value) { user_data.restack.requiredDifference = value; },
				                        editor: "number|step=500"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "overviewsCommands",
				            title: sangu_trans.overviews.commands.title,
				            save: sangu_saver,
				            properties: {
				                sumRow: {
				                    label: sangu_trans.overviews.commands.sumRow,
				                    propUI: {
				                        getter: function() { return user_data.command.sumRow; },
				                        setter: function(value) { user_data.command.sumRow = value; },
				                        editor: "bool"
				                    }
				                },
				                filterFakeMaxPop: {
				                    label: sangu_trans.overviews.commands.filterFakeMaxPop,
				                    propUI: {
				                        getter: function() { return user_data.command.filterFakeMaxPop; },
				                        setter: function(value) { user_data.command.filterFakeMaxPop = value; },
				                        editor: "number|step=100"
				                    }
				                },
				                requiredTroopAmount: {
				                    label: sangu_trans.overviews.commands.requiredTroopAmount,
				                    propUI: {
				                        getter: function() { return user_data.command.bbCodeExport.requiredTroopAmount; },
				                        setter: function(value) { user_data.command.bbCodeExport.requiredTroopAmount = value; },
				                        editor: "number|step=100"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "overviewsResources",
				            title: sangu_trans.overviews.resources.title,
				            save: sangu_saver,
				            properties: {
				                requiredResDefault: {
				                    label: sangu_trans.overviews.resources.requiredResDefault,
				                    propUI: {
				                        getter: function() { return user_data.resources.requiredResDefault; },
				                        setter: function(value) { user_data.resources.requiredResDefault = value; },
				                        editor: "number|step=10000"
				                    }
				                },
				                requiredMerchants: {
				                    label: sangu_trans.overviews.resources.requiredMerchants,
				                    propUI: {
				                        getter: function() { return user_data.resources.requiredMerchants; },
				                        setter: function(value) { user_data.resources.requiredMerchants = value; },
				                        editor: "number|step=10"
				                    }
				                },
				                filterMerchants: {
				                    label: sangu_trans.overviews.resources.filterMerchants,
				                    propUI: {
				                        getter: function() { return user_data.resources.filterMerchants; },
				                        setter: function(value) { user_data.resources.filterMerchants = value; },
				                        editor: "bool"
				                    }
				                },
				                highlightColor: {
				                    label: sangu_trans.overviews.resources.highlightColor,
				                    propUI: {
				                        getter: function() { return user_data.resources.highlightColor; },
				                        setter: function(value) { user_data.resources.highlightColor = value; },
				                        editor: "color"
				                    }
				                },
				                filterRows: {
				                    label: sangu_trans.overviews.resources.filterRows,
				                    propUI: {
				                        getter: function() { return user_data.resources.filterRows; },
				                        setter: function(value) { user_data.resources.filterRows = value; },
				                        editor: "bool"
				                    }
				                },
				                bbcodeMinimumDiff: {
				                    label: sangu_trans.overviews.resources.bbcodeMinimumDiff,
				                    propUI: {
				                        getter: function() { return user_data.resources.bbcodeMinimumDiff; },
				                        setter: function(value) { user_data.resources.bbcodeMinimumDiff = value; },
				                        editor: "number|step=2000"
				                    }
				                }
				            }
				        });
				    }
				
				    if (showConfigs) {
				        // Buildingsoverview:
				        (function() {
				            var properties = {},
				                i;
				
				            for (i = 0; i < world_data.buildings.length; i++) {
				                (function() {
				                    var captured_index = i,
				                        building_name = world_data.buildings[captured_index],
				                        buildingPrettyfier = function(building) { return "<img src='graphic/buildings/"+building+".png'>"; };
				
				                    properties[building_name+'_min'] = {
				                        label: sangu_trans.overviews.buildings.minLevel.replace("{building}", buildingPrettyfier(building_name)),
				                        propUI: {
				                            getter: function() { return user_data.buildings[building_name][0]; },
				                            setter: function(value) { user_data.buildings[building_name][0] = value; },
				                            editor: "number"
				                        }
				                    };
				
				                    properties[building_name+'_max'] = {
				                        label: sangu_trans.overviews.buildings.maxLevel.replace("{building}", buildingPrettyfier(building_name)),
				                        propUI: {
				                            getter: function() { return user_data.buildings[building_name][1]; },
				                            setter: function(value) { user_data.buildings[building_name][1] = value; },
				                            editor: "number"
				                        }
				                    };
				                })();
				            }
				
				            user_data_configs.push({
				                id: "overviewsBuildings",
				                title: sangu_trans.overviews.buildings.title,
				                save: sangu_saver,
				                properties: properties
				            });
				        }());
				    }
				
				    if (showConfigs) {
				        // Incomingsoverview:
				        (function() {
				            var properties = {},
				                i;
				
				            properties.attackIdTitle = {
				                type: "subtitle",
				                    label: sangu_trans.overviews.incomings.attackIdTitle
				            };
				
				            for (i = 0; i < user_data.incomings.attackIdDescriptions.length; i++) {
				                (function() {
				                    var captured_index = i;
				
				                    properties['incomings_attackIdDesc'+captured_index+'_title'] = {
				                        type: "subtitle",
				                            label: sangu_trans.overviews.incomings.seperatorTitle.replace("{minValue}", user_data.incomings.attackIdDescriptions[captured_index].minValue)
				                    };
				
				                    properties['incomings_attackIdDesc'+captured_index+'_minValue'] = {
				                        label: sangu_trans.overviews.incomings.minValue,
				                        tooltip: captured_index == 0 ? sangu_trans.overviews.incomings.minValueTooltip : undefined,
				                        propUI: {
				                            getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].minValue; },
				                            setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].minValue = value; },
				                            editor: "number"
				                        }
				                    };
				
				                    properties['incomings_attackIdDesc'+captured_index+'_text'] = {
				                        label: sangu_trans.overviews.incomings.text,
				                        propUI: {
				                            getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].text; },
				                            setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].text = value; },
				                            editor: "text"
				                        }
				                    };
				                })();
				            }
				
				            properties['incomings_attackIdDescMaxText'] = {
				                label: sangu_trans.overviews.incomings.attackIdHigherDescription,
				                propUI: {
				                    getter: function() { return user_data.incomings.attackIdHigherDescription; },
				                    setter: function(value) { user_data.incomings.attackIdHigherDescription = value; },
				                    editor: "text"
				                }
				            };
				
				            user_data_configs.push({
				                id: "overviewsIncomings",
				                title: sangu_trans.overviews.incomings.title,
				                save: sangu_saver,
				                properties: properties
				            });
				        }());
				    }
				
				    if (showConfigs) {
				        user_data_configs.push({
				            id: "other",
				            title: sangu_trans.other.title,
				            save: sangu_saver,
				            properties: {
				                fancyImages: {
				                    label: sangu_trans.overviews.addFancyImagesToOverviewLinks,
				                    propUI: {
				                        getter: function() { return user_data.overviews.addFancyImagesToOverviewLinks; },
				                        setter: function(value) { user_data.overviews.addFancyImagesToOverviewLinks = value; },
				                        editor: "bool"
				                    }
				                },
				                proStyle: {
				                    tooltip: sangu_trans.other.proStyleTooltip,
				                    label: sangu_trans.other.proStyle,
				                    propUI: {
				                        getter: function() { return user_data.proStyle; },
				                        setter: function(value) { user_data.proStyle = value; },
				                        editor: "bool"
				                    }
				                },
				                calculateSnob: {
				                    label: sangu_trans.other.calculateSnob,
				                    show: !world_config.coins,
				                    propUI: {
				                        getter: function() { return user_data.other.calculateSnob; },
				                        setter: function(value) { user_data.other.calculateSnob = value; },
				                        editor: "bool"
				                    }
				                },
				                showPlayerProfileOnVillage: {
				                    label: sangu_trans.other.showPlayerProfileOnVillage,
				                    propUI: {
				                        getter: function() { return user_data.showPlayerProfileOnVillage; },
				                        setter: function(value) { user_data.showPlayerProfileOnVillage = value; },
				                        editor: "bool"
				                    }
				                },
				                overviewAjaxSeperateSupport: {
				                    label: sangu_trans.other.ajaxSeperateSupport,
				                    show: server_settings.ajaxAllowed,
				                    propUI: {
				                        getter: function() { return user_data.overview.ajaxSeperateSupport; },
				                        setter: function(value) { user_data.overview.ajaxSeperateSupport = value; },
				                        editor: "bool"
				                    }
				                },
				                canHideDiv: {
				                    label: sangu_trans.other.canHideDiv,
				                    propUI: {
				                        getter: function() { return user_data.overview.canHideDiv; },
				                        setter: function(value) { user_data.overview.canHideDiv = value; },
				                        editor: "bool"
				                    }
				                },
				                timeDisplayTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.other.timeDisplayTitle
				                },
				                walkingTimeDisplay: {
				                    label: sangu_trans.other.walkingTimeDisplay,
				                    tooltip: sangu_trans.other.walkingTimeDisplayTooltip,
				                    propUI: {
				                        getter: function() { return user_data.walkingTimeDisplay; },
				                        setter: function(value) { user_data.walkingTimeDisplay = value; },
				                        editor: "text"
				                    }
				                },
				                displayDays: {
				                    label: sangu_trans.other.displayDays,
				                    tooltip: sangu_trans.other.displayDaysTooltip,
				                    propUI: {
				                        getter: function() { return user_data.displayDays; },
				                        setter: function(value) { user_data.displayDays = value; },
				                        editor: "bool"
				                    }
				                },
				                commandRenamerTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.other.commandRenamer
				                },
				                commandRenamerActive: {
				                    label: sangu_trans.other.commandRenamerActive,
				                    propUI: {
				                        getter: function() { return user_data.attackAutoRename.active; },
				                        setter: function(value) { user_data.attackAutoRename.active = value; },
				                        editor: "bool"
				                    }
				                },
				                commandRenamerAddHaul: {
				                    label: sangu_trans.other.commandRenamerAddHaul,
				                    propUI: {
				                        getter: function() { return user_data.attackAutoRename.addHaul; },
				                        setter: function(value) { user_data.attackAutoRename.addHaul = value; },
				                        editor: "bool"
				                    }
				                },
				                farmLimitTitle: {
				                    type: "subtitle",
				                    label: sangu_trans.other.farmLimitTitle
				                },
				                farmLimitColors: {
				                    label: sangu_trans.other.farmLimitStackColors,
				                    propUI: {
				                        getter: function(propIndex) {
				                            return user_data.farmLimit.stackColors;
				                        },
				                        setter: function(value, propIndex) { user_data.farmLimit.stackColors = value; },
				                        editor: "array|addNew:color|delete"
				                    }
				                },
				                farmLimitAcceptableOverstack: {
				                    label: sangu_trans.other.farmLimitAcceptableOverstack,
				                    tooltip: sangu_trans.other.farmLimitAcceptableOverstackTooltip.replace("{farmlimit}", 30 * world_config.farmLimit),
				                    show: world_config.farmLimit,
				                    propUI: {
				                        getter: function() { return user_data.farmLimit.acceptableOverstack; },
				                        setter: function(value) { user_data.farmLimit.acceptableOverstack = value; },
				                        editor: "array|addNew:float|delete|step=0.01"
				                    }
				                },
				                farmLimitUnlimitedStack: {
				                    label: sangu_trans.other.farmLimitUnlimitedStack,
				                    show: !world_config.farmLimit,
				                    propUI: {
				                        getter: function() { return user_data.farmLimit.unlimitedStack; },
				                        setter: function(value) { user_data.farmLimit.unlimitedStack = value; },
				                        editor: "array|addNew:number|delete|step=1000"
				                    }
				                }
				            }
				        });
				    }
				
				
				
				
				    if (showConfigs) {
				        // Extra links on village info to troop overview
				        (function() {
				            var properties = {},
				                i;
				
				            function addSetting(properties, index, offDef, propName, label, editor, tooltip) {
				                properties['infoPage_extra_link'+index+'_'+offDef+propName] = {
				                    label: label,
				                    tooltip: tooltip,
				                    propUI: {
				                        getter: function() { return user_data.villageInfo4[index][offDef][propName]; },
				                        setter: function(value) { user_data.villageInfo4[index][offDef][propName] = value; },
				                        editor: editor
				                    }
				                };
				            }
				
				            // hehe
				            function addSetting2(properties, index, offDef, propName, label, editor, tooltip) {
				                properties['infoPage_extra_link'+index+'_'+offDef+propName] = {
				                    label: label,
				                    tooltip: tooltip,
				                    propUI: {
				                        getter: function() { return user_data.villageInfo4[index][offDef].filter[propName]; },
				                        setter: function(value) { user_data.villageInfo4[index][offDef].filter[propName] = value; },
				                        editor: editor
				                    }
				                };
				            }
				
				            function add2Links(captured_index, offDef) {
				                addSetting(properties, captured_index, offDef+"_link", "name", sangu_trans.villageInfo.linkName, "text");
				                addSetting(properties, captured_index, offDef+"_link", "icon", sangu_trans.villageInfo.icon, "text");
				                addSetting(properties, captured_index, offDef+"_link", "sort", sangu_trans.villageInfo.sort, "bool");
				                addSetting(properties, captured_index, offDef+"_link", "changeSpeed", sangu_trans.villageInfo.changeSpeed, "unit");
				                addSetting(properties, captured_index, offDef+"_link", "group", sangu_trans.villageInfo.group, "number", sangu_trans.villageInfo.groupTitle);
				
				                properties['incomings_attackIdDesc'+captured_index+offDef+'_FilterTitle'] = {
				                    type: "subtitle",
				                    label: sangu_trans.villageInfo.filter.title
				                };
				
				                addSetting2(properties, captured_index, offDef+"_link", "active", sangu_trans.villageInfo.filter.title, "bool");
				                addSetting2(properties, captured_index, offDef+"_link", "unit", sangu_trans.villageInfo.filter.unit, "unit");
				                addSetting2(properties, captured_index, offDef+"_link", "amount", sangu_trans.villageInfo.filter.amount, "number|step=100");
				            }
				
				            for (i = 0; i < user_data.villageInfo4.length; i++) {
				                (function() {
				                    var captured_index = i;
				
				                    properties['incomings_attackIdDesc'+captured_index+'_title'] = {
				                        type: "subtitle",
				                        label: sangu_trans.villageInfo.title2 + " " + (captured_index + 1)
				                    };
				
				                    properties['infoPage_extra_link'+captured_index+'_activate'] = {
				                        label: sangu_trans.global.resources.activate,
				                        propUI: {
				                            getter: function() { return user_data.villageInfo4[captured_index].active; },
				                            setter: function(value) { user_data.villageInfo4[captured_index].active = value; },
				                            editor: "bool"
				                        }
				                    };
				
				                    properties['incomings_attackIdDesc'+captured_index+"off"+'_title'] = {
				                        type: "subtitle",
				                        label: sangu_trans.villageInfo.off_title
				                    };
				                    add2Links(captured_index, "off");
				
				                    properties['incomings_attackIdDesc'+captured_index+"def"+'_title'] = {
				                        type: "subtitle",
				                        label: sangu_trans.villageInfo.def_title
				                    };
				                    add2Links(captured_index, "def");
				
				                })();
				            }
				
				            user_data_configs.push({
				                id: "villageInfoLinks",
				                title: sangu_trans.villageInfo.title,
				                save: sangu_saver,
				                properties: properties
				            });
				        }());
				    }
				
				    return user_data_configs;
				}());
				(function() {
				    // contentPage is the place we will add the settings menu to
				    var contentPage = $("table:first td:last", content_value).attr("width", "99%"),
				        sanguTitle = "<h3 id='sanguConfigTitle'>" + trans.sp.sp.configuration.replace("{version}", sangu_version) + "</h3>";
				
				    function gimmeTheMoney() {
				        function createButton(paypalCode, euroAmount, tooltip) {
				            return '<div align="center">'
				                + '<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">'
				                + '<input type="hidden" name="cmd" value="_s-xclick">'
				                + '<input type="hidden" name="hosted_button_id" value="' + paypalCode + '">'
				                + '<input type="image" src="https://www.paypalobjects.com/nl_NL/BE/i/btn/btn_donate_SM.gif" border="0" name="submit" title="'+tooltip+'">'
				                + '<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">'
				                + '<br>' + trans.sp.sp.donate.buttonAmount.replace("{amount}", euroAmount)
				                + '</form></div>';
				        }
				
				        var html = "<h3>Contributors</h3>";
				        html += "Hebben aan het Sangu Package meegewerkt: <br><b>";
        html += "De Goede Fee, Tjeerdo, cgrain, Hardcode93";
				        html += "</b>";
				
				        html += "<h3>"+trans.sp.sp.donate.title+"</h3>";
				        html += trans.sp.sp.donate.whyWouldI;
				        html += "<br>" + trans.sp.sp.donate.books
				            .replace("{abegin}", "<a target='_blank' href='http://www.amazon.com/wishlist/1RFQ21NSF4PAI/ref=cm_wl_prev_ret?_encoding=UTF8&reveal='>")
				            .replace("{aend}", "</a>");
				
				        html += "<br><br>"
				            + "<table width='100%'><tr>"
				            + "<td>" + createButton("FA9MAMFAYKANL", 5, trans.sp.sp.donate.beer) + "</td>"
				            + "<td>" + createButton("R9RX6XBCV6T4G", 10, trans.sp.sp.donate.food) + "</td>"
				            + "<td>" + createButton("ELG8Y2GLSXAVA", 20, trans.sp.sp.donate.yaye) + "</td>"
				            + "</tr>"
				            + "</table>";
				
				        return html;
				    }
				
				    // Reset sangu settings links
				    var resetForm = "<a href='#' id='resetSettings'>&raquo; " + trans.sp.sp.settings.reset + "</a>";
				    resetForm += "<br>";
				    resetForm += "<a href='#' id='resetAllSettings'>&raquo; " + trans.sp.sp.settings.resetAll + "</a>";
				
				    // skeleton injection
				    contentPage.html(sanguTitle + "<div id='sanguSettingsForm'>" + resetForm + gimmeTheMoney() + "</div>");
				
				    gimmeTheMoney();
				    $("#sanguSettingsForm").append("<br><br>");
				
				    $("#resetSettings").click(function() {
				        if (confirm(trans.sp.sp.settings.reset)) {
				            pers.set('sangusettings', '');
				            location.reload(false);
				        }
				        return false;
				    });
				
				    $("#resetAllSettings").click(function() {
				        if (confirm(trans.sp.sp.settings.resetAll)) {
				            pers.clear();
				            location.reload(false);
				        }
				        return false;
				    });
				
				    (function() {
				        var sanguSettingsForm,
				            configIterator,
				            settingFormTogglerHtml,
				            settingsFormsOpenFromPersistence,
				            adornButton = function(button) { $(button).css("background-color", user_data.colors.error); };
				
				        sanguSettingsForm = $("#sanguSettingsForm");
				
				        settingFormTogglerHtml = "<h3>" + trans.sp.sp.settings.configuration + "</h3>";
				        settingFormTogglerHtml +=
				            "<table class='vis' width='100%'><tr class='row_a'><th>"
				                + trans.sp.sp.settings.configurationFormTogglerTooltip
				                + "</th></tr><tr class='row_b'><td>";
				        for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) {
				            settingFormTogglerHtml +=
				                "<input type='button' value=\""
				                    + user_data_configs[configIterator].title
				                    + "\" id='"+user_data_configs[configIterator].id
				                    + "_button' class='editFormToggler' /> &nbsp;";
				        }
				        settingFormTogglerHtml += "</td></tr></table><br>";
				        sanguSettingsForm.append(settingFormTogglerHtml);
				        $(".editFormToggler", sanguSettingsForm).click(function() {
				            var openForms = "",
				                linkedDiv = $("#" + this.id.replace("_button", ""));
				
				            if (linkedDiv.is(":visible")) {
				                linkedDiv.hide();
				                $(this).css("background-color", "");
				            } else {
				                linkedDiv.fadeIn();
				                adornButton(this);
				            }
				
				            $(".propertyEditFormContainer", sanguSettingsForm).each(function() {
				                if ($(this).is(":visible")) {
				                    openForms += this.id + "|";
				                }
				            });
				            pers.set("settingsFormsOpen", openForms);
				        });
				
				        // build the property handler editting form
				        for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) {
				            buildConfigForm(sanguSettingsForm, user_data_configs[configIterator]);
				        }
				
				        settingsFormsOpenFromPersistence = pers.get("settingsFormsOpen");
				        $(".propertyEditFormContainer", sanguSettingsForm).each(function() {
				            if (settingsFormsOpenFromPersistence.indexOf(this.id+"|") > -1) {
				                adornButton($("#" + this.id + "_button"));
				                $(this).show();
				            }
				        });
				        
				        $('input[id*="mainTagger_otherButtonHitKey"]').on('keydown', function(e){
				            e.preventDefault();
				            e.stopPropagation();
				            var TagNumber = $(this).attr("id").match(/\d+/);
				            $(this).val('');
				            $(this).val(keyCodeMap[e.which].toUpperCase());
				            user_data.mainTagger2.otherDescs[TagNumber]["hitKey"] = $(this).val();
				            pers.set('sangusettings', JSON.stringify(user_data));
				            trackEvent("ScriptUsage", "SettingEdit", "1");
				        })
				        
				    })();
				
				    // notable contributors
				    (function() {
				        var notableHtml = "<u>" + trans.sp.sp.donate.notable + "</u>";
				        notableHtml += "<br><br><b>sakeb</b>: Nogmaals bedankt voor 'JavaScript: The Good Parts'! :)";
				        notableHtml += "<br><b>Daniel Ivanov</b>";
				        notableHtml += "<br><br>";
				
				        $("#sanguSettingsForm").append(notableHtml);
				    })();
				})();
                }
                break;

            case "place":
                /**
                 * {spVillage} The current village
                 */
                var vilHome = getVillageFromCoords(game_data.village.coord);
                if ($("#attack_name").size() > 0) {
                    // RALLYPOINT CONFIRM
			(function() {
			    //console.time("confirm");
			    try {
			        // reorder the page
			        if (user_data.proStyle) {
			            $("table:first", content_value).css("width", 500);
			
			            // Merge nightbonus & tribe claim statements (for OK button placement)
			            if (user_data.proStyle && (user_data.confirm.replaceTribeClaim || user_data.confirm.replaceNightBonus)) {
			                var header = $("h2:first", content_value);
			                var claim = $("h3.error:visible");
			                if (claim.size() != 0) {
			                    claim.each(function() {
			                        var $this = $(this);
			                        $this.hide();
			                        header.addClass("error").text(header.text() + " - " + $this.text());
			                    });
			                }
			            }
			        }
			
			        // extra attack button (always on the same place)
			        if (user_data.confirm.addExtraOkButton) {
			            $("h2:first", content_value).prepend("<input type=submit style='font-size: 10pt' id=focusPlaceHolder value='" + $("#troop_confirm_go").val() + "'><br>");
			            $("#focusPlaceHolder").click(function () {
			                $(this).attr("disabled", "disabled");
			                $("#troop_confirm_go").click();
			            });
			        }
			
			        // Catapult building images
			        if (user_data.confirm.addCatapultImages && $("#save_default_attack_building").length == 1) {
			            var dropdown = $("select[name='building']");
			            var buildingImages = "";
			
			            dropdown.find("option").each(function(index, value) {
			                buildingImages += "<img class='catapultSwitcher' title='" + trans.sp.command.catapultImageTitle + "' building='" + $(value).val() +"' src='https://www.tribalwars.vodka/graphic/buildings/" + $(value).val() + ".png'> ";
			            });
			
			            dropdown.parent().parent().before("<tr><td colspan=4>"+buildingImages+"</td></tr>");
			            $("img.catapultSwitcher").click(function() {
			                dropdown.val($(this).attr("building"));
			            });
			        }
			
			        var valueCells = $("table.vis:first td:odd", content_value);
			        var targetVillage = valueCells.first().text();
			
			        // remember last attack
			        // saved at the confirmation page so that we can't save
			        // invalid coordinates
			        var village = getVillageFromCoords(targetVillage);
			        if (village.isValid) {
			            pers.set("lastVil", village.coord);
			        }
			
			        var isAttack = $("input[name='attack']").val() == "true";
			        var isBarbarian = valueCells.eq(1).has("a").length === 0;
			        var player = (isBarbarian ? '' : valueCells.eq(1).text());
			
			        var unitsSent = {};
			        $.each(world_data.units, function (i, val) {
			            unitsSent[val] = parseInt($("input[name='" + val + "']", content_value).val(), 10);
			        });
			
			        // compare runtime with dodgetime
			        var unitsCalc = calcTroops(unitsSent);
			        var dodgeCookie = pers.getCookie("sanguDodge" + getQueryStringParam("village"));
			        if (dodgeCookie) {
			            dodgeCookie = dodgeCookie.split("~");
			            var durationCell = $("table.vis:first td:contains('" + trans.tw.command.walkingTimeTitle + "')", content_value).next();
			            var attackRunTime = getTimeFromTW(durationCell.text());
			            var dodgeTime = getTimeFromTW(dodgeCookie[1]);
			
			            var runtimeIsOk = attackRunTime.totalSecs >= dodgeTime.totalSecs;
			            var diffSecs = (attackRunTime.totalSecs - dodgeTime.totalSecs);
			
			            var dodgeCellText = "<table border=0 cellpadding=0 cellspacing=0 width='1%'><tr>";
			            dodgeCellText += "<td width='25%' align=center>" + durationCell.text() + "</td>";
			            dodgeCellText += "<td width='50%' align=center><b>" + (runtimeIsOk ? "&gt;&gt;&gt;" : "&lt;&lt;&lt;") + "</b></td>";
			            dodgeCellText += "<td width='25%' align=center nowrap>" + dodgeCookie[1] + "&nbsp;";
			            if (diffSecs > 0) {
			                dodgeCellText += trans.sp.command.dodgeMinuteReturn.replace("{minutes}", prettyDate(diffSecs * 2000, true)); // 2000 = Method expects milliseconds and distance is walked 2 times!
			            }
			            dodgeCellText += "</td>";
			
			            dodgeCellText += "</tr></table>";
			            durationCell.html(dodgeCellText);
			
			            if (!runtimeIsOk) {
			                durationCell.find("table").attr("title", trans.sp.command.dodgeNotFarEnough).css("background-color", user_data.colors.error).find("td").css("background-color", user_data.colors.error);
			            }
			
			            if (dodgeCookie[0] != "unit_" + unitsCalc.getSlowest()) {
			                $("h2:first", content_value).css("background-color", user_data.colors.error);
			            }
			        } else {
			            // If a dodgecookie is in use, nightbonus etc isn't relevant
			            unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), isAttack);
			            var arrivalTime = getDateFromTodayTomorrowTW($.trim($("#date_arrival").text()));
			            if (user_data.proStyle && user_data.confirm.replaceNightBonus && isDateInNightBonus(arrivalTime)) {
			                $("#date_arrival").css("background-color", user_data.colors.error).css("font-weight", "bold");
			            }
			        }
			
			        if (user_data.attackAutoRename.active) {
			            // rename attack command
			            // cookie reading code in place.js
			            var villageCoord = $("input[name='x']", content_value).val() + '|' + $("input[name='y']", content_value).val();
			            var sent = buildAttackString(villageCoord, unitsSent, player, !isAttack);
			            document.title = game_data.village.coord + " -> " + sent;
			
			            var twInitialCommandName = (isAttack ? trans.tw.command.attackOn : trans.tw.command.supportFor) + targetVillage;
			            pers.setSession("attRen_" + game_data.village.id + '_' + twInitialCommandName, sent);
			        }
			    } catch (e) { handleException(e, "place-confirm"); }
			    //console.timeEnd("confirm");
			}());
                }
                // RALLYPOINT UNITS THERE
                else if (current_page.mode === 'units' && location.href.indexOf('try=back') == -1) {
			(function() {
			    //console.time("units_back");
			    try {
			        var units_awayTable = $("#units_away").width("100%");
			        if (units_awayTable.size() != 0) {
			            // Troops in other villages
			            $("tr:first", units_awayTable).append(
			                "<th>" + trans.sp.place.distance + "</th>"
			                    + "<th>" + trans.sp.place.backOn + "</th>");
			
			            units_awayTable.find("tr:gt(0):even").each(function() {
			                var row = $(this),
			                    villageCoord = getVillageFromCoords(row.find("td:eq(1)").text());
			
			                if (!villageCoord.isValid) {
			                    row.append("<th>&nbsp;</th><th>&nbsp;</th>");
			                } else {
			                    var slowestUnit = null;
			                    var slowestUnitName = null;
			                    $.each(world_data.units, function (i, val) {
			                        var amount = $("td:eq(" + (i + 2) + "), th:eq(" + (i + 1) + ")", row).text();
			                        if (amount != '0') {
			                            if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) {
			                                slowestUnitName = val;
			                                slowestUnit = world_data.unitsSpeed['unit_' + val];
			                            }
			                        }
			                    });
			
			                    var fields = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName);
			                    var extraColumns = "<td align=right>" + parseInt(fields.fields, 10) + "</td>";
			                    extraColumns += "<td>" + twDateFormat(fields.arrivalTime) + "</td>";
			
			                    row.append(extraColumns);
			                }
			            });
			        }
			
			        // Calculate distance and walkingtime to the villages
			        var unitsTable = $("form table:first");
			        $("tr:first", unitsTable).append('<th width="50"><span class="icon header population" title="' + trans.sp.all.population + '"></span></th><th>' + trans.sp.place.distance + '</th><th>' + trans.sp.place.backOn + '</th>');
			        unitsTable.find("tr:gt(0)").each(function () {
			            var pop = 0;
			            var row = $(this);
			            var slowestUnit = null;
			            var slowestUnitName = null;
			
			            $.each(world_data.units, function (i, val) {
			                var amount = parseInt($("td:eq(" + (i + 1) + "), th:eq(" + (i + 1) + ")", row).text(), 10);
			                if (amount !== 0) {
			                    pop += amount * world_data.unitsPositionSize[i];
			
			                    if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) {
			                        slowestUnitName = val;
			                        slowestUnit = world_data.unitsSpeed['unit_' + val];
			                    }
			                }
			            });
			
			            var villageCoord = getVillageFromCoords(row.find("td:first").text());
			            var color = getStackColor(pop);
			
			            if (color !== "") {
			                $(this).append("<td align=right style='background-color: " + color + "'>" + formatNumber(pop) + "</td><td colspan=2>&nbsp;</td>");
			            } else {
			                var extraColumns = '<td align=right>' + formatNumber(pop) + '</td>';
			                if (!villageCoord.isValid) {
			                    extraColumns += "<td colspan=2 align=right>&nbsp;</td>";
			                } else {
			                    //q(vilHome.x + ':' + slowestUnitName);
			                    var dist = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName),
			                        fields = parseInt(dist.fields, 10);
			
			                    extraColumns += "<td align=right>" + fields + "</td><td>" + twDateFormat(dist.arrivalTime) + "</td>";
			                    $("td:first", this).append("&nbsp; <b>" + trans.sp.all.fieldsSuffix.replace("{0}", fields) + "</b>");
			                    $(this).addClass("toSort").attr("fields", fields);
			                }
			                $(this).append(extraColumns);
			            }
			        });
			
			        var checkboxAmount = $("input[type='checkbox']", unitsTable);
			        if (checkboxAmount.size() == 1) {
			            // village has just been taken over? auto check checkbox
			            checkboxAmount.attr("checked", true);
			        }
			
			        // Sort on distance
			        unitsTable.find("tr.toSort").sortElements(function (a, b) {
			            return parseInt($(a).attr("fields"), 10) < parseInt($(b).attr("fields"), 10) ? 1 : -1;
			        });
			
			        // are there incomings on the supporting villages?
			        if (server_settings.ajaxAllowed) {
			            unitsTable.find("tr.toSort").each(function() {
			                var row = $(this);
			                var villageUrl = $("a:first", this).attr("href");
			                ajax(villageUrl, function (villageDetails) {
			                    var villageOwner = $("table.vis:first tr:eq(4) a", villageDetails);
			                    if (villageOwner.text() != game_data.player.name) {
			                        $("td:first a", row).after(" [" + villageOwner.outerHTML() + "]");
			                    } else {
			                        var incomingTable = $("table th:contains('" + trans.tw.overview.incomingTroops + "')", villageDetails);
			                        if (incomingTable.size() > 0) {
			                            incomingTable = incomingTable.parent().parent();
			                            var incomingRows = $("tr:has(img[src*='attack'])", incomingTable);
			                            if (incomingRows.size() > 0) {
			                                var firstAttack = incomingRows.eq(0);
			                                var timeLeft = $("td:eq(2)", firstAttack).text();
			                                var arrivalDate = $("td:eq(1)", firstAttack).text();
			
			                                var lastAttack = incomingRows.last();
			                                var timeLeftLast = $("td:eq(2)", lastAttack).text();
			                                var arrivalDateLast = $("td:eq(1)", lastAttack).text();
			
			                                var amount = incomingRows.size();
			
			                                var attacksDesc;
			                                if (amount == 1) {
			                                    attacksDesc = trans.sp.place.onlyAttack
			                                    .replace("{timeLeftFirst}", timeLeft)
			                                    .replace("{arrivalDateFirst}", arrivalDate);
			                                } else {
			                                    attacksDesc = trans.sp.place.multipleAttack
			                                    .replace("{timeLeftFirst}", timeLeft)
			                                    .replace("{arrivalDateFirst}", arrivalDate)
			                                    .replace("{timeLeftLast}", timeLeftLast)
			                                    .replace("{arrivalDateLast}", arrivalDateLast)
			                                    .replace("{amount}", amount);
			                                }
			
			                                $("td:first input", row).after("&nbsp; <img src='graphic/command/attack.png' title='" + attacksDesc + "'>");
			                            }
			                        }
			                    }
			                });
			            });
			        }
			    } catch (e) { handleException(e, "place-units_back"); }
			    //console.timeEnd("units_back");
			}());
                }
                // RALLY POINT (DEFAULT)
                else {
			(function() {
			    //console.time("place-place");
			    try {
			    // Auto rename attacks
			    if (user_data.attackAutoRename.active) {
			        // Less than ideal solution:
			        // Does not work properly when sending many attacks (ie snobtrain)
			        // In confirm.js the cookies are saved
			
			        var hasAttackRenamingCookieNeedle = pers.getWorldKey('attRen_' + game_data.village.id + '_');
			        for (var i = 0; i  <  sessionStorage.length; i++) {
			            var key = sessionStorage.key(i);
			            if (key.indexOf(hasAttackRenamingCookieNeedle) == 0) {
			                var twInitialCommandName = key.substr(hasAttackRenamingCookieNeedle.length);
			                //q("found:" + hasAttackRenamingCookieNeedle + " -> " + twInitialCommandName);
			
			                // ' is an invalid village name character so we don't need to escape
			                var commandLabel = $('.quickedit-label:contains("' + twInitialCommandName + '")');
			                if (commandLabel.length > 0 && server_settings.ajaxAllowed) {
			                    var sanguCommandName = sessionStorage.getItem(key);
			
			                    // Open the rename command form:
			                    commandLabel.parent().next().click();
			
			                    // Fill in new command name and click rename button
			                    var commandWrapper = commandLabel.parent().parent().parent(),
			                        commandForm = commandWrapper.find(".quickedit-edit");
			
			                    commandForm.find("input:first").val(sanguCommandName);
			                    commandForm.find("input:last").click();
			
			                    pers.removeSessionItem(key);
			
			                    if (commandLabel.closest("table").find("tr").length > 2) {
			                        commandLabel.closest("td").addClass("selected");
			                    }
			                }
			            }
			        }
			    }
			
			    $("#inputx,#inputy").focus(function() {
			        $(this).select();
			    });
			
			    // fill in coordinates? (links from troops overview page)
			    if (server_settings.autoFillCoordinatesAllowed && window.location.search.indexOf("&sanguX=") != -1) {
			        var match = window.location.search.match(/sanguX=(\d+)&sanguY=(\d+)/);
			        if (typeof match[1] !== "undefined") {
			            $("#inputx").val(match[1]);
			            $("#inputy").val(match[2]);
			        }
			    }
			
			    // Spice up rally point:
			    var speedCookie = spSpeedCookie();
			
(function() {
    try {

        // Show current selected speed + ability to change active speed
        $(".unit_link img", content_value).each(function() {
            $(this).attr("title", trans.sp.place.changeSpeedImageTooltips.replace("{originalTitle}", $(this).attr("title")));
        });

        $("#command-data-form a img").click(function () {
            var unit = this.src;
            unit = unit.substr(unit.lastIndexOf('/') + 1);
            unit = unit.substr(0, unit.lastIndexOf('.'));
            speedCookie = spSpeedCookie(unit);
            $("#command-data-form a img").css("border", "0px").filter("img[src*='" + unit + "']").css("border", "3px red solid");

            // lastvil
            var coord = getVillageFromCoords(pers.get("lastVil"));
            if (coord.isValid) {
                var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
                $("#lastVilTime")[0].innerHTML = dist.html;
            }

            // targetVillage
            coord = getVillageFromCoords(spTargetVillageCookie());
            if (coord.isValid) {
                dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
                $("#targetVilTime")[0].innerHTML = dist.html;
            }

        }).filter("img[src*='" + speedCookie + "']").css("border", "3px red solid");

    } catch (e) { handleException(e, "place-activespeed"); }
}());
(function() {
    try {
        // sangupackage last village
        var cookie = pers.get("lastVil"),
            coord = getVillageFromCoords(cookie),
            dist;

        if (coord.isValid) {
            dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
            var htmlStr = printCoord(coord, "&raquo; " + trans.sp.all.last + ": " + coord.x + "|" + coord.y);
            htmlStr += " &nbsp; <span id=lastVilTime>" + dist.html + "</span>";
            $("#command-data-form").append(htmlStr);
        }

        // Add target village
        var targetVillage = getVillageFromCoords(spTargetVillageCookie());
        if (targetVillage.isValid) {
            dist = getDistance(targetVillage.x, vilHome.x, targetVillage.y, vilHome.y, speedCookie);
            $("#command-data-form").append("<br>" + printCoord(targetVillage, "&raquo; " + trans.sp.all.target + ": " + targetVillage.x + "|" + targetVillage.y) + " &nbsp;<span id=targetVilTime>" + dist.html + "</span>");
        }
    } catch (e) { handleException(e, "place-lastandtargetvillage"); }
}());
(function() {
    try {
        // Read troops available
        var units = [];
        units.total = 0;
        $("#command-data-form .unitsInput").each(function () {
            var amount = $(this).next().text().substr(1);
            units[this.name] = parseInt(amount.replace(")", ""), 10);
            units.total += units[this.name] * world_data.unitsSize['unit_'+this.name];
        });

        // Add extra links next to "All troops"
        function createRallyPointScript(linksContainer, unitLoop, name, min, checkFunction, tag) {
            send = {};
            $.each(unitLoop, function (i, v) {
                if (units[v] >= min) {
                    send[v] = checkFunction(units[v], v, tag);
                }
            });
            linksContainer.append("&nbsp; &nbsp;<a href='#' onclick='" + fillRallyPoint(send) + "; return false'>" + name + "</a>");
        }

        var villageType = calcTroops(units);
        var linksContainer = $('#selectAllUnits').parent().attr("colspan", 4);

        // add fake attack
        var minFake = 0;
        if (world_config.hasMinFakeLimit) {
            minFake = getBuildingPoints();
            minFake *= world_config.minFake;
            if (units.ram > 0) {
                minFake -= world_data.unitsSize['unit_ram'];
            }
        }

        if (user_data.place.attackLinks.fakePlaceLink && units['total'] >= minFake) {
            createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.fakePlaceLinkName, 0, function (amount, v, tag) {
                if ((v == 'ram' || v == 'catapult') && !tag.rammed && amount > 0) {
                    tag.rammed = true;
                    return 1;
                }

                if (v == 'snob' || tag.toSend <= 0 || amount == 0) {
                    return 0;
                }

                if (user_data.place.attackLinks.fakePlaceExcludeTroops.indexOf(v) > -1) {
                    return 0;
                }

                var farmSize = world_data.unitsSize['unit_' + v];
                if (amount * farmSize > tag.toSend) {
                    amount = Math.ceil(tag.toSend / farmSize);
                }
                tag.toSend -= amount * farmSize;
                if (v == 'sword' && amount > 0) {
                    tag.toSend++;
                    amount--;
                }

                return amount;
            }, { toSend: minFake, rammed: false });
        }

        if (units['total'] > 0)
            $.each(user_data.place.customPlaceLinks, function (i, v) {
                if (v.active && villageType.isMatch(v.type)) {
                    // villageType: off, def, all
                    if (v.required == undefined || units[v.required[0]] >= v.required[1]) {
                        // requires certain amount of troops
                        if (v.totalPop == undefined) {
                            // work with absolute numbers
                            createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) {
                                //q(v + ' - SEND:' + tag[v] + '; amount=' + amount + ';');
                                var send = tag[unitVal];
                                if (send != undefined && amount > 0) {
                                    //q("send: " + send + " // amount: " + amount + " // unitVal: " + unitVal);
                                    if (send < 0) {
                                        send = amount + send;
                                        if (send < 0) {
                                            send = 1;
                                        }
                                    }
                                    if ((amount - send) * world_data.unitsSize['unit_' + unitVal] < tag.sendAlong) {
                                        send = amount;
                                    }
                                    if (send > 0 && !tag.ignoreNobles) {
                                        $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
                                            if (unitVal == val.unit && villageType.isMatch(val.villageType)) {
                                                send -= Math.ceil(units.snob * val.amount);
                                            }
                                        });
                                    }
                                    //if (unitVal == 'light') q(send);

                                    if (send > amount) {
                                        return amount;
                                    }
                                    if (send > 0) {
                                        return send;
                                    }
                                }
                                return 0;
                            }, v);

                        } else { // do automatic calculation which division of troops to select
                            ////{ active: true, type: 'def', name: 'HelftZc', totalPop: 10000, divideOver: ['spear', 'heavy'] },
                            // TODO this doesn't yet work, does it?
                            // Probably not active...
                            var totalPop = 0;
                            $.each(v.divideOver, function (i, val) { totalPop += units[val] * world_data.unitsSize['unit_' + val]; });

                            createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) {
                                if ($.inArray(unitVal, tag.divideOver) == -1) {
                                    return 0;
                                }
                                if (totalPop < tag.totalPop) {
                                    return amount;
                                }

                                var currentUnitPercentage = (amount * world_data.unitsSize['unit_' + unitVal]) / totalPop;
                                return Math.floor(amount * currentUnitPercentage);
                            }, v);
                        }
                    }
                }
            });

        if (units.spy >= user_data.place.attackLinks.scoutVillage && user_data.place.attackLinks.scoutPlaceLinks != null && user_data.place.attackLinks.scoutPlaceLinks.length > 0) {
            $.each(user_data.place.attackLinks.scoutPlaceLinks, function (i, v) {
                if (units.spy >= v) {
                    createRallyPointScript(linksContainer, ["spy"], user_data.place.attackLinks.scoutPlaceLinksName.replace("{amount}", v), 0, function (amount, v, tag) {
                        return tag;
                    }, v);
                }
            });
        }

        if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLink) {
            if (user_data.place.attackLinks.noblePlaceLinkFirstName) {
                createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkFirstName, 0, function (amount, v, tag) {
                    if (v == 'snob') {
                        return 1;
                    }
                    if (tag > 0) {
                        var returned = null;
                        $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
                            if (v == val.unit && villageType.isMatch(val.villageType)) {
                                returned = amount - Math.ceil((tag - 1) * val.amount);
                            }
                        });
                        if (returned != null) {
                            return returned;
                        }
                    }
                    return amount;
                }, units.snob);
            }

            if (user_data.place.attackLinks.noblePlaceLinkSupportName && (units.snob > 1 || user_data.place.attackLinks.noblePlaceLinksForceShow)) {
                createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkSupportName, 0, function (amount, v, tag) {
                    if (v == 'snob') {
                        return 1;
                    }
                    var returned = 0;
                    $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
                        if (v == val.unit && villageType.isMatch(val.villageType)) {
                            returned = Math.ceil(1 * val.amount);
                        }
                    });
                    return returned;
                });
            }

            if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLinkDivideName) {
                createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkDivideName, 0, function (amount, v, tag) {
                    if (v == 'snob') {
                        return 1;
                    }
                    if (v == 'catapult') {
                        return 0;
                    }
                    if (v == 'ram' && !user_data.place.attackLinks.noblePlaceLinkDivideAddRam) {
                        return 0;
                    }
                    return Math.floor(amount / units.snob);
                });
            }
        }
    } catch (e) { handleException(e, "place-extratrooplinks"); }
}());
			
			    } catch (e) { handleException(e, "place-place"); }
			    //console.timeEnd("place-place");
			}());
                }
                break;

            case "overview_villages":
                break;
        }

		// USERPROFIEL++ // INFO_ ALLY/PLAYER
        if ((current_page.screen === 'info_ally' || current_page.screen === 'info_player' || current_page.screen === 'info_village')
            || (current_page.screen === "ally" && current_page.mode === "profile")) {

			(function() {
			    try {
			        var tables = $('table.vis', content_value),
			            villageInfoTable = tables.first(),
			            commandsTable = villageInfoTable.next('table'),
			            profile = user_data.profile,
			            i;
			
			        if (game_data.player.premium && location.href.indexOf('screen=info_village') > -1) {
			            // extra links on the village overview page
			            var createFilterLink = function(baseLink, settings) {
			                var link = baseLink + "&group=" + settings.group + "&sort=" + settings.sort + "&changeSpeed=" + settings.changeSpeed;
			
			                if (settings.filter.active) {
			                    link += "&unit=" + settings.filter.unit + "&amount=" + settings.filter.amount;
			                }
			
			                var fancyIcon = settings.icon ? "<img src='" + settings.icon + "'>" : "";
			                return "<a href='" + link + "'>" + fancyIcon + settings.name + "</a>";
			            };
			
			            for (i = 0; i < user_data.villageInfo4.length; i++) {
			                var currentPairInfo = user_data.villageInfo4[i];
			                if (currentPairInfo.active) {
			                    var id = villageInfoTable.find("td:eq(2)").text(),
			                        link = getUrlString(
			                            "&screen=overview_villages&type=own_home&mode=units&page=-1&targetvillage="
			                                + id.substr(id.lastIndexOf("=") + 1));
			
			                    commandsTable.find("tbody:first").append(
			                        "<tr><td>" + createFilterLink(link, currentPairInfo.off_link) + "</td>"
			                            + "<td>" + createFilterLink(link, currentPairInfo.def_link) + "</td><tr>");
			                }
			            }
			        }
			
			        if (user_data.profile.show && (location.href.indexOf('screen=info_village') == -1 || user_data.showPlayerProfileOnVillage)) {
			            var screen;
			            var mapProfile = user_data.profile.mapLink;
			            var isVillage = false;
			            if (current_page.screen !== 'info_ally' && current_page.screen !== "ally") {
			                // player and village info page
			                // Extra links and info in table at the left top
			                screen = "player";
			                if (user_data.proStyle) {
			                    $("td:first", content_value).closest('table').hasClass('modemenu')
			                        ? $(content_value).find('table:has("#villages_list") td:first').css("width", "40%").next().css("width", "60%")
			                        : $("td:first", content_value).css("width", "40%").next().css("width", "60%");
			                }
			
			                if (current_page.screen === 'info_player') {
			                    // player info page
			                    id = commandsTable.find("a[href*='screen=mail']").attr("href");
			                    
			                    if (id == undefined) {
			                        id = game_data.player.id;
			                    } else {
			                        id = id.substr(id.indexOf("&player=") + 8);
			                        //alert(id);
			                        if (id.indexOf("&") > -1) {
			                            id = id.substr(0, id.indexOf("&"));
			                        }
			                    }
			                } else {
			                    // village info page
			                    isVillage = true;
			                    commandsTable = $("table.vis:first", content_value);
			                    id = commandsTable.find("tr:eq(3) a");
			                    //assert(id.size() == 1, "player id not found on info_village page");
			                    if (id.size() > 0) {
			                        id = id.attr("href").match(/id=(\d+)/)[1];
			                        assert(!!id, "player id href is not set");
			                    } else {
			                        id = 0;
			                    }
			                }
			
			                // Direct link to TW Stats map
			                if (id > 0 && profile.mapLink.show) {
			                    var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map";
			                    var tribeId = commandsTable.prev('table').find("td:eq(8) a");
			                    //assert(tribeId.size() == 1, "tribe id not found"); // Not everyone is in a tribe
			                    if (tribeId.size() == 1) {
			                        tribeId = tribeId.attr("href").match(/id=(\d+)/)[1];
			                        assert(!isNaN(tribeId), "tribe id is not a number");
			                    } else tribeId = 0;
			
			                    if (mapProfile.tribeColor != null) {
			                        link += "&tribe_0_id=" + tribeId + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1);
			                    }
			                    if (mapProfile.yourTribeColor != null && game_data.player.ally_id != tribeId && game_data.player.ally_id > 0) {
			                        link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1);
			                    }
			                    link += "&player_0_id=" + id + "&player_0_colour=" + mapProfile.playerColor.substr(1);
			                    link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom + "&centrex=" + mapProfile.centreX + "&centrey=" + mapProfile.centreY;
			                    if (mapProfile.markedOnly) {
			                        link += "&nocache=1";
			                    }
			                    if (mapProfile.bigMarkers) {
			                        link += "&bm=1";
			                    }
			                    if (mapProfile.gridContinentNumbers) {
			                        link += "&kn=1";
			                    }
			                    if (mapProfile.ownColor != null && game_data.player.id != id) {
			                        link += "&player_1_id=" + game_data.player.id + "&player_1_colour=" + mapProfile.ownColor.substr(1);
			                    }
			                    commandsTable.find("tr:last").after("<tr><td colspan=2><a href='" + link + "' target='_blank'>&raquo; " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>");
			                }
			
			                if (!isVillage) {
			                    // Amount of villages
			                    if (user_data.proStyle) {
			                        // always show villagename on one line
			                        var colWidth = $("table:eq(2) th", content_value);
			                        colWidth.first().css("width", "98%");
			                        colWidth.eq(1).css("width", "1%");
			                        colWidth.eq(2).css("width", "1%");
			                    }
			
			                    var amountOfVillages = tables.eq(2).find("th:first").text();
			                    amountOfVillages = amountOfVillages.substr(amountOfVillages.indexOf("(") + 1);
			                    amountOfVillages = amountOfVillages.substr(0, amountOfVillages.length - 1);
			                    commandsTable.prev('table').find("tr:eq(2)").after("<tr><td>" + trans.sp.profile.villages + "</td><td>" + formatNumber(amountOfVillages) + "</td></tr>");
			                }
			            } else {
			                screen = "tribe";
			                if (current_page.screen === 'info_ally') {
			                    commandsTable = tables.eq(0);
			                }
			                id = commandsTable.find("a");
			                id = id.last().attr("href").match(/&id=(\d+)/)[1];
			
			                var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map";
			                link += "&tribe_0_id=" + id + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1);
			                link += "&centrex=" + mapProfile.centreX + "&centrey=" + mapProfile.centreY;
			                if (mapProfile.yourTribeColor != null && game_data.player.ally_id != id) {
			                    link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1);
			                }
			                link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom
			                if (mapProfile.markedOnly) {
			                    link += "&nocache=1";
			                }
			                if (mapProfile.bigMarkers) {
			                    link += "&bm=1";
			                }
			                if (mapProfile.gridContinentNumbers) {
			                    link += "&kn=1";
			                }
			                if (mapProfile.ownColor != null) {
			                    link += "&player_0_id=" + game_data.player.id + "&player_0_colour=" + mapProfile.ownColor.substr(1);
			                }
			                commandsTable.find("tr:last").before("<tr><td colspan=2><a href='" + link + "' target='_blank'>&raquo; " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>");
			            }
			
			            // Build graphs
			            if (id > 0) {
			                var html = "";
			
			                // TWMap graphs
			                var twMapGraphs;
			                if (screen == "tribe") {
			                    twMapGraphs = [["tribe", trans.sp.profile.graphTWMap], ["p_tribe", trans.sp.profile.graphPoints], ["oda_tribe", trans.sp.profile.graphODA], ["odd_tribe", trans.sp.profile.graphODD]];
			                } else {
			                    twMapGraphs = [["player", trans.sp.profile.graphTWMap], ["p_player", trans.sp.profile.graphPoints], ["oda_player", trans.sp.profile.graphODA], ["odd_player", trans.sp.profile.graphODD], ["ods_player", trans.sp.profile.graphODS]];
			                }
			                for (var i = 0; i < twMapGraphs.length; i++) {
			                    var graphDetails = screen == "tribe" ? profile.twMapTribeGraph[twMapGraphs[i][0]] : profile.twMapPlayerGraph[twMapGraphs[i][0]];
			                    if (graphDetails[0]) {
			                        html += createSpoiler(twMapGraphs[i][1], '<img src="http://' + game_data.world + '.tribalwarsmap.com/' + game_data.market + '/graph/' + twMapGraphs[i][0] + '/' + id + '" title="' + trans.sp.profile.graphTWMap + '">', graphDetails[1]);
			                    }
			                }
			
			                // TWStats graphs
			                var graphs = [["points", trans.sp.profile.graphPoints], ["villages", trans.sp.profile.graphVillages], ["od", trans.sp.profile.graphOD], ["oda", trans.sp.profile.graphODA], ["odd", trans.sp.profile.graphODD], ["rank", trans.sp.profile.graphRank]];
			                if (screen == "tribe") {
			                    graphs.push(["members", trans.sp.profile.graphMembers]);
			                }
			                var toShow = screen == "tribe" ? profile.tribeGraph : profile.playerGraph;
			                for (var i = 0; i < graphs.length; i++) {
			                    if (toShow[i][1]) {
			                        var graphType = toShow[i][1] == 'big' ? 'ss' : '';
			                        html += createSpoiler(graphs[i][1], '<img src="https://' + game_data.market + '.twstats.com/image.php?type=' + screen + graphType + 'graph&id=' + id + '&s=' + game_data.world + '&graph=' + graphs[i][0] + '">', toShow[i][2] != undefined);
			                    }
			                }
			
			                // Show graphs
			                if (html.length > 0) {
			                    var pictureTable;
			                    if (screen == 'player' || (isVillage && user_data.showPlayerProfileOnVillage)) {
			                        pictureTable = $(content_value).find('table:has("th:first:contains(Profiel)")'); // TODO: untranslated resource Profiel
			                        if (isVillage || pictureTable.html() == null) {
			                            // With no info nor personal text
			                            pictureTable = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>");
			                            $("td:first", content_value).closest('table').hasClass('modemenu') ? $(content_value).find('table:has("#villages_list") td:first').next().prepend(pictureTable) : $("td:first", content_value).next().prepend(pictureTable);
			                        } else if (pictureTable.find("th").text() != trans.tw.profile.title) {
			                            // TODO: There is a ; after the IF, is that the intention???
			                            if (pictureTable.find("th:first").text() == trans.tw.profile.awardsWon);
			                            pictureTable = pictureTable.parent();
			
			                            // If there is only the node "Personal info"
			                            var temp = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>");
			                            pictureTable.prepend(temp);
			                            pictureTable = temp;
			                        }
			
			                        if (pictureTable.find("td[colspan=2]").size() > 0) {
			                            pictureTable.find("tr:last").before("<tr><td colspan=2>" + html + "</td></tr>");
			                        } else {
			                            pictureTable.find("tr:last").after("<tr><td colspan=2>" + html + "</td></tr>");
			                        }
			                    } else {
			                        commandsTable.after("<table class=vis width='100%'><tr><th>" + trans.tw.profile.title + "</th></tr><tr><td>" + html + "</td></tr></table>");
			                    }
			                }
			            }
			
			            // Conquers (intern)
			            if (id > 0 && profile.popup.show) {
			                var twLink = 'https://' + game_data.market + '.twstats.com/' + game_data.world + '/index.php?page=' + screen + '&mode=conquers&id=' + id + '&pn=1&type=1&enemy=-1&enemyt=-1&min=&max=';
			                var conquers = "<tr><td colspan=2><a href=\"\" id='conquers'>&raquo; " + trans.sp.profile.conquers + "</a> " + trans.sp.profile.internalPage + "</td></tr>";
			                if (screen == 'tribe') {
			                    commandsTable.find("tr:last").before(conquers);
			                } else {
			                    commandsTable.find("tr:last").after(conquers);
			                }
			                var popupWidth = profile.popup.width;
			                var popupHeight = profile.popup.height;
			                commandsTable.after('<div class="messagepop pop" id="popup" style="display: none"><iframe src=' + twLink + ' width=' + popupWidth + ' height=' + popupHeight + '></div>');
			                $("#popup").css({ "left": profile.popup.left, "top": profile.popup.top, "background-color": "#FFFFFF", "border": "1px solid #999999", "position": "absolute", "width": popupWidth, "height": popupHeight, "z-index": 50, "padding": "25px 25px 20px" });
			
			                $(function () {
			                    $("#conquers").on('click', function (event) {
			                        if ($(this).hasClass('selected')) {
			                            $("#conquers").removeClass("selected");
			                        } else {
			                            $(this).addClass("selected");
			                        }
			                        $("#popup").toggle();
			                        return false;
			                    });
			
			                    $("#popup").on('click', function () {
			                        $("#popup").hide();
			                        $("#conquers").removeClass("selected");
			                        return false;
			                    });
			                });
			            }
			        }
			
			        if (current_page.screen === 'info_village' && user_data.proStyle && profile.moveClaim) {
			            // move claim to a position that does not interfere with more important links (2-click behavior)
			            if ($("td:eq(8)", commandsTable).text() == trans.tw.profile.claimedBy) {
			                commandsTable.append($("tr:eq(5),tr:eq(6)", commandsTable));
			            }
			        }
			    } catch (e) { handleException(e, "info_villageplayertribe"); }
			}());
        }
		if (current_page.screen === 'info_village') {
			//Written by hardcode
			(function() {
			    var show = true;
			    var head = $(".vis:contains('Aankomend')", content_value).find("tr:first");
			    var text = $("th:contains('Aankomst:')", content_value).html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">');
			
			    head.on("click", function () {
			        if(show === true) {
			            $(".no_ignored_command").hide();
			            text.html('Verborgen: <img src="https://www.tribalwars.vodka/graphic/plus.png" style=" float: right;">');
			            show = false;
			        }else{
			            $(".no_ignored_command").show();
			            text.html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">');
			            show = true;
			        }
			    });
			}());
		}

		// ALL OVERVIEW PAGES
        if (current_page.screen === 'overview_villages') {
			var overviewTable;
			//tableHandler.overviewTable
			
			var tableHandler;
			(function (tableHandler) {
				function init(id, options) {
					tableHandler.overviewTableName = id;
					tableHandler.overviewTable = $("#" + id);
					tableHandler.settings = {
						hasBottomTotalRow: false
						
					};
					tableHandler.settings = $.extend({}, tableHandler.settings, options || {});
					
					// do stuff on page load
					ajaxLoadNextPageSetup();
				}
				tableHandler.init = init;
				
				function getReplacedVillageRows(page) {
					var overviewTable = typeof page === 'undefined' ? tableHandler.overviewTable : $("#"+tableHandler.overviewTableName, page);
					if (typeof tableHandler.settings.rowReplacer === "function") {
						var newTable = "";
						var villageRows = selectVillageRows(overviewTable);
						villageRows.each(function () {
							var row = $(this);
							newTable += tableHandler.settings.rowReplacer(row);
						});
						return newTable;
					} else {
						return selectVillageRows(overviewTable);
					}
				}
				tableHandler.getReplacedVillageRows = getReplacedVillageRows;
				
				function selectVillageRows(page) {
					//q(tableHandler.overviewTableName);
					//q("grrrr:"+page.find("tr").not(":first").length);
					var villageRows = page.find("tr").not(":first");
					if (tableHandler.settings.hasBottomTotalRow) {
						villageRows = villageRows.not(":last");
					}
					//q(villageRows);
					return villageRows;
				}
				
				function ajaxLoadNextPageSetup() {
					if (server_settings.ajaxAllowed) {
						var nextPageLink = $("#paged_view_content a.paged-nav-item").first();
						if (nextPageLink.length !== 0) {
							// find all pages we can still add to the current table
							var currentPageLabel = nextPageLink.parent().find("strong");
							var nextPageLinks = [];
							currentPageLabel = currentPageLabel.next();
							while (currentPageLabel.text().match(/\d/)) {
								nextPageLinks.push(currentPageLabel);
								currentPageLabel = currentPageLabel.next();
							}
							
							if (nextPageLinks.length > 0) {
								nextPageLink.parent().append("&nbsp; <a href=# id=loadNextPage>"+trans.sp.overviews.loadNextPage+"</a>");
								
								$("#loadNextPage").click(function() {
									// Get next page or remove link
									var nextPageUrl = nextPageLinks[0];
									if (nextPageLinks.length == 1) {
										$(this).replaceWith("<strong>"+trans.sp.overviews.loadNextPage+"</strong>");
									}
									nextPageLinks.shift();
									
									// Fetch and insert next page
									ajax(nextPageUrl.attr("href"), function (page) {
										var nextPageRows = getReplacedVillageRows($(page));
										if (tableHandler.settings.hasBottomTotalRow) {
											tableHandler.overviewTable.find("tr:last").before(nextPageRows);
										} else {
											tableHandler.overviewTable.append(nextPageRows);
										}
			
										nextPageUrl.replaceWith("<strong>"+nextPageUrl.text()+"</strong>");
									});
								});
							}
						}
					}
				}
			})(tableHandler || (tableHandler = {}));

			// PRODUCTION OVERVIEW
            if (location.href.indexOf('mode=prod') > -1) {
				(function() {
				    //console.time("overview-prod");
				    try {
				        overviewTable = $("#production_table");
				        tableHandler.init("production_table");
				
				        // Filter full storage rooms
				        var resTable = $("#production_table");
				        var menu = "<table class='vis' width='100%'>";
				        menu += "<tr><th width='99%'>";
				        menu += " <input type=checkbox id=resFilter " + (user_data.resources.filterRows ? "checked" : "") + "> " + trans.sp.prodOverview.filter + " ";
				        menu += "&nbsp;<input type=button id=resStorageFull value='" + trans.sp.prodOverview.filterFullGS + "' title=''>&nbsp; &nbsp; ";
				        menu += "<select id=resAmountType><option value=1>" + trans.sp.all.more + "</option>";
				        menu += "<option value=-1>" + trans.sp.all.less + "</option></select>";
				        menu += "<input type=text id=resAmount size=6 value=" + user_data.resources.requiredResDefault + ">";
				        menu += " <input type=button class=resFilter value='" + trans.tw.all.wood + "' resIndex=0><input type=button class=resFilter value='" + trans.tw.all.stone + "' resIndex=1><input type=button class=resFilter value='" + trans.tw.all.iron + "' resIndex=2><input type=button class=resFilter value='" + trans.sp.all.all + "' resIndex=-1>";
				        menu += " " + trans.sp.all.withText + " <input type=checkbox id=resMerchant " + (user_data.resources.filterMerchants ? "checked" : "") + " title='" + trans.sp.prodOverview.merchantTooltip + "'>";
				        menu += "<input type=text id=resMerchantAmount size=2 value=" + user_data.resources.requiredMerchants + " title='" + trans.sp.prodOverview.merchantAmountTooltip + "'> " + trans.sp.all.merchants + " ";
				
				        menu += "</th><th width='1%' nowrap>";
				        menu += "<input type=button id=resBBCode value='" + trans.sp.prodOverview.bbCodes + "'> "
				            + "<input type=checkbox id=resBBCodeImages> " + trans.sp.prodOverview.bbCodesInfo + "&nbsp; ";
				        menu += "</th></tr></table>";
				        resTable.before(menu);
				
				        $("#resFilter").change(function () {
				            var isCheck = $(this).is(":checked");
				            $("#resFilter").attr("title", isCheck ? trans.sp.prodOverview.filterTooltip : trans.sp.prodOverview.filterTooltipReverse);
				            $("#resStorageFull").attr("title", isCheck ? trans.sp.prodOverview.filterFullGSTooltip : trans.sp.prodOverview.filterFullGSTooltipReverse);
				            $(".resFilter").each(function (index, value) {
				                if (index == 3) {
				                    $(value).attr("title", isCheck ? trans.sp.prodOverview.filterAllTooltip : trans.sp.prodOverview.filterAllTooltipReverse);
				                } else {
				                    $(value).attr("title", isCheck ? trans.sp.prodOverview.filter1Tooltip.replace("{0}", $(value).attr("value")) : trans.sp.prodOverview.filter1TooltipReverse.replace("{0}", $(value).attr("value")));
				                }
				            });
				        });
				
				        $("#resFilter").change();
				
				        $("#resStorageFull").click(function () {
				            trackClickEvent("FilterFullRes");
				            filterRes('full', $("#resFilter").is(":checked"));
				        });
				
				        $("#resBBCode").click(function () {
				            trackClickEvent("BBCodeOutput");
				            var bbs = filterRes("bbcode", false),
				                reverse = $("#resAmountType").val() == "-1",
				                bbCodesTitle = reverse ? trans.sp.prodOverview.tooLittleText : trans.sp.prodOverview.tooMuchText;
				
				            bbCodesTitle = bbCodesTitle
				                .replace("{diff}", parseInt(user_data.resources.bbcodeMinimumDiff / 1000, 10))
				                .replace("{min}", parseInt(parseInt($("#resAmount").val(), 10) / 1000, 10));
				
				            if ($("#textsArea").size() == 0) {
				                $(this).parent().parent().parent().append("<tr><td colspan=2 id=textsArea></td></tr>");
				            } else {
				                $("#textsArea").html("");
				            }
				
				            $("#textsArea").append("<b>" + bbCodesTitle + "</b>" + trans.sp.prodOverview.bbCodeExtraInfo + "<br><textarea id=bbcodeArea cols=50 rows=10 wrap=off>");
				            $("#bbcodeArea").val(bbs);
				
				            $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
				            $("#closeTextsArea").click(function() {
				                $("#textsArea").parent().remove();
				            });
				        });
				
				        function filterRes(resourceIndex, hideRows) {
				            var resCode = [trans.tw.all.wood, trans.tw.all.stone, trans.tw.all.iron];
				            var bbcodes = '';
				            var goners = $();
				            var stayers = $();
				            var filterMerchants = $("#resMerchant").is(":checked");
				            var filterMerchantsAmount = parseInt($("#resMerchantAmount").val(), 10);
				            var minAmount = parseInt($("#resAmount").val(), 10);
				            var reverse = $("#resAmountType").val() == "-1";
				            var bbCodeImages = $("#resBBCodeImages").is(":checked");
				            var minDif = user_data.resources.bbcodeMinimumDiff;
				            var bbCodesTitle;
				
				            if (reverse) {
				                bbcodes = trans.sp.prodOverview.tooLittle + "\n";
				                bbCodesTitle = trans.sp.prodOverview.tooLittleText;
				            } else {
				                bbcodes = trans.sp.prodOverview.tooMuch + "\n";
				                bbCodesTitle = trans.sp.prodOverview.tooMuchText;
				            }
				            bbCodesTitle = bbCodesTitle.replace("{min}", minDif).replace("{diff}", minAmount);
				
				            function doResource(resCell, resArray, resIndex, reverse, minAmount) {
				                var resAmount = parseInt(resArray[resIndex], 10);
				                if ((!reverse && resAmount > minAmount) || (reverse && resAmount < minAmount)) {
				                    $("span[title]:eq(" + resIndex + ")", resCell).css("font-weight", "bold")
				                    return false;
				                }
				                return true;
				            }
				
				            var hasNotes = $("th:first", resTable).text().indexOf(trans.tw.overview.village) == -1;
				            resTable.find("tr:gt(0)").each(function () {
				                var isOk = true;
				                var resCell;
				                if (hasNotes) {
				                    resCell = $(this).find("td:eq(3)");
				                } else {
				                    resCell = $(this).find("td:eq(2)");
				                }
				                var resources = $.trim(resCell.text()).replace(/\./gi, "").split(" ");
				
				                if (resourceIndex == 'bbcode') {
				                    // All resources
				                    var villageBBCode = '';
				                    for (var i = 0; i < 3; i++) {
				                        if ((!reverse && resources[i] - minDif > minAmount) || (reverse && parseInt(resources[i], 10) + parseInt(minDif, 10) < minAmount)) {
				                            if (bbCodeImages) {
				                                villageBBCode += "[img]https://www.tribalwars.nl/graphic/" + world_data.resources[i] + ".png[/img] ";
				                            } else {
				                                villageBBCode += resCode[i] + " ";
				                            }
				                            villageBBCode += parseInt(Math.abs(resources[i] - minAmount) / 1000, 10) + "k ";
				                        }
				                    }
				                    if (villageBBCode.length > 0) {
				                        var villageCell = $("td:eq(" + (hasNotes ? "1" : "0") + ") span:eq(1)", this);
				                        bbcodes += "[village]" + getVillageFromCoords(villageCell.text()).coord + "[/village] " + villageBBCode + "\n";
				                    }
				                } else if (resourceIndex == 'full') {
				                    // full storage rooms
				                    if ($(".warn", this).size() > 0) {
				                        resCell.css("background-color", user_data.resources.highlightColor);
				                        isOk = false;
				                    }
				
				                } else {
				                    // One specific resource
				                    $("span[title]", resCell).css("font-weight", "normal");
				
				                    if (resourceIndex == "-1") {
				                        isOk = isOk && !(!doResource(resCell, resources, 0, reverse, minAmount)
				                            | !doResource(resCell, resources, 1, reverse, minAmount)
				                            | !doResource(resCell, resources, 2, reverse, minAmount));
				                    } else {
				                        isOk = isOk && doResource(resCell, resources, resourceIndex, reverse, minAmount);
				                    }
				
				                    if (!isOk) {
				                        resCell.css("background-color", user_data.resources.highlightColor);
				                    } else {
				                        resCell.css("background-color", "");
				                    }
				
				                    if (filterMerchants) {
				                        resCell = $(this).find("td:eq(4)");
				                        if (hasNotes) {
				                            resCell = resCell.next();
				                        }
				                        var merchants = resCell.text();
				                        merchants = merchants.substr(0, merchants.indexOf("/"));
				                        if (merchants < filterMerchantsAmount) {
				                            resCell.css("background-color", user_data.colors.error);
				                        } else {
				                            resCell.css("background-color", "");
				                        }
				                    }
				                }
				
				                if (hideRows && isOk) {
				                    goners = goners.add($(this));
				
				                    // Village rename script will not rename villages if the hidden rename inputfield is on a hidden row
				                    // --> People were using our script to filter the village list and then use a mass village renamer which also renamed the hidden village rows
				                    $("input:first", $(this)).val("");
				
				                }
				                else if (!$(this).is(":visible")) {
				                    stayers = stayers.add($(this));
				                }
				            });
				            if (hideRows) {
				                goners.remove();
				                var amountOfVillagesCell = $("tr:first th", resTable).eq(hasNotes ? 1 : 0);
				                amountOfVillagesCell.text(amountOfVillagesCell.text().replace(/\d+/, $("tr", resTable).size() - 1));
				            } else {
				                stayers.show();
				                goners.hide();
				            }
				
				            return bbcodes;
				        }
				
				        $(".resFilter").click(function () {
				            trackClickEvent("FilterResource");
				            filterRes($(this).attr("resIndex"), $("#resFilter").is(":checked"));
				        });
				    } catch (e) { handleException(e, "overview-prod"); }
				    //console.timeEnd("overview-prod");
				}());
            }
			// TROOPS OVERVIEW
            else if (location.href.indexOf('mode=units') > -1
						&& (location.href.indexOf('type=own_home') > -1 || location.href.indexOf('type=there') > -1)) {
				(function() {
				    //console.time("overview-thereownhome");
				    try {
				        var villageCounter = 0;
				        var rowSize = world_data.units.length + 1;
				        if (world_config.hasMilitia) {
				            rowSize++;
				        }
				
				        var overviewMenuRowFilter = "tr:gt(0)",
				            /**
				             * Page speed can be overruled by the querystring
				             */
				            currentPageSpeed = spSpeedCookie(),
				            /**
				             * {village} object from target cookie (or by url querystring set)
				             */
				            target;
				
				        /**
				         * Do initial filter? (based on querystring)
				         */
				        var doFilter = false,
				            unitIndex = world_data.units.indexOf(user_data.command.filterMinDefaultType),
				            unitAmount = user_data.command.filterMinDefault,
				            sort = false,
				            changeSpeed = false,
				            i;
						var search = window.location.search.substring(1).split("&");
						for (i = 0; i < search.length; i++) {
						    var item = search[i].split("=");
						    switch (item[0]) {
						        case 'unit':
						            doFilter = true;
						            unitIndex = world_data.units.indexOf(item[1]);
						            break;
						        case 'amount':
						            doFilter = true;
						            unitAmount = parseInt(item[1], 10);
						            break;
						        case 'changeSpeed':
						            changeSpeed = item[1];
						            if (changeSpeed != false) {
						                //spSpeedCookie(changeSpeed);
						                currentPageSpeed = changeSpeed;
						            }
						            break;
						
						        case 'targetvillage':
						            var newTargetVillage = getVillageFromCoords(item[1]);
						            spTargetVillageCookie(newTargetVillage.coord);
						            break;
						
						        case 'sort':
						            sort = item[1] == "true";
						            break;
						    }
						}
				
				        // Sangu package menu is also built in reinitialize_table
						/**
						 * Creates a select box with all unit types in this world
						 * @param {string} id the DOM ID
						 * @param {string} select the currently selected unit
						 */
						function makeUnitBox(id, select) {
						    var box = "<select id=" + id + ">";
						    $.each(world_data.units, function (i, v) {
						        box += "<option value=" + i + (v == select ? " selected" : "") + ">" + trans.tw.units.names[v] + "</option>";
						    });
						    box += "</select>";
						    return box;
						}
						
						var menu = "<table width='100%' class='vis'>";
						menu += "<tr>";
						menu += "<th nowrap width='1%'>";
						menu += "<input type=text size=5 id=filterAxeValue value='" + user_data.command.filterMinDefault + "'>";
						menu += makeUnitBox("filterAxeType", user_data.command.filterMinDefaultType);
						menu += "<input type=button id=filterAxe value='" + trans.sp.troopOverview.filterTroops + "'";
						menu += " title='" + trans.sp.troopOverview.filterTroopsTooltip + "'> ";
						
						menu += "</th><th nowrap width='1%'>";
						
						menu += "<select id=filterPopValueType><option value=1>" + trans.sp.all.more + "</option>";
						menu += "<option value=-1>" + trans.sp.all.less + "</option></select>";
						menu += "<input type=text size=5 id=filterPopValue value='" + user_data.command.filterMinPopulation + "'>";
						menu += "<input type=button id=filterPop value='" + trans.sp.troopOverview.filterPopulation + "' title='" + trans.sp.troopOverview.filterPopulationTooltip + "'> ";
						
						menu += "</th><th nowrap width='1%'>";
						menu += "<input type=text size=5 id=filterWalkingTimeValue>";
						menu += "<input type=button id=filterWalkingTime value='" + trans.sp.troopOverview.filterWalkingTime + "' title='" + trans.sp.troopOverview.filterWalkingTimeTooltip + "'> ";
						
						menu += "</th><th width='95%'>";
						
						menu += "<input type=button id=snobFilter value='" + trans.sp.troopOverview.filterNoble + "' title='" + trans.sp.troopOverview.filterNobleTooltip + "'> &nbsp; ";
						menu += "<input type=button id=attackFilter value='" + trans.sp.troopOverview.filterUnderAttack + "' title='" + trans.sp.troopOverview.filterUnderAttackTooltip + "'> &nbsp; ";
						
						menu += "</th><th width='1%'>";
						
						menu += "<input type=button id=calculateStack value='" + trans.sp.troopOverview.calcStack + "' title='" + trans.sp.troopOverview.calcStackTooltip + "'>";
						menu += "</th>";
						
						menu += "</tr></table>";
						
						// second row
						menu += "<table><tr><th width='1%' nowrap>";
						menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
						
						menu += "</th><th width='1%' nowrap>";
						menu += "<input type=text size=12 id=defFilterTextValue value=''>";
						menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>";
						
						menu += "</th><th width='97%' nowrap>";
						menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
						
						menu += "</th>";
						
						if (location.href.indexOf('type=there') > -1) {
						    menu += "<th width='1%'><input type=button id=defRestack value='" + trans.sp.troopOverview.restack + "'></th>";
						}
						menu += "<th nowrap width='1%' style='padding-right: 8px; padding-top: 3px;'>";
						
						menu += "<input type=checkbox id=sortIt title='" + trans.sp.troopOverview.sortTooltip + "'"
						    + (user_data.command.filterAutoSort ? " checked" : "") + "> "
						    + trans.sp.troopOverview.sort;
						
						menu += "</th></tr>";
						menu += "</table>";
						
						// Sangu filter menu
						var sanguMenu = menu;
						
						// Overview table menu
						menu = "<tr id=units_table_header>";
						menu += "<th>" + trans.sp.troopOverview.village + "</th>";
						menu += "<th>" + trans.sp.troopOverview.nightBonus + "</th>";
						$.each(world_data.units, function (i, v) {
						    menu += "<th><img src='/graphic/unit/unit_" + v + ".png' title=\"" + trans.sp.troopOverview.selectUnitSpeed.replace("{0}", trans.tw.units.names[v]) + "\" alt='' id=" + v + " /></th>";
						});
						if (world_config.hasMilitia) {
						    menu += "<th><img src='/graphic/unit/unit_militia.png' title='" + trans.tw.units.militia + "' alt='' id=militia /></th>";
						}
						menu += "<th>" + trans.sp.troopOverview.commandTitle + "</th>";
						
						
						target = getVillageFromCoords(spTargetVillageCookie());
						menu += "<th nowrap>" + trans.sp.all.targetEx
						    + " <input type=text id=targetVillage name=targetVillage size=8 value='"
						    + (target.isValid ? target.coord : "") + "'>"
						    + "<input type=button class='btn' id=targetVillageButton value='"
						    + trans.sp.troopOverview.setTargetVillageButton + "'></th>";
						menu += "</tr>";
						
						
						
						
						
						
						// function to replace the village rows
						tableHandler.init("units_table", {
						    rowReplacer: function (row) {
						        //q($(row).html());
						        var mod = "row_a";
						        var newRow = "";
						        var finalRow = "";
						        var addThisRow = true;
						        var cells = $("td:gt(0)", row);
						        var units = {};
						        var villageCell = $("td:first", row);
						        var villageId = $("span.quickedit-vn", villageCell).attr("data-id");
						
						        cells.each(function (index, element) {
						            if (doFilter && index - 1 == unitIndex && parseInt(this.innerHTML, 10) < unitAmount) {
						                //q("index:" + index + ' == '+ unitIndex + " : " + row.html() + ' * 1 < ' + unitAmount);
						                addThisRow = false;
						                return false;
						            }
						            else if (index == rowSize) {
						                //q(index + "==" + rowSize);
						                newRow += "<td>";
						                newRow += "<img src='/graphic/dots/red.png' title='" + trans.sp.troopOverview.removeVillage + "' style='margin-bottom: 2px' /> ";
						                //newRow += "<img src='https://www.tribalwars.vodka/graphic/delete_small.png' style='margin-bottom: 3px; position: relative' title='" + trans.sp.troopOverview.removeVillage + "' /> ";
						                newRow += "<a href='" + $("a", element).attr('href').replace("mode=units", "") + "&sanguX=0&sanguY=0' class='attackLinks'>";
						                newRow += "<img src='/graphic/command/attack.png' title='" + trans.sp.troopOverview.toThePlace + "' style='margin-bottom: 1px' />";
						                // Works only with leftclick onclick='this.src=\"/graphic/command/return.png\";'
						                newRow += "</a>";
						                newRow += "</td>";
						            } else {
						                //q("units:" + world_data.units[index - 1]);
						                var cellDisplay = this.innerHTML;
						                if (cellDisplay === "0") {
						                    cellDisplay = "&nbsp;";
						                }
						                else if (cellDisplay.indexOf('="has_tooltip"') > -1)  {
						                    cellDisplay = cellDisplay.replace('="has_tooltip"', '="has_tooltip" title="'+trans.sp.troopOverview.cheapNobles+'"');
						                }
						
						                newRow += "<td>" + cellDisplay + "</td>";
						                if (index > 0) {
						                    units[world_data.units[index - 1]] = parseInt(element.innerHTML, 10);
						                }
						                // innerHTML can contain a + sign for the nobles: "+" indicates nobles can be rebuild cheaply
						                // The snobs are not important here
						            }
						        });
						
						        if (addThisRow) {
						            var villageType = calcTroops(units);
						            if (doFilter) {
						                mod = villageCounter % 2 == 0 ? "row_a" : "row_b";
						            } else {
						                mod = !villageType.isDef ? "row_a" : "row_b";
						            }
						
						            var coord = getVillageFromCoords(villageCell.text());
						
						            //finalRow += "<tbody>";
						            finalRow += "<tr arrival='0' data-coord-x='" + coord.x + "' data-coord-y='" + coord.y + "' "
						                + " class='row_marker " + mod + (game_data.village.id == villageId ? " selected" : "") + "'>";
						            finalRow += "<td>" + villageCell.html() + "</td>";
						            finalRow += newRow;
						            finalRow += "<td></td></tr>";
						            //finalRow += "</tbody>";
						
						            villageCounter++;
						
						            return finalRow;
						        }
						        return "";
						    }
						});
						
						var newTable = tableHandler.getReplacedVillageRows();
						$("#units_table")
						    .html("<table width='100%' class='vis' id='units_table' target='false'>" + menu + newTable + "</table>")
						    .before(sanguMenu);
						
						
						// Tooltips
						$("#defReverseFilter").change( function () {
						    var isChecked = $(this).is(":checked");
						    var defTrans = trans.sp.troopOverview;
						
						    $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse);
						    $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
						});
						$("#defReverseFilter").change();
						
						
						// Initial focus on target inputbox
						$('#targetVillage').click(function () {
						    $(this).focus().select();
						});
						
						
						
						// "Attacks per page" -> change to # villages in the list
						var pageSize = $("input[name='page_size']");
						var villageAmountCell = $("#units_table tr:first th:first");
						//assert(villageAmountCell.length === 1, "village cell Dorp (xxx) niet gevonden");
						villageAmountCell.text(villageAmountCell.text() + " (0)");
						function setVillageCount(amount) {
						    pageSize.val(amount);
						    villageAmountCell.text(villageAmountCell.text().replace(/\d+/, amount));
						}
						
						pageSize.parent().prev().text(trans.sp.overviews.totalVillages);
						setVillageCount(villageCounter);
				
						// Recalculate arrival times as the target village changes
						$("#targetVillageButton").click(function () {
						    trackClickEvent("TargetVillageSet");
						    var targetMatch = getVillageFromCoords($('#targetVillage').val(), true);
						    $("#units_table").attr("target", targetMatch.isValid);
						    if (!targetMatch.isValid) {
						        spTargetVillageCookie("");
						        alert(trans.sp.troopOverview.setTargetVillageButtonAlert);
						        $("#targetVillage").focus();
						
						    } else {
						        $(".attackLinks", tableHandler.overviewTable).each(function() {
						            // add target coordinates to attack image href which are read in place
						            var hrefWithVillageCoords = $(this).attr("href");
						            hrefWithVillageCoords = hrefWithVillageCoords.replace(/sanguX=(\d+)&sanguY=(\d+)/, "sanguX="+targetMatch.x+"&sanguY="+targetMatch.y);
						            $(this).attr("href", hrefWithVillageCoords);
						        });
						
						        spTargetVillageCookie(targetMatch.coord);
						        $("#units_table").find(overviewMenuRowFilter).each(function () {
						            var unitRow = $(this),
						                dist = getDistance(targetMatch.x, unitRow.attr("data-coord-x"), targetMatch.y, unitRow.attr("data-coord-y"), currentPageSpeed);
						
						            $("td:last", unitRow).html(dist.html);
						            $(this).attr("arrival", dist.travelTime);
						            if (dist.isNightBonus) {
						                $("td:eq(1)", unitRow).css("background-color", user_data.colors.error);
						            } else {
						                $("td:eq(1)", unitRow).css("background-color", '');
						            }
						        });
						
						        if ($("#sortIt").is(":checked")) {
						            $("#units_table").find(overviewMenuRowFilter).sortElements(function (a, b) {
						                return parseInt($(a).attr("arrival"), 10) > parseInt($(b).attr("arrival"), 10) ? 1 : -1;
						            });
						        }
						    }
						});
						
						// sort can be set with the querystring
						if (sort) {
						    $("#targetVillageButton").click();
						}
						
						// delete a table row
						$("#units_table").mouseup(function (e) {
						    if (e.target.nodeName === 'IMG') {
						        if (e.target.title == trans.sp.troopOverview.removeVillage) {
						            setVillageCount(parseInt(pageSize.val(), 10) - 1);
						            $(e.target).parent().parent().remove();
						        }
						    }
						});
						
						// remove row or add border to command cell when middle mouse click (open in new tab)
						$(tableHandler.overviewTable).on("mousedown",".attackLinks", function(e) {
						    if (e.which == 2) {
						        var cell = $(e.target).parent().parent();
						        if (user_data.command.middleMouseClickDeletesRow2) {
						            cell.parent().remove();
						        } else {
						            cell.css("border", (parseInt(cell.css("border-width").substr(0, 1), 10) + 1) + "px red solid");
						        }
						    }
						});
						
						// Change active speed by clicking on a unit icon
						// ATTN: border style duplicated in trans.troopOverview.help
						$('#' + currentPageSpeed).parent().css("border", "2px green dotted");
						$('#' + spSpeedCookie()).parent().css("border", "3px red solid");
						$("#units_table_header").click(function (e) {
						    if (e.target.nodeName === 'IMG' && e.target.id !== "militia") {
						        currentPageSpeed = e.target.id;
						        $("img", this).parent().css("border", "0px");
						        $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
						        $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
						        $("#targetVillageButton").click();
						    }
						});
						
						$("#units_table_header").dblclick(function (e) {
						    if (e.target.nodeName === 'IMG' && e.target.id !== "militia") {
						        currentPageSpeed = e.target.id;
						        spSpeedCookie(e.target.id);
						        $("img", this).parent().css("border", "0px");
						        $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
						        $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
						        $("#targetVillageButton").click();
						    }
						});
						function filterVillageRows(filterStrategy, options) {
						    // return true to hidethe row; false keep row visible (without reverse filter checkbox)
						    options = options || {
						            allowFilter: true
						        };
						    var reverseFilter = options.allowFilter && $("#defReverseFilter").is(":checked"),
						        goners = $(),
						        villageCounter = 0;
						
						    $("#units_table").find(overviewMenuRowFilter).each(function () {
						        var self = $(this);
						        if (!reverseFilter != !filterStrategy(self)) {
						            goners = goners.add(self);
						            $("input:eq(1)", self).val("");
						        } else {
						            villageCounter++;
						        }
						    });
						    goners.remove();
						
						    // Show totals
						    setVillageCount(villageCounter);
						}
						
						// CONTINENT FILTER
						$("#defFilterContinent").click(function () {
						    trackClickEvent("FilterContinent");
						    var continent = parseInt($("#defFilterContinentText").val(), 10);
						    if (!isNaN(continent)) {
						        filterVillageRows(function (row) {
						            var village = getVillageFromCoords(row.find("td:first").text());
						            if (!village.isValid ) {
						                return true;
						            }
						            return village.continent() != continent;
						        });
						    }
						});
						
						// TEXT FILTER
						$("#defFilterText").click(function () {
						    trackClickEvent("FilterText");
						    var compareTo = $("#defFilterTextValue").val().toLowerCase();
						    if (compareTo.length > 0) {
						        filterVillageRows(function (row) {
						            return row.text().toLowerCase().indexOf(compareTo) == -1;
						        });
						    }
						});
						
						// WALKINGTIME FILTER
						$("#filterWalkingTime").click(function () {
						    var minWalkingTime = parseInt($("#filterWalkingTimeValue").val(), 10) * 60;
						
						    if (!isNaN(minWalkingTime)) {
						        trackClickEvent("WalkingTime");
						        filterVillageRows(
						            function (row) {
						                return parseInt(row.attr("arrival"), 10) < minWalkingTime;
						            },
						            {
						                allowFilter: false
						            }
						        );
						    } else {
						        alert(trans.sp.troopOverview.filterWalkingTimeTooltip);
						    }
						});
						
						
						
						
						
						
						// Filter rows with less than x axemen (or another unit)
						$("#filterAxe").click(function () {
						    trackClickEvent("FilterUnitAmount");
						    var villageCounter = 0;
						    var goners = $();
						    var minAxeValue = parseInt($("#filterAxeValue").val(), 10);
						    var unit = parseInt($('#filterAxeType').val(), 10);
						    $("#units_table").find(overviewMenuRowFilter).each(function () {
						        var val = $("td:eq(" + (unit + 2) + ")", this).html();
						        if (val == '&nbsp;' || parseInt(val, 10) < minAxeValue) {
						            goners = goners.add($(this));
						            $("input:first", $(this)).val("");
						        }
						        else
						            villageCounter++;
						    });
						    goners.remove();
						    setVillageCount(villageCounter);
						});
						// change by default selected unit the filter will be active for
						$("#filterAxeType").change(function () {
						    var unit = world_data.units[$(this).val()];
						    if (typeof user_data.command.filterMin[unit] !== 'undefined') {
						        $("#filterAxeValue").val(user_data.command.filterMin[unit]);
						    } else {
						        $("#filterAxeValue").val(user_data.command.filterMinOther);
						    }
						});
						
						
						
						// Filter rows without snobs/nobles
						$("#snobFilter").click(function () {
						    trackClickEvent("FilterSnob");
						    var villageCounter = 0;
						    var goners = $();
						    $("#units_table").find(overviewMenuRowFilter).each(function () {
						        if ($.trim($("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", this).text()) === '') {
						            goners = goners.add($(this));
						            $("input:first", $(this)).val("");
						        } else
						            villageCounter++;
						    });
						    goners.remove();
						    setVillageCount(villageCounter);
						});
						
						// hide rows not under attack
						$("#attackFilter").click(function () {
						    trackClickEvent("FilterUnderAttack");
						    var villageCounter = 0;
						    var goners = $();
						    $("#units_table").find(overviewMenuRowFilter).each(function () {
						        //q("'" + $(this).html() + "'");
						        //q("---------------------------------------------------");
						        if ($('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', this).size() != 0) {
						            goners = goners.add($(this));
						            $("input:first", $(this)).val("");
						        } else {
						            villageCounter++;
						        }
						    });
						    goners.remove();
						    setVillageCount(villageCounter);
						});
						
						// filter rows with less then x population
						$("#filterPop").click(function () {
						    trackClickEvent("FilterFarm");
						    $("#calculateStack").click();
						    var villageCounter = 0;
						    var goners = $();
						    var min = parseInt($("#filterPopValue").val(), 10);
						    var reverseFilter = $("#filterPopValueType").val() == "-1";
						    $("#units_table").find(overviewMenuRowFilter).each(function () {
						        var line = $(this);
						        $("td:eq(1)", this).each(function () {
						            var amount = parseInt($(this).text().replace('.', ''), 10);
						            if ((!reverseFilter && amount < min) || (reverseFilter && amount > min)) {
						                goners = goners.add(line);
						                $("input:first", line).val("");
						            }
						            else villageCounter++;
						        });
						    });
						    goners.remove();
						    setVillageCount(villageCounter);
						});
						// One time help display
						(function() {
						    if ($("#targetVillageButton").length === 0) {
						        // group without villages
						        return;
						    }
						
						    var position = $("#targetVillageButton").position(),
						        options = {
						            left: position.left - 300,
						            top: position.top + 35
						        },
						        content = {
						            title: trans.sp.troopOverview.helpTitle,
						            body: trans.sp.troopOverview.help.replace("{unitIcon}", "<img src='graphic/unit/unit_ram.png'>, <img src='graphic/unit/unit_spear.png'>, ...")
						        };
						
						    createFixedTooltip("troopOverviewTooltip", content, options);
						}());
						
						// Calculate stack
						$("#calculateStack").click(function () {
						    trackClickEvent("CalculateStack");
						    if (!this.disabled) {
						        this.disabled = true;
						        $("#units_table").find(overviewMenuRowFilter).each(function () {
						            var total = 0;
						            $("td:gt(1)", this).each(function (i) {
						                if (!($.trim(this.innerHTML) == '' || this.innerHTML == '&nbsp;' || i >= world_data.unitsPositionSize.length)) {
						                    total += this.innerHTML * world_data.unitsPositionSize[i];
						                }
						            });
						            $("td:eq(1)", this).text(formatNumber(total)).css("background-color", getStackColor(total));
						        });
						    }
						});
						// Calculate Restack BB codes
						if (location.href.indexOf('type=there') > -1) {
						    $("#defRestack").click(function () {
						        trackClickEvent("BBCodeOutput");
						        $("#calculateStack").click();
						
						        var request = "";
						        $("#units_table").find(overviewMenuRowFilter).each(function () {
						            var total = parseInt($("td:eq(1)", $(this)).text().replace(/\./, ''), 10);
						            if (user_data.restack.to - total > user_data.restack.requiredDifference) {
						                var villageDesc = $(this).find("td:first span[data-text]").text(),
						                    villageCoord = getVillageFromCoords(villageDesc);
						
						                request += "[village]" + villageCoord.coord + "[/village] (" + parseInt((user_data.restack.to - total) / 1000, 10) + "k)\n";
						            }
						        });
						
						        if ($("#textsArea").size() == 0) {
						            $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>");
						        } else {
						            $("#textsArea").html("");
						        }
						
						        var title = trans.sp.troopOverview.restackTitle
						            .replace("{to}", parseInt(user_data.restack.to / 1000, 10))
						            .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10));
						        $("#textsArea").append(title + "<br><textarea cols=35 rows=10 id=defRestackArea>" + request + "</textarea>");
						
						        $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
						        $("#closeTextsArea").click(function() {
						            $("#textsArea").parent().remove();
						        });
						    });
						}
				
				    } catch (e) { handleException(e, "overview-thereownhome"); }
				    //console.timeEnd("overview-thereownhome");
				}());
            }
			// BUILDINGS OVERVIEW
            else if (location.href.indexOf('mode=buildings') > -1) {
				(function() {
				    //console.time("overview-buildings");
				    try {
				        // Highlight everything not conform
				        overviewTable = $("#buildings_table");
				        tableHandler.init("buildings_table");
				
				        var menu = "<table class='vis' width='100%'>";
				        menu += "<tr><th>";
				        menu += "<input type=checkbox id=buildingOpti> " + trans.sp.buildOverview.optimistic + " ";
				        menu += "<input type=button id=buildingHighlight value='" + trans.sp.buildOverview.mark + "'>";
				        menu += "<input type=button id=buildingFilter value='" + trans.sp.buildOverview.filter + "'>";
				        menu += "</th></tr></table>";
				        overviewTable.before(menu);
				
				        function filterBuildings(cellAction, hideRows) {
				            var buildings = [];
				            overviewTable.find("tr:first img").each(function (i, v) {
				                buildings[i] = this.src.substr(this.src.lastIndexOf('/') + 1);
				                buildings[i] = buildings[i].substr(0, buildings[i].indexOf('.'));
				            });
				
				            var goners = $();
				            var opti = $("#buildingOpti").is(":checked");
				            overviewTable.find("tr:gt(0)").each(function () {
				                var isOk = true;
				                $(this).find("td:gt(3)").each(function (i, v) {
				                    var range = user_data.buildings[buildings[i]];
				                    if (range != undefined) {
				                        var text = parseInt($(this).text(), 10);
				                        if (text < range[0]) {
				                            $(this).css("background-color", user_data.colors.error);
				                            isOk = false;
				                        } else if (text > range[1] && !opti) {
				                            $(this).css("background-color", user_data.colors.good);
				                            isOk = false;
				                        } else
				                            $(this).css("background-color", "");
				                    }
				                });
				                if (hideRows && isOk) {
				                    goners = goners.add($(this));
				                    $("input:first", $(this)).val("");
				                }
				            });
				            goners.remove();
				        }
				
				        $("#buildingHighlight").click(function () {
				            trackClickEvent("TableHighlight");
				            filterBuildings(function (cell, isOk) {
				                cell.css("background-color", isOk ? "" : user_data.colors.neutral);
				            }, false);
				        });
				
				        $("#buildingFilter").click(function () {
				            trackClickEvent("TableRemove");
				            filterBuildings(function (cell, isOk) {
				                cell.css("background-color", isOk ? "" : user_data.colors.neutral);
				            }, true);
				        });
				    } catch (e) { handleException(e, "overview-buildings"); }
				    //console.timeEnd("overview-buildings");
				}());
            }
			// TECHS OVERVIEW // SMEDERIJ OVERVIEW // SMITHY OVERVIEW
            else if (location.href.indexOf('mode=tech') > -1) {
				(function() {
				    //console.time("overview-techs");
				    try {
				        overviewTable = $("#techs_table");
				        tableHandler.init("techs_table");
				
				// Highlight everything not conform usersettings
				        if (world_config.smithyLevels) {
				            var menu = "<table class='vis' width='100%'>";
				            menu += "<tr><th>";
				            menu += "<select id='groupType'>";
				            $.each(user_data.smithy, function (i, v) {
				                menu += "<option value=" + i + ">" + v[0] + "</option>";
				            });
				            menu += "</select>";
				            menu += "<input type=checkbox id=buildingOpti> " + trans.sp.smithOverview.optimistic + " ";
				            menu += "<input type=button id=smithyHighlight value='" + trans.sp.smithOverview.mark + "'>";
				            menu += "<input type=button id=smithyFilter value='" + trans.sp.smithOverview.filter + "'>";
				            menu += "</th></tr></table>";
				            $("#techs_table").before(menu);
				
				            function filterTechs(cellAction, hideRows) {
				                var goners = $();
				                var opti = $("#buildingOpti").is(":checked");
				                var def = user_data.smithy[$("#groupType").val()][1];
				                $("#techs_table").find("tr:gt(0)").each(function () {
				                    var isOk = true;
				                    $(this).find("td:gt(2)").each(function (i, v) {
				                        var range = def[world_data.units[i]];
				                        if (i < world_data.units.length && range != undefined) {
				                            var text = parseInt($(this).text(), 10);
				                            if (text == '') {
				                                text = 0;
				                            }
				                            if (text < range[0]) {
				                                $(this).css("background-color", user_data.colors.error);
				                                isOk = false;
				                            }
				                            else if (text > range[1] && !opti) {
				                                $(this).css("background-color", user_data.colors.good);
				                                isOk = false;
				                            } else {
				                                $(this).css("background-color", "");
				                            }
				                        }
				                    });
				                    if (hideRows && isOk) {
				                        goners = goners.add($(this));
				                        $("input:first", $(this)).val("");
				                    }
				                });
				                goners.remove();
				            }
				
				            $("#smithyHighlight").click(function () {
				                trackClickEvent("TableHighlight");
				                filterTechs(function (cell, isOk) {
				                    cell.css("background-color", isOk ? "" : user_data.colors.neutral);
				                }, false);
				            });
				
				            $("#smithyFilter").click(function () {
				                trackClickEvent("TableRemove");
				                filterTechs(function (cell, isOk) {
				                    cell.css("background-color", isOk ? "" : user_data.colors.neutral);
				                }, true);
				            });
				        }
				    } catch (e) { handleException(e, "overview-techs"); }
				    //console.timeEnd("overview-techs");
				}());
            }
			// GROUPS OVERVIEW
            else if (location.href.indexOf('mode=groups') > -1) {
				(function() {
				    //console.time("overview-groups");
				    try {
				        overviewTable = $("#group_assign_table");
				        tableHandler.init("group_assign_table", {
				            hasBottomTotalRow: true
				        });
				
				        // TODO: edit groups: make div floatable and remember position
				        var menu = "";
				        menu += "<table class=vis width='100%'><tr><th>";
				
				        menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>";
				        menu += "<select id=defFilterDistType>";
				        menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>";
				        menu += "&nbsp;F <input type=text size=3 id=defFilterDistFields value=" + user_data.restack.fieldsDistanceFilterDefault + ">";
				        menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>";
				
				        menu += "&nbsp; | &nbsp;";
				        menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>";
				
				        menu += "<br>";
				
				        menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
				
				        menu += "&nbsp; <input type=text size=12 id=defFilterTextValue value=''>";
				        menu += "<input type=button id=defFilterText value='" + trans.sp.groups.villageFilter + "'>";
				
				        menu += "&nbsp; <input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
				
				        menu += "&nbsp; <input type=textbox size=3 id=defFilterAmountText maxlength=2><input type=button id=defFilterAmount value='" + trans.sp.groups.amountFilter + "'>";
				        menu += "&nbsp; <input type=textbox size=4 id=defFilterPointsText maxlength=5><input type=button id=defFilterPoints value='" + trans.sp.groups.pointsFilter + "'>";
				        menu += "&nbsp; <input type=textbox size=5 id=defFilterFarmText maxlength=6><input type=button id=defFilterFarm value='" + trans.tw.all.farm + "'>";
				
				        menu += "&nbsp; <input type=text size=12 id=defFilterGroupValue value=''>";
				        menu += "<input type=button id=defFilterGroup value='" + trans.sp.groups.groupNameFilter + "'>";
				        menu += "</th></tr></table>";
				
				        var selectAllRow = $("#group_assign_table tr:last");
				        $("#group_assign_table").before(menu).after("<table class=vis width='100%'><tr><th><input type=checkbox id=selectAllVisible> " + selectAllRow.text() + "</th></tr></table>");
				        selectAllRow.remove();
				
				        // Select all checkbox behavior
				        $("#selectAllVisible").change(function () {
				            var isChecked = $(this).is(":checked");
				            $("#group_assign_table input:checked").prop("checked", false);
				            if (isChecked) {
				                $("#group_assign_table input[type='checkbox']").not(":hidden").prop("checked", true);
				            }
				
				            //$("#group_assign_table input:hidden").prop("checked", false);
				            //$("#group_assign_table input:visible").prop("checked", isChecked);
				        });
				
				        // Change tooltips when clicking the reverse filter checkbox
				        $("#defReverseFilter").change(function () {
				            var isChecked = $(this).is(":checked");
				            var defTrans = trans.sp.groups;
				            $("#defFilterText").attr("title", isChecked ? defTrans.villageFilterTitle : defTrans.villageFilterTitleRev);
				            $("#defFilterContinent").attr("title", isChecked ? trans.sp.commands.continentFilterTooltip : trans.sp.commands.continentFilterTooltipReverse);
				
				            $("#defFilterAmount").attr("title", isChecked ? defTrans.amountFilterTitle : defTrans.amountFilterTitleRev);
				            $("#defFilterPoints").attr("title", isChecked ? defTrans.pointsFilterTitle : defTrans.pointsFilterTitleRev);
				            $("#defFilterFarm").attr("title", isChecked ? defTrans.farmFilterTitle : defTrans.farmFilterTitleRev);
				
				            $("#defFilterGroup").attr("title", isChecked ? defTrans.groupNameFilterTitle : defTrans.groupNameFilterTitleRev);
				        });
				        $("#defReverseFilter").change();
				
				        /**
				         * Perform a filter on the groups table rows
				         * @param {function} filterStrategy jQuery object with the row is the first parameter
				         * @param {boolean} reverseFilter
				         * @param {function} [keepRowStrategy]
				         * @param {*} [tag] passed as second param to filterStrategy and keepRowStrategy
				         */
				
				        function filterGroupRows(filterStrategy, reverseFilter, keepRowStrategy, tag) {
				            if (typeof reverseFilter === "undefined") {
				                reverseFilter = !$("#defReverseFilter").is(":checked");
				            }
				
				            var goners = $();
				            var totalVisible = 0;
				            $("#group_assign_table tr:gt(0)").each(function () {
				                var row = $(this);
				                if (row.is(":visible")) {
				                    if (!reverseFilter != !filterStrategy(row, tag)) {
				                        goners = goners.add(row);
				                        //$("input:eq(1)", row).val("");
				                    } else {
				                        totalVisible++;
				                        if (keepRowStrategy != null) {
				                            keepRowStrategy(row, tag);
				                        }
				                    }
				                }
				            });
				            goners.remove();
				            var firstHeaderCell = $("#group_assign_table th:first");
				            var firstHeaderCellHtml = firstHeaderCell.html();
				            firstHeaderCell.html(firstHeaderCellHtml.substr(0, firstHeaderCellHtml.lastIndexOf(" ")) + " (" + totalVisible + ")");
				        }
				
				        // Filter on distance to given village
				        $("#defFilterDist").click(function () {
				            var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true);
				            if (!targetVillage.isValid) {
				                alert(trans.sp.defOverview.distanceToVillageNoneEntered);
				                return;
				            }
				
				            trackClickEvent("FilterDistance");
				            var reverseFilter = !($("#defFilterDistType").val() != "-1");
				            var maxDistance = parseInt($("#defFilterDistFields").val(), 10);
				
				            var isAlreadyVisible = $("#filterContext").size() == 1;
				            var distanceHeader =
				                trans.sp.defOverview.distanceToVillage.replace(
				                    "{0}",
				                    "<a href='"
				                        + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>")
				                        + targetVillage.coord + "</a>");
				
				            if (isAlreadyVisible) {
				                $("#filterContext").html(distanceHeader);
				            } else {
				                $("#group_assign_table").find("th:first").after("<th><span id=filterContext>" + distanceHeader + "</span> <img src='graphic/oben.png' class=sortDistance direction=up> <img src='graphic/unten.png' class=sortDistance direction=down></th>");
				                $(".sortDistance").click(function () {
				                    if ($(this).attr("direction") == "up") {
				                        $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) {
				                            return parseInt($(a).attr("fieldAmount"), 10) > parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1;
				                        });
				                    } else {
				                        $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) {
				                            return parseInt($(a).attr("fieldAmount"), 10) < parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1;
				                        });
				                    }
				                });
				            }
				
				            filterGroupRows(
				                function (row, tag) {
				                    var compareVillage = getVillageFromCoords(row.find("td:first").text());
				                    tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields;
				                    return tag.distance > maxDistance;
				
				                }, reverseFilter,
				                function (mainRow, tag) {
				                    mainRow.attr("fieldAmount", tag.distance);
				                    if (!isAlreadyVisible) {
				                        mainRow.find("td:first").after("<td><b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b></td>");
				                    } else {
				                        mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>");
				                    }
				                }, { distance: 0 });
				        });
				
				        // Filter on incoming attacks
				        $("#attackFilter").click(function () {
				            trackClickEvent("FilterUnderAttack");
				            filterGroupRows(function (row) {
				                return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0;
				            });
				        });
				
				        // filter on village name
				        $("#defFilterText").click(function () {
				            trackClickEvent("FilterText");
				            var compareTo = $("#defFilterTextValue").val().toLowerCase();
				            if (compareTo.length > 0) {
				                filterGroupRows(function (row) {
				                    return row.find("td:first").text().toLowerCase().indexOf(compareTo) != -1;
				                });
				            }
				        });
				
				        // filter on group names
				        $("#defFilterGroup").click(function () {
				            trackClickEvent("FilterGroupName");
				            var compareTo = $("#defFilterGroupValue").val().toLowerCase();
				            if (compareTo.length > 0) {
				                filterGroupRows(function (row) {
				                    return row.find("td:eq(4)").text().toLowerCase().indexOf(compareTo) != -1;
				                });
				            }
				        });
				
				        $("#defFilterContinent").click(function () {
				            trackClickEvent("FilterContinent");
				            var compareTo = parseInt($("#defFilterContinentText").val(), 10);
				            if (compareTo >= 0) {
				                compareTo = compareTo.toString();
				                filterGroupRows(function (row) {
				                    var villageContinent = $.trim(row.find("td:first").text()),
				                        continentStart = villageContinent.lastIndexOf(trans.tw.all.continentPrefix);
				
				                    return villageContinent.substr(continentStart + 1) === compareTo;
				                });
				            }
				        });
				
				        // filter on # groups
				        $("#defFilterAmount").click(function (){
				            trackClickEvent("FilterGroupCount");
				            var compareTo = parseInt($("#defFilterAmountText").val(), 10);
				            if (compareTo >= 0) {
				                if (!$("#defReverseFilter").is(":checked")) {
				                    filterGroupRows(
				                        function (row) {
				                            return parseInt(row.find("td:eq(1)").text(), 10) > compareTo;
				                        },
				                        false);
				                } else {
				                    filterGroupRows(
				                        function (row) {
				                            return parseInt(row.find("td:eq(1)").text(), 10) < compareTo;
				                        },
				                        false);
				                }
				            }
				        });
				
				        $("#defFilterPoints").click(function () {
				            trackClickEvent("FilterPoints");
				            var compareTo = parseInt($("#defFilterPointsText").val(), 10);
				            if (compareTo >= 0) {
				                filterGroupRows(function (row) {
				                    return parseInt(row.find("td:eq(2)").text().replace(".", ""), 10) < compareTo;
				                });
				            }
				        });
				
				        $("#defFilterFarm").click(function () {
				            trackClickEvent("FilterFarm");
				            var compareTo = parseInt($("#defFilterFarmText").val(), 10);
				            if (compareTo >= 0) {
				                filterGroupRows(function (row) {
				                    var farmValue = row.find("td:eq(3)").text();
				                    farmValue = parseInt(farmValue.substr(0, farmValue.indexOf("/")), 10);
				                    return farmValue < compareTo;
				                });
				            }
				        });
				    } catch (e) { handleException(e, "overview-groups"); }
				    //console.timeEnd("overview-groups");
				}());
            }
            // SUPPORT OVERVIEW
            else if (location.href.indexOf('type=support_detail') > -1
                || location.href.indexOf('type=away_detail') > -1) {

				(function() {
				    //console.time("overview-supportdetail");
				    try {
				        overviewTable = $("#units_table");
				        tableHandler.init("units_table", {
				            hasBottomTotalRow: true
				        });
				
				        /**
				         * true: we're on the support_detail page. false: away_detail page
				         * @type {boolean}
				         */
				        var isSupport = location.href.indexOf('type=support_detail') > -1;
				
						/**
						 * Sets the correct rowcount in the first header cell
						 */
						function setTotalCount() {
						    $("th:first", overviewTable).text(
						        trans.sp.defOverview.totalVillages.replace(
						            "{0}",
						            $("tr.units_away", overviewTable).size()));
						}
						
				
						var menu = "<table class='vis' width='100%'>";
						menu += "<tr><th width='1%' nowrap>";
						menu += "<input type=button id=defTotals value='" + trans.sp.defOverview.stackButton + "' title='" + trans.sp.defOverview.stackTooltip + "'>";
						menu += "<input type=button id=defHideEmpty value='" + trans.sp.defOverview.filterNoSupport + "' title='" + trans.sp.defOverview.filterNoSupportTooltip + "'> ";
						
						menu += "</th><th width='96%' nowrap>";
						menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>";
						if (!isSupport) {
						    menu += "&nbsp; <input type=button id=defFilterBarbarian value='" + trans.sp.defOverview.barbarianFilter + "' title='" + trans.sp.defOverview.barbarianFilterTooltip + "'>";
						} else {
						    menu += "</th><th width='1%' nowrap>";
						    menu += "<input type=text size=8 id=defFilterTotalPopValue value='" + user_data.restack.defaultPopulationFilterAmount + "'>";
						    menu += "<select id=defFilterTotalPopComparer>";
						    menu += "<option value=-1>" + trans.sp.all.less + "</option><option value=1 selected>" + trans.sp.all.more + "</option></select>";
						    menu += "<input type=button id=defFilterTotalPop value='" + trans.sp.defOverview.stackFilter + "' title='" + trans.sp.defOverview.stackFilterTooltip + "'>";
						
						    menu += "</th><th width='1%' nowrap>";
						    menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>";
						    menu += "<select id=defFilterDistType>";
						    menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>";
						    // TODO: untranslated F(ields)
						    menu += "&nbsp;F <input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + ">";
						    menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>";
						
						    menu += "</th><th width='1%' nowrap>";
						    menu += " <input type=text size=8 id=defRestackTo value=" + user_data.restack.to + "> <input type=button id=defRestack value='" + trans.sp.defOverview.stackBBCodes + "' title='" + trans.sp.defOverview.stackBBCodesTooltip + "'>";
						    //menu += "</th></tr></table>";
						}
						
						menu += "</th></tr></table>";
						menu += "<table class='vis' width='100%'><tr><th width='1%' nowrap>";
						menu += isSupport ? trans.sp.defOverview.extraFiltersSupport : trans.sp.defOverview.extraFiltersDefense;
						
						menu += "</th><th width='1%' nowrap>";
						menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.defOverview.extraFiltersReverse + "'" + (user_data.restack.filterReverse ? " checked" : "") + "> " + trans.sp.defOverview.extraFiltersInfo;
						
						menu += "</th><th width='1%' nowrap>";
						menu += "<input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + "> <input type=button id=defFilterDistance value='" + trans.sp.defOverview.distFilter2 + "'>";
						
						menu += "</th><th width='1%' nowrap>";
						menu += "&nbsp; <span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>";
						menu += "&nbsp; <img src='graphic/unit/unit_snob.png' id=filtersnob>&nbsp; <img src='graphic/unit/unit_spy.png' id=filterspy>";
						menu += "&nbsp; <img src='graphic/buildings/barracks.png' id=filterAttack>&nbsp;<img src='graphic/unit/def.png' id=filterDefense>&nbsp;<img id=filterSupport src='graphic/command/support.png'>&nbsp;";
						menu += "</span>&nbsp;&nbsp;";
						
						menu += "</th><th width='96%' nowrap>";
						menu += "<input type=text size=12 id=defFilterTextValue value=''>";
						menu += "<input type=button id=defFilterText value='" + trans.sp.defOverview.freeTextFilter + "'>";
						menu += "</th></tr></table>";
						
						overviewTable.before(menu);
						
						$("#defReverseFilter").change(function () {
						    var isChecked = $(this).is(":checked");
						    var defTrans = trans.sp.defOverview;
						    $("#unitFilterBox").find("img:eq(0)").attr("title", isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev);
						    $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev);
						    $("#unitFilterBox").find("img:eq(2)").attr("title", isChecked ? defTrans.attackFilter : defTrans.attackFilterRev);
						    $("#unitFilterBox").find("img:eq(3)").attr("title", isChecked ? defTrans.supportFilter : defTrans.supportFilterRev);
						
						    $("#unitFilterBox").find("img:eq(4)").attr("title", (isSupport ? defTrans.otherPlayerFilterFrom : defTrans.otherPlayerFilterTo).replace("{action}", isChecked ? defTrans.otherPlayerFilterShow : defTrans.otherPlayerFilterHide));
						    $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
						    $("#defFilterDistance").attr("title", defTrans.distanceFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", !isChecked ? defTrans.distanceFilterTooltipFilterTypeCloser : defTrans.distanceFilterTooltipFilterTypeFurther));
						});
						$("#defReverseFilter").change();
						// This file contains the filters on the FIRST row of the menu
						
						// UNDER ATTACK FILTER
						$("#attackFilter").click(function () {
						    trackClickEvent("FilterAttack");
						    var reverseFilter = true; // never reverse this filter!
						
						    var filterStrategy =
						        function (row) {
						            return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0;
						        };
						
						    var lastRow = $("tr:last", overviewTable).get(0);
						    var goners = $();
						    $("tr.units_away", overviewTable).each(function () {
						        var self = $(this);
						        if (!reverseFilter != !filterStrategy(self)) {
						            goners = goners.add(self);
						
						            var nextRow = self.next();
						            while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) {
						                goners = goners.add(nextRow);
						                nextRow = nextRow.next();
						            }
						        }
						    });
						    goners.remove();
						    setTotalCount();
						
						    // this is already done in the code above :)
						    //$("#defHideEmpty").click();
						
						    if (user_data.restack.calculateDefTotalsAfterFilter
						        && !$("#defTotals").is(":disabled")) {
						
						        $("#defTotals").click();
						    }
						});
						
						
						
						/**
						 * Performs a filter on the OWN villages (ie not the villages supporting the OWN villages)
						 * The 'row' parameter are the rows with class grandTotal. These are the rows that get added after (below) all
						 * supporting os rows when the total def is being calculated.
						 * @param {function} filterStrategy return a boolean to filter all rows for the OWN away. first parameter is the (jQuery) row with the OWN village
						 * @param {boolean} reverseFilter reverse the above strategy
						 * @param {function} [survivorRowStrategy] execute on all rows that are not being removed (gets passed the row and optional tag)
						 * @param {*} [tag] this value is passed onto filterStrategy and survivorRowStrategy as the second parameter (row is the first param)
						 */
						function filterMainRows(filterStrategy, reverseFilter, survivorRowStrategy, tag) {
						    if (!$("#defTotals").is(":disabled")) {
						        $("#defTotals").click();
						    }
						
						    /*var goners = $();
						    $("tr.grandTotal", overviewTable).each(function () {
						        var self = $(this),
						            prev;
						        if (!reverseFilter != !filterStrategy(self, tag)) {
						            goners = goners.add(self).add(self.next());
						
						            prev = self.prev();
						            while (!prev.hasClass("units_away")) {
						                goners = goners.add(prev);
						                prev = prev.prev();
						            }
						
						            goners = goners.add(prev);
						        } else if (survivorRowStrategy != null) {
						            prev = self.prev();
						            while (!prev.hasClass("units_away")) {
						                prev = prev.prev();
						            }
						            survivorRowStrategy(prev, tag);
						        }
						    });
						     goners.remove();
						     setTotalCount();*/
						
						    var lastRow = $("tr:last", overviewTable).get(0);
						    var goners = $();
						    $("tr.units_away", overviewTable).each(function () {
						        var self = $(this);
						        if (!reverseFilter != !filterStrategy(self, tag)) {
						            goners = goners.add(self);
						
						            var nextRow = self.next();
						            while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) {
						                goners = goners.add(nextRow);
						                nextRow = nextRow.next();
						            }
						        }
						        else if (survivorRowStrategy != null) {
						            /*prev = self.prev();
						            while (!prev.hasClass("units_away")) {
						                prev = prev.prev();
						            }*/
						            survivorRowStrategy(self, tag);
						        }
						    });
						    goners.remove();
						    setTotalCount();
						}
						
						
						
						// filter the OWN villages on less/more population (requires total calculation)
						$("#defFilterTotalPop").click(function () {
						    trackClickEvent("FilterFarm");
						    var reverseFilter = $("#defFilterTotalPopComparer").val() != "-1";
						    var compareTo = parseInt($("#defFilterTotalPopValue").val(), 10);
						
						    filterMainRows(
						        //q(row.attr("village") + "is:" + row.attr("population"));
						        function (row) { return (parseInt(row.attr("population"), 10) > compareTo); },
						        reverseFilter);
						});
						
						// filter the OWN villages on less/more distance to given coordinates (requires total calculation)
						$("#defFilterDist").click(function () {
						    var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true);
						    if (!targetVillage.isValid) {
						        alert(trans.sp.defOverview.distanceToVillageNoneEntered);
						        return;
						    }
						
						    trackClickEvent("FilterDistanceToX");
						    var reverseFilter = !($("#defFilterDistType").val() != "-1");
						    var maxDistance = parseInt($("#defFilterDistanceValue").val(), 10);
						
						    // Change text of th cell to 'distance to ' + given village
						    overviewTable.find("th:eq(1)").html(
						        trans.sp.defOverview.distanceToVillage.replace(
						            "{0}",
						            "<a href='"
						                + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>")
						                + targetVillage.coord + "</a>"));
						
						    filterMainRows(
						        function (row, tag) {
						            var compareVillage = getVillageFromCoords(row.attr("village"));
						            tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields;
						            return tag.distance > maxDistance;
						        },
						        reverseFilter,
						        function (mainRow, tag) {
						            // Adds the distance between OWN village and the user given coordinates
						            mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>");
						        },
						        { distance: 0 });
						});
						// Calculate villages that don't have x population defense
						// and create BBcodes textarea for it
						$("#defRestack").click(function () {
						    trackClickEvent("BBCodeOutput");
						    if (!$("#defTotals").attr("disabled")) {
						        $("#defTotals").click();
						    }
						
						    var restackTo = parseInt($("#defRestackTo").val(), 10);
						    var counter = 0;
						
						    var request = "";
						    $("tr.grandTotal", overviewTable).each(function () {
						        var self = $(this);
						        var total = parseInt(self.attr('population'), 10);
						        if (restackTo - total > user_data.restack.requiredDifference) {
						            var villageCoords = self.attr("village");
						            counter++;
						            request += counter + "[village]" + villageCoords + "[/village] (" + parseInt((restackTo - total) / 1000, 10) + trans.sp.defOverview.thousandSuffix + ")\n";
						        }
						    });
						
						    if ($("#textsArea").size() == 0) {
						        $(this).parent().parent().parent().parent().after(
						            "<table class='vis' width='100%'><tr>"
						                + "<td id=textsArea width='50%' valign='top'></td>"
						                + "<td id='extraTextsArea' width='50%' valign='top'>"
						                + trans.sp.defOverview.freeText
						                + "<br><textarea cols=50 rows=9></textarea></td>"
						                + "</tr></table>");
						
						        $("#textsArea").parent().after("<tr><td colspan='2'><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea></td></tr>");
						    } else {
						        $("#textsArea").html("");
						    }
						
						    var title = trans.sp.troopOverview.restackTitle
						        .replace("{to}", parseInt(restackTo / 1000, 10))
						        .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10));
						
						    $("#textsArea").append(title + "<br><textarea cols=50 rows=10 id=restackArea>" + request + "</textarea>");
						
						    $("#closeTextsArea").click(function() {
						        $("#textsArea").parent().parent().remove();
						    });
						});
						// Check all villages checkbox replacement
						$("input.selectAll").replaceWith("<input type=checkbox id=selectAllVisible>");
						$("#selectAllVisible").change(function () {
						    var isChecked = $(this).is(":checked");
						
						    $("input.village_checkbox:hidden", overviewTable).prop("checked", false);
						    $("input.village_checkbox:visible", overviewTable).prop("checked", isChecked);
						});
						
						
						// Hide all OWN rows/villages that don't have any support rows anymore
						$("#defHideEmpty").click(function () {
						    trackClickEvent("FilterEmpty");
						    var goners = $();
						    if ($("#defTotals").is(":disabled")) {
						        $("tr.units_away", overviewTable).each(function () {
						            var mainRow = $(this),
						                nextRow = mainRow.next();
						
						            if (nextRow.hasClass("grandTotal")) {
						                goners = goners.add(mainRow).add(nextRow.next()).add(nextRow);
						            }
						            else if (nextRow.hasClass("units_away")) {
						                goners = goners.add(mainRow);
						            }
						        });
						    } else {
						        $("tr.units_away", overviewTable).each(function () {
						            var mainRow = $(this),
						                nextRow = mainRow.next();
						
						            if (nextRow.hasClass("units_away")) {
						                goners = goners.add(mainRow);
						            }
						        });
						    }
						
						    goners.remove();
						    setTotalCount();
						});
						
						
						// Calculate the amount of def in each village
						// Give sensible background row colors
						// Add attributes to the grandTotal class rows 'village' (coords) and 'population'
						// Add attribute 'distance' the distance between OWN and supporting villages, in fields
						$("#defTotals").click(function () {
						    trackClickEvent("FilterTotalDef");
						    $(this).attr("disabled", true);
						    var rowColor = 0;
						    var goners = $();
						    overviewTable.find("tr.units_away").each(function () {
						        var self = $(this);
						        var firstCell = self.find("td:first");
						        var villageCoord = getVillageFromCoords(firstCell.text().replace(firstCell.find(".quickedit-label").attr("data-text"), ""));
						
						        // ensure row color swapping for each own village
						        rowColor++;
						        if (rowColor % 2 == 1) {
						            self.removeClass("row_a").addClass("row_b");
						        } else {
						            self.removeClass("row_b").addClass("row_a");
						        }
						
						        // village attribute both to .units_away and .grandTotal rows ;)
						        self.attr("village", villageCoord.coord);
						
						        var nextRow = self.next();
						        if (nextRow.hasClass("units_away")) {
						            if (user_data.restack.removeRowsWithoutSupport) {
						                goners = goners.add(self);
						            }
						        } else {
						            // calculate total support
						            var grandTotal = 0;
						            var totals = [];
						            while (nextRow.hasClass("row_a") || nextRow.hasClass("row_b")) {
						                // supporting rows loop
						                var total = 0;
						                $("td:gt(0)", nextRow).each(function (i) {
						                    // total support per supporting village
						                    var cellSelf = $(this);
						                    var cellContent = $.trim(cellSelf.text());
						                    if (!(cellContent == '0' || i >= world_data.unitsPositionSize.length)) {
						                        total += cellContent * world_data.unitsPositionSize[i];
						                        if (totals[i] == undefined) {
						                            totals[i] = parseInt(cellContent, 10);
						                        } else {
						                            totals[i] += parseInt(cellContent, 10);
						                        }
						                    }
						                });
						                grandTotal += total;
						                $("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", nextRow).text(formatNumber(total));
						
						                // print distance between own village
						                var supportedCell = $("td:first", nextRow);
						                var supportedVillage = getVillageFromCoords(supportedCell.text());
						                var distance = parseInt(getDistance(supportedVillage.x, villageCoord.x, supportedVillage.y, villageCoord.y, 'ram').fields, 10);
						                //supportedCell.html(supportedCell.html() + ' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>');
						                supportedCell.append(' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>');
						                nextRow.attr("distance", distance);
						
						                if (rowColor % 2 == 1) {
						                    nextRow.removeClass("row_a").addClass("row_b");
						                } else {
						                    nextRow.removeClass("row_b").addClass("row_a");
						                }
						
						                nextRow = nextRow.next();
						            }
						
						            // row colors for the support villages
						            if (rowColor % 2 == 1) {
						                nextRow.removeClass("row_a").addClass("row_b");
						            } else {
						                nextRow.removeClass("row_b").addClass("row_a");
						            }
						
						            var troopCells = "";
						            for (var i = 0; i < world_data.unitsPositionSize.length; i++) {
						                if (typeof totals[i] !== 'undefined') {
						                    troopCells += "<td>" + formatNumber(totals[i]) + "</td>";
						                } else {
						                    troopCells += "<td><span class=hidden>0</span></td>";
						                }
						            }
						
						            self.attr("population", grandTotal);
						            var color = getStackColor(grandTotal);
						            color = "<td style='background-color: " + color + "; border:1px solid black'>" + formatNumber(grandTotal) + "</td>";
						
						            nextRow.before("<tr class='grandTotal " + (rowColor % 2 == 1 ? "row_b" : "row_a") + "' village='" + villageCoord.coord + "' population='" + grandTotal + "'><td>&nbsp;</td><td>" + (isSupport ? trans.sp.defOverview.totalFromOtherVillages : trans.sp.defOverview.totalInOtherVillages) + "</td>" + troopCells + color + "</tr><tr height=10></tr>");
						        }
						    });
						
						    goners.remove();
						});
						// This file contains the filters on the SECOND row of the menu
						
						/**
						 * Loops over all supporting rows and removes the rows that fail the filterStrategy predicate. Where the
						 * filterMainRows function loops over the OWN villages, this one loops over all the others.
						 * @param {Function} filterStrategy gets each jQuery row that represents a supporting village passed as parameter
						 * @param {string=after} [calcDefTotalsTime] is "before" or "after". before if it uses row attributes set by #defTotals
						 */
						function filterTable(filterStrategy, calcDefTotalsTime) {
						    if (typeof calcDefTotalsTime === 'undefined') {
						        calcDefTotalsTime = "after";
						    }
						    if (calcDefTotalsTime === "before" && !$("#defTotals").is(":disabled")) {
						        $("#defTotals").click();
						    }
						    var totalDefCalced = $("#defTotals").is(":disabled");
						
						    var reverseFilter = $("#defReverseFilter").is(":checked");
						    var goners = $();
						    $("tr", overviewTable).slice(1).each(function () {
						        var self = $(this);
						        if ((totalDefCalced && self.attr("distance"))
						            || (!totalDefCalced && (self.hasClass("row_a") || self.hasClass("row_b")))) {
						
						            if (!reverseFilter != !filterStrategy(self)) {
						                goners = goners.add(self);
						            }
						        }
						    });
						    goners.remove();
						    setTotalCount();
						    if (user_data.restack.autohideWithoutSupportAfterFilter) {
						        $("#defHideEmpty").click();
						    }
						
						    if (user_data.restack.calculateDefTotalsAfterFilter
						        && calcDefTotalsTime === "after"
						        && !$("#defTotals").is(":disabled")) {
						
						        $("#defTotals").click();
						    }
						}
						
						
						
						
						
						// NOBLES and SCOUTS
						$("#filtersnob, #filterspy").click( function () {
						    trackClickEvent("FilterSnobOrSpy");
						    var position = $.inArray($(this).attr("id").substr(6), world_data.units) + 1;
						    filterTable(function (row) {
						        return row.find("td").eq(position).text() != "0";
						    });
						});
						
						// OTHER PLAYERS SUPPORT
						$("#filterSupport").click( function () {
						    trackClickEvent("FilterSupport");
						    filterTable(function (row) {
						        return row.find("td:first a").length != 2;
						    });
						});
						
						// DEFENSIVE & OFFENSIVE UNITS
						$("#filterAttack, #filterDefense").click( function () {
						    trackClickEvent("FilterOffOrDef");
						    var unitArray = $(this).attr('id') == "filterDefense" ? world_data.units_def : world_data.units_off;
						    filterTable(function (row) {
						        var hideRow = false;
						        $("td:gt(0)", row).each(function (i) {
						            if (world_data.units[i] != undefined
						                && world_data.units[i] != "heavy"
						                && parseInt($(this).text(), 10) > 0
						                && $.inArray(world_data.units[i], unitArray) > -1) {
						
						                hideRow = true;
						                return false;
						            }
						        });
						
						        return hideRow;
						    });
						});
						
						/// BARBARIAN VILLAGES filter
						$("#defFilterBarbarian").click( function () {
						    trackClickEvent("FilterBarbarian");
						    filterTable(function (row) {
						        var text = row.find("td:first").text();
						        return text.match(/\(---\)\s+\(F\d+\)$/); // Unlocalized F(ields) string
						    });
						});
						
						// TEXT FILTER
						$("#defFilterText").click( function () {
						    trackClickEvent("FilterText");
						    var compareTo = $("#defFilterTextValue").val().toLowerCase();
						    if (compareTo.length > 0)
						        filterTable(function (row) {
						            return row.text().toLowerCase().indexOf(compareTo) == -1;
						        });
						});
						
						// DISTANCE between OWN and supporting village
						$("#defFilterDistance").click(function () {
						    trackClickEvent("FilterDistance");
						    var maxDistance = $("#defFilterDistanceValue").val();
						    filterTable(
						        function (row) {
						            var distance = $(row).attr("distance");
						            return (distance != '' && parseInt(distance, 10) < maxDistance);
						        },
						        "before");
						});
				
				    } catch (e) { handleException(e, "overview-supportdetail"); }
				    //console.timeEnd("overview-supportdetail");
				}());
            }
			// COMMANDS OVERVIEW
            else if (location.href.indexOf('mode=commands') > -1) {
				(function() {
				    //console.time("overview-commands");
				    try {
				        overviewTable = $("#commands_table");
				        tableHandler.init("commands_table", {
				            hasBottomTotalRow: true
				        });
				
				        var commandListType = getQueryStringParam("type");
				
				        var menu = "";
				        menu += "<table class=vis width='100%'>";
				        menu += "<tr>";
				        if (location.href.indexOf('type=all') > -1 || location.href.indexOf('&type=') == -1) {
				            menu += "<th width='1%'>";
				            menu += "<input type=button id=filterReturning value='" + trans.sp.commands.filterReturn + "' title=\"" + trans.sp.commands.filterReturnTooltip + "\">";
				            menu += "</th>";
				        }
				
				        menu += "<th width='1%' nowrap>";
				        menu += "<input type=checkbox id=sortSum " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.commands.totalRows + " ";
				        var isSupport = location.href.indexOf('type=support') > -1;
				        menu += "<input type=button id=sortIt value='" + trans.sp.commands.group + "'>";
				
				        menu += "</th><th width='98%'>";
				
				        menu += "<input type=button id=BBCodeOutput value='" + trans.sp.commands.bbCodeExport + "' title='" + trans.sp.commands.bbCodeExportTooltip + "'>";
				
				        if (commandListType !== "attack" && commandListType !== "return") {
				            menu += "&nbsp; &nbsp;";
				            menu += "<input type=text id=supportPlayerName size=>&nbsp;";
				            menu += "<input type=button id=supportPlayerExport value='" + trans.sp.commands.supportPlayerExport + "' title='" + trans.sp.commands.supportPlayerExportTooltip + "'>";
				        }
				
				        menu += "</th></tr></table>";
				
				        // second row
				        menu += "<table><tr><th width='1%' nowrap>";
				        menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
				
				        menu += "</th><th width='1%' nowrap>";
				        menu += "<span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>";
				        menu += "&nbsp; <img src='graphic/unit/unit_snob.png' id=filtersnob>&nbsp; <img src='graphic/unit/unit_spy.png' id=filterspy>&nbsp; <img src='graphic/face.png' id=filterFake>&nbsp;";
				        menu += "&nbsp; </span>";
				
				        menu += "</th><th width='1%' nowrap>";
				        menu += "<input type=text size=12 id=defFilterTextValue value=''>";
				        menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>";
				
				        menu += "</th><th width='97%' nowrap>";
				        menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
				
				        menu += "</th></tr>";
				        menu += "</table>";
				        $("#commands_table").before(menu);
				
				        $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>");
				        var selectAllCheckboxes = function() {
				            var isChecked = $("#selectAll").is(":checked");
				            $("#commands_table tr:visible").find(":checkbox").prop("checked", isChecked);
				        };
				        $("#selectAll").change(selectAllCheckboxes);
				
				        var offsetToUnits = 3;
				
				        $("#defReverseFilter").change( function () {
				            var isChecked = $(this).is(":checked");
				            var defTrans = trans.sp.commands;
				            $("#unitFilterBox").find("img:eq(0)").attr("title", !isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev);
				            $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev);
				            $("#unitFilterBox").find("img:eq(2)").attr("title", !isChecked ? defTrans.fakeFilter : defTrans.fakeFilterRev);
				
				            $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse);
				
				            $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
				        });
				
				        $("#defReverseFilter").change();
				        var hasGrouped = false;
				
				        // generate bb code or JSON (for player os) export
				        $("#BBCodeOutput,#supportPlayerExport").click(function () {
				            trackClickEvent($(this).attr("id"));
				            var villages = [];
				            var request = {};
				            var filter = hasGrouped ? "tr.command" : "tr:gt(0)";
				            $("#commands_table " + filter).filter(":visible").each(function () {
				                var row = $(this);
				                var cells = $("td", row);
				                var firstCell = cells.first();
				                var commandType = firstCell.find("img:first").attr("src");
				
				                if (typeof commandType !== 'undefined'
				                    && commandType.indexOf("command/cancel.png") == -1
				                    && commandType.indexOf("command/other_back.png") == -1
				                    && commandType.indexOf("command/back.png") == -1
				                    && commandType.indexOf("command/return.png") == -1) {
				
				                    // We get the village coords from the description of the command
				                    // Meaning if the user changes the name to "blabla" that we can't parse it
				                    var village = getVillageFromCoords($.trim(firstCell.text()));
				                    //assert(village.isValid, $.trim(firstCell.text()) + " could not be converted to village");
				                    if (village.isValid) {
				                        if (request[village.coord] == undefined) {
				                            request[village.coord] = { village: village.coord, attacks: [], hasSupport: false };
				                            villages.push(village.coord);
				                        }
				
				                        var unitsSent = {};
				                        $.each(world_data.units,
				                            function (i, val) {
				                                unitsSent[val] = parseInt(cells.eq(offsetToUnits + i).text(), 10);
				                            });
				
				                        var isSupport = false;
				                        if (commandListType == "support") {
				                            isSupport = true;
				                        }
				                        else if (commandListType == "attack") {
				                            isSupport = false;
				                        } else {
				                            isSupport = cells.first().has("img[src*='command/support.png']").size() == 1;
				                        }
				
				                        request[village.coord].hasSupport = isSupport;
				                        request[village.coord].attacks.push({
				                            isSupport: isSupport,
				                            units: unitsSent,
				                            unitsString: buildAttackString(null, unitsSent, null, isSupport, user_data.command.bbCodeExport.requiredTroopAmount),
				                            commandName: isSupport ? $.trim(firstCell.text()) : "",
				                            commandId: isSupport ? firstCell.find(":checkbox").attr("value") : null,
				                            arrivalDate: getDateFromTodayTomorrowTW(cells.eq(2).text())
				                        });
				                    }
				                }
				            });
				
				            var exportWidgets = [];
				            if ($(this).attr("id") === "BBCodeOutput") {
				                var requestsPer500 = [""];
				                var requestComposed = "";
				                for (var i = 0; i < villages.length; i++) {
				                    var currentVillage = request[villages[i]];
				                    var currentText = "";
				                    currentText += "[spoiler][code]";
				                    var attackCount = 0;
				                    var supportCount = 0;
				                    var lastAttack = null;
				                    var largestAttack = 0;
				                    var totalPop = 0;
				                    for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
				                        var currentAttack = currentVillage.attacks[attackId];
				                        if (currentAttack.isSupport) {
				                            supportCount++;
				                            $.each(world_data.units, function (i, val) {
				                                totalPop += currentAttack.units[val] * world_data.unitsPositionSize[i];
				                            });
				                        } else {
				                            attackCount++;
				                            if (lastAttack == null || lastAttack < currentAttack.arrivalDate) {
				                                lastAttack = currentAttack.arrivalDate;
				                            }
				                        }
				                        if (largestAttack < currentAttack.unitsString.length) {
				                            largestAttack = currentAttack.unitsString.length;
				                        }
				                    }
				
				                    for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
				                        var currentAttack = currentVillage.attacks[attackId];
				                        currentText += currentAttack.unitsString;
				                        var extraTabs = (largestAttack - currentAttack.unitsString.length) / 1;
				                        if (Math.ceil(extraTabs) == extraTabs) {
				                            extraTabs = Math.ceil(extraTabs);
				                        }
				                        for (var tabs = 0; tabs < extraTabs + 1; tabs++) {
				                            currentText += " ";
				                        }
				
				                        currentText += "\t" + twDateFormat(currentAttack.arrivalDate, true) + "\n";
				                    }
				                    currentText += "[/code][/spoiler]\n";
				
				                    var headerTemplate;
				                    if (!currentVillage.hasSupport && attackCount !== 0) {
				                        headerTemplate = trans.sp.commands.exportAttackHeader;
				                    }
				                    else if (currentVillage.hasSupport && attackCount === 0) {
				                        headerTemplate = trans.sp.commands.exportDefenseHeader;
				                    } else {
				                        headerTemplate = trans.sp.commands.exportCompleteHeader;
				                    }
				
				                    requestComposed +=
				                        headerTemplate
				                            .replace("{#}", attackCount)
				                            .replace("{support#}", supportCount)
				                            .replace("{totalStack}", formatNumber(totalPop))
				                            .replace("{lastAttack}", lastAttack !== null ? twDateFormat(lastAttack, true) : "")
				                            .replace("{village}", "[village]" + villages[i] + "[/village]")
				                            + "\n " + currentText;
				
				                    // splits per 500 [ characters (limit in TW)
				                    var amountBracket = requestsPer500[requestsPer500.length - 1].match(/\[/g);
				                    if (amountBracket != null && (requestComposed.match(/\[/g).length + amountBracket.length > server_settings.allowedSquareBrackets)) {
				                        requestsPer500.push("");
				                    }
				                    requestsPer500[requestsPer500.length - 1] += requestComposed;
				                    requestComposed = "";
				                }
				
				                for (i = 0; i < requestsPer500.length; i++) {
				                    exportWidgets.push("<textarea cols=80 rows=10 class=restackArea>" + requestsPer500[i] + "</textarea>");
				                }
				
				            } else {
				                // JSON export for player support
				                var exportAttacks = [],
				                    playerName = $.trim($("#supportPlayerName").val()),
				                    filter = playerName.length === 0
				                        ? function(attackString) { return true; }
				                        : function(attackString) { return attackString.indexOf(playerName) !== -1 };
				
				                for (var i = 0; i < villages.length; i++) {
				                    var currentVillage = request[villages[i]];
				
				                    if (currentVillage.hasSupport) {
				                        for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
				                            var currentAttack = currentVillage.attacks[attackId];
				                            if (currentAttack.isSupport && filter(currentAttack.commandName)) {
				                                exportAttacks.push({
				                                    commandName: currentAttack.commandName,
				                                    commandId: currentAttack.commandId
				                                });
				                                /*q(villages[i]);
				                                q(currentVillage)
				                                q(currentAttack);
				                                q("---------------------");*/
				                            }
				                        }
				                    }
				                }
				
				                if (exportAttacks.length > 0) {
				                    exportWidgets.push("<textarea style='width: 96%' rows=10 class=restackArea>" + JSON.stringify(exportAttacks, null, 4) + "</textarea>");
				                } else {
				                    alert(trans.sp.commands.exportNone);
				                }
				            }
				
				            if (exportWidgets.length > 0) {
				                if ($("#textsArea").size() == 0) {
				                    $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=3></td></tr>");
				                } else {
				                    $("#textsArea").html("");
				                }
				                for (var i = 0; i < exportWidgets.length; i++) {
				                    $("#textsArea").append(exportWidgets[i]);
				                }
				                $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
				                $("#closeTextsArea").click(function() {
				                    $("#textsArea").parent().remove();
				                });
				            }
				        });
				
				        function filterCommandRows(filterStrategy) {
				            // return true to hidethe row; false keep row visible (without reverse filter checkbox)
				            var reverseFilter = $("#defReverseFilter").is(":checked");
				            var goners = $();
				            var filter = hasGrouped ? "tr.command" : "tr:gt(0)";
				            $("#commands_table " + filter).filter(":visible").each(function () {
				                if ($("th", this).size() != 0) {
				                    // don't do anything anymore when on the total row
				                    return;
				                }
				                if (!reverseFilter != !filterStrategy($(this))) {
				                    goners = goners.add($(this));
				                    $("input:eq(1)", this).val("");
				                }
				            });
				            goners.remove();
				
				            // Show totals
				            var amountOfCommandos = $("#commands_table " + filter).size();
				            if (hasGrouped) {
				                $("#commands_table tr.sumLine").hide();
				            } else {
				                amountOfCommandos--;
				            }
				
				            $("#commands_table th:first").text(trans.sp.commands.tableTotal.replace("{0}", amountOfCommandos));
				            $("#amountOfAttacks").text(amountOfCommandos);
				            if ($("#amountOfAttacks").size() == 1) {
				                $("#amountOfTargets").val("???");
				            }
				
				            $("#commands_table tr").not(":visible").find(":checkbox").prop("checked", false);
				        }
				
				        // Filter sent back, returning and cancelled commands
				        $("#filterReturning").click(function () {
				            $(this).attr("disabled", "disabled");
				            trackClickEvent("FilterReturning");
				            filterCommandRows( function (row) {
				                var firstCellImage = $("td:first img:first", row).attr("src");
				                return firstCellImage.indexOf("command/other_back.png") != -1
				                    || firstCellImage.indexOf("command/back.png") != -1
				                    || firstCellImage.indexOf("command/return.png") != -1
				                    || firstCellImage.indexOf("command/cancel.png") != -1;
				            });
				        });
				
				        $("#defFilterText").click(function () {
				            trackClickEvent("FilterText");
				            var compareTo = $("#defFilterTextValue").val().toLowerCase();
				            if (compareTo.length > 0) {
				                filterCommandRows(function (row) {
				                    return row.text().toLowerCase().indexOf(compareTo) == -1;
				                });
				            }
				        });
				
				        $("#filterspy").click(function () {
				            trackClickEvent("FilterSpy");
				            var position = $.inArray($(this).attr("id").substr(6), world_data.units);
				            filterCommandRows(function (row) {
				                if (row.find("td").eq(position + offsetToUnits).text() == "0") {
				                    return false;
				                }
				                var totalScout = row.find("td").eq(position + offsetToUnits).text();
				
				                var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")");
				                for (var i = 0; i < world_data.units.length; i++) {
				                    cell = cell.next();
				                    if (totalScout < cell.text()) {
				                        return false;
				                    }
				                }
				                return true;
				            });
				        });
				
				        $("#filtersnob").click(function () {
				            trackClickEvent("FilterSnob");
				            var position = $.inArray($(this).attr("id").substr(6), world_data.units) + offsetToUnits;
				            filterCommandRows(function (row) {
				                return row.find("td").eq(position).text() == "0";
				            });
				        });
				
				        $("#filterFake").click(function () {
				            trackClickEvent("FilterFake");
				            var maxPop = user_data.command.filterFakeMaxPop;
				            filterCommandRows(function (row) {
				                var total = 0;
				                var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")");
				                for (var i = 0; i < world_data.units.length; i++) {
				                    cell = cell.next();
				                    total += parseInt(cell.text(), 10);
				
				                    // An attack with a noble is (almost) never a fake:
				                    if (i == world_data.units.length - 1 && cell.text() != "0") {
				                        return false;
				                    }
				
				                    if (total > maxPop) {
				                        return false;
				                    }
				                }
				                return true;
				            });
				        });
				
				        $("#defFilterContinent").click(function () {
				            trackClickEvent("FilterContinent");
				            var continent = parseInt($("#defFilterContinentText").val(), 10);
				            if (!isNaN(continent)) {
				                filterCommandRows(function (row) {
				                    var village = getVillageFromCoords(row.find("td:first").text());
				                    var village2 = getVillageFromCoords(row.find("td:eq(1)").text());
				                    if (!village.isValid || !village2.isValid) {
				                        return true;
				                    }
				                    return village.continent() != continent && village2.continent() != continent;
				                });
				            }
				        });
				
				        // Sort/group incoming attacks
				        $("#sortIt").click(function () {
				            trackClickEvent("Sort");
				            hasGrouped = true;
				            var newTable = "";
				            var targets = [];
				            var amountOfCommandos = 0;
				            var sum = $('#sortSum').is(':checked');
				            $("#filterReturning").attr("disabled", true);
				
				            $("#commands_table").find("tr:gt(0)").filter(":visible").each(function () {
				                var target = $.trim($(".quickedit-label", this).text());
				                var village = getVillageFromCoords(target);
				                if (village.isValid) {
				                    amountOfCommandos++;
				                    if (targets[village.coord] == undefined) {
				                        targets.push(village.coord);
				                        targets[village.coord] = new Array();
				                    }
				                    targets[village.coord].push($(this));
				                }
				            });
				
				            var mod = 0;
				            if (isSupport) {
				                $.each(targets, function (i, v) {
				                    mod++;
				                    var amount = 0;
				                    var totalDef = new Array();
				                    totalDef['pop'] = 0;
				                    $.each(world_data.units, function (index, value) { totalDef[value] = 0; });
				
				                    $.each(targets[v], function (index, value) {
				                        var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1];
				                        newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>";
				                        amount++;
				
				                        var unitAmounts = $("td:gt(2)", value);
				                        $.each(world_data.units, function (iUnit, vUnit) {
				                            var amount = parseInt(unitAmounts.eq(iUnit).html(), 10);
				                            if (amount == 1) {
				                                totalDef[vUnit] = amount;
				                            } else {
				                                totalDef[vUnit] += amount;
				                            }
				                            totalDef['pop'] += amount * world_data.unitsSize['unit_' + vUnit];
				                        });
				                    });
				
				                    if (sum) {
				                        newTable += "<tr class='sumLine'><td align=right colspan=3><b>" + trans.sp.commands.totalRowsText.replace("{0}", amount).replace("{1}", formatNumber(totalDef['pop'])) + "&nbsp;</b></td>";
				                        $.each(world_data.units, function (iUnit, vUnit) {
				                            newTable += "<td>" + (totalDef[vUnit] == 0 ? "&nbsp;" : formatNumber(totalDef[vUnit])) + "</td>";
				                        });
				                        newTable += "</tr>";
				                    }
				                });
				            } else {
				                // attacks (meaning: no support commands)
				                $.each(targets, function (i, v) {
				                    mod++;
				                    var amount = 0;
				                    var lastArrival = '';
				                    $.each(targets[v], function (index, value) {
				                        var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1];
				
				                        var currentArrival = $(value).find("td:eq(2)").text();
				                        if (lastArrival == currentArrival) {
				                            // Don't show when it's on the same second
				                            // Only practical on full second worlds really
				                            newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>";
				                            $(this).find("td").each(function (i) {
				                                if (i == 2) {
				                                    newTable += "<td>&nbsp;</td>";
				                                }
				                                else if ($(this).text() == 0) {
				                                    newTable += "<td class=hidden>0</td>";
				                                } else {
				                                    newTable += "<td>" + $(this).html() + "</td>";
				                                }
				                            });
				                            newTable += "</tr>";
				                        }
				                        else {
				                            newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>";
				                        }
				                        lastArrival = currentArrival;
				                        amount++;
				                    });
				
				                    if (sum) {
				                        newTable += "<tr class='sumLine'><td align=right colspan=" + (3 + world_data.units.length) + ">" + amount + "&nbsp;</td></tr>";
				                    }
				                });
				            }
				
				            var menu = $("#commands_table tr").first().html(),
				                totalRow = $("#commands_table tr:last");
				            $("#commands_table").html("<table id='commands_table' class='vis'>" + menu + newTable + totalRow.outerHTML() + "</table>");
				            $("#selectAll").change(selectAllCheckboxes);
				
				            // total number of attacks
				            if ($("#amountOfAttacks").size() == 0) {
				                var totalDesc = (isSupport ? trans.sp.commands.totalSupport : trans.sp.commands.totalAttack);
				                var totalVillagesDesc = isSupport ? trans.sp.commands.totalVillagesSupport : trans.sp.commands.totalVillagesAttack;
				                var pageSize = $("input[name='page_size']");
				                if (pageSize.size() == 0) {
				                    pageSize = $("input[type='submit']:last");
				                    pageSize.after("<table class=vis><tr class='row_a'><th>" + totalVillagesDesc + "</th><td><input type=text size=5 value=" + targets.length + " id=amountOfTargets></td></tr><tr class='row_a'><th>" + totalDesc + ":</th><td id='amountOfAttacks'>" + amountOfCommandos + "</td></tr></table>");
				                } else {
				                    pageSize[0].id = "amountOfTargets";
				                    pageSize.parent().prev().text(totalVillagesDesc);
				                    pageSize = pageSize.val(targets.length).parent().parent().parent();
				                    pageSize.append('<tr><th colspan=2>' + totalDesc + ':</th><td id="amountOfAttacks">' + amountOfCommandos + '</td></tr>');
				                }
				            } else {
				                $("#amountOfTargets").val(targets.length);
				                $("#amountOfAttacks").text(amountOfCommandos);
				            }
				        });
				    } catch (e) { handleException(e, "overview-commands"); }
				    //console.timeEnd("overview-commands");
				}());
            }
			// INCOMINGS OVERVIEW
            else if (location.href.indexOf('mode=incomings') > -1) {
				(function() {
				    //console.time("overview-incomings");
				    try {
						overviewTable = $("#incomings_table");
						tableHandler.init("incomings_table", {
						    hasBottomTotalRow: getQueryStringParam("subtype") !== "supports"
						});
						
						var table = {
						    /**
						     * Quick sort adds extra rows with the .total class
						     */
						    hasTotalRows: false,
						    /**
						     * Some buttons add extra columns
						     */
						    newColumns: {
						        before: 0,
						        after: 0
						    },
						    getColspan: function() {
						        return 7 + this.newColumns.before + this.newColumns.after;
						    },
						    /**
						     * Remove the total rows so that other filters can operate again
						     */
						    fixTable: function() {
						        if (this.hasTotalRows === true) {
						            overviewTable.find("tr.total").remove();
						            this.hasTotalRows = false;
						        }
						    },
						    getVillageRows: function() {
						        var rows = overviewTable.find("tr:gt(0)");
						        if (tableHandler.settings.hasBottomTotalRow) {
						            rows = rows.not("tr:last");
						        }
						        return rows;
						    },
						    /**
						     * Set the table total rows count correctly
						     * @param {number} rowCount
						     * @param {number} [villagesTargeted]
						     */
						    setTotals: function(rowCount, villagesTargeted) {
						        var amountOfCommandsHeaderCell = $("tr:first", overviewTable).find("th:first"),
						            amountOfRows = $("#amountOfRows");
						
						        assert(amountOfCommandsHeaderCell.length === 1, "couldn't find the command headercell");
						        amountOfCommandsHeaderCell.html(amountOfCommandsHeaderCell.html().replace(/\(\d+\)/, "(" + rowCount + ")"));
						
						        if (typeof villagesTargeted !== "undefined") {
						            if (amountOfRows.size() === 0) {
						                var pageSize = $("input[name='page_size']");
						                pageSize.parent().prev().text(trans.sp.commands.totalVillagesAttack);
						                pageSize = pageSize.attr("id", "villagesTargeted").parent().parent().parent();
						                pageSize.append('<tr><th colspan=2>' + trans.sp.incomings.amount + '</th><td id="amountOfRows">' + rowCount + '</td></tr>');
						            } else {
						                $("#amountOfRows").text(villagesTargeted);
						                $("#villagesTargeted").val(villagesTargeted);
						            }
						        }
						    }
						};
				
						var columnsToFilterCount = 5;
						
						// build sangu menu
						var menu = "";
						menu += "<table width='100%' class='vis' id='sangu_menu'>";
						menu += "<tr><th width='1%'>";
						menu += "<input type=button id=sortIt value='" + trans.sp.incomings.dynamicGrouping + "' title='" + trans.sp.incomings.dynamicGroupingTooltip + "'>";
						menu += "</th><th width='1%' nowrap>";
						menu += "<input type=checkbox id=sortShowTotalRow " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.incomings.summation + " ";
						menu += "<input type=button id=sortQuick value='" + trans.sp.incomings.fastGrouping + "' title='" + trans.sp.incomings.fastGroupingTooltip + "'>";
						menu += "</th><th width='1%'>";
						
						menu += "<input type=button id=sortByAttackId value='" + trans.sp.incomings.sortByAttackId + "' title='" + trans.sp.incomings.sortByAttackIdTooltip + "'>";
						
						menu += "</th><th width='96%'>";
						menu += "<input type=button id=filterAttack value='" + trans.sp.incomings.showNewIncomings + "'>";
						
						menu += "</th><th width='1%' nowrap>";
						menu += "<input type=button id=commandsImport value='" + trans.sp.incomings.commandsImport + "' title='" + trans.sp.incomings.commandsImportTooltip + "'>";
						menu += "</th></tr>";
						menu += "</table>";
						
						// second row
						menu += "<table width='100%' class=vis>";
						menu += "<tr><th width='1%' nowrap>";
						
						menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
						menu += "</th>";
						
						// generate one input field/button filter with a select for the first cells
						var defaultColumnFilters = (function() {
						    var headerCells = $("tr:first th", overviewTable),
						        cols = [],
						        headerCellText;
						
						    for (i = 0; i < columnsToFilterCount; i++) {
						        headerCellText = headerCells.eq(i).text();
						        if (headerCellText.indexOf(" ") !== -1) {
						            headerCellText = $.trim(headerCellText.substr(0, headerCellText.indexOf(" ")));
						        }
						        cols.push(headerCellText);
						    }
						    return cols;
						}());
						
						/**
						* builds a textinput+select+button filter that filters rows based on table column index
						*/
						function buildColumnFilter() {
						    var i,
						        defualtIndex = pers.get("incomingsColumnFilterIndex"),
						        menu = "<th width='99%' nowrap>";
						
						    menu += "<input type='text' size='20' id='filterColumnValue'>";
						    menu += "<select id='filterColumnIndex'>";
						    for (i = 0; i < defaultColumnFilters.length; i++) {
						        menu += "<option value='" + i + "'"
						            + (defualtIndex == i ? " selected" : "") + ">"
						            + defaultColumnFilters[i] + "</option>";
						    }
						    menu += "</select>";
						    menu += "<input type='button' id='filterColumn' value='"
						        + trans.sp.incomings.filterColumnButton + "'"
						        + "'>";
						    menu += "</th>";
						    return menu;
						}
						
						menu += buildColumnFilter();
						
						//menu += "<th width='97%' nowrap>";
						//menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
						//menu += "</th></tr>";
						
						
						menu += "</table>";
						overviewTable.before(menu);
						
						$("#filterColumnIndex").change(function() {
						    pers.set("incomingsColumnFilterIndex", $("#filterColumnIndex").val());
						});
						
						// switch tooltips on reverse filter checkbox change
						$("#defReverseFilter").change( function () {
						    var isChecked = $(this).is(":checked"),
						        overviewTrans = trans.sp.incomings;
						
						    //$("#").attr("title", isChecked ? overviewTrans.continentFilterTooltip : overviewTrans.continentFilterTooltipReverse);
						
						    $("#filterColumn").attr(
						        "title",
						        overviewTrans.filterColumnButtonTooltip.replace(
						            "{type}",
						            isChecked ? overviewTrans.filterColumnButtonTooltipHide : overviewTrans.filterColumnButtonTooltipShow));
						}).change();
						
						
						// select all checkbox
						$("#select_all").replaceWith("<input type='checkbox' id='selectAll'>");
						$("#selectAll").change(function() {
						    var isChecked = $("#selectAll").is(":checked");
						    $("tr", overviewTable).find(":checkbox").prop("checked", isChecked);
						});
						// IMPORT os exported by other player
						$("#commandsImport").click(function() {
						    if ($("#textsArea").size() == 0) {
						        $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>");
						        $("#textsArea").append(
						            "<textarea cols=80 rows=10 id=commandImportText></textarea>"
						                + "<br>"
						                + "<input type=button value='" + trans.sp.incomings.commandsImport + "' id=commandsImportReal>"
						                + "<input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
						
						        $("#closeTextsArea").click(function() {
						            $("#textsArea").parent().remove();
						        });
						
						        $("#commandsImportReal").click(function() {
						            var commandsToImport;
						            try {
						                commandsToImport = JSON.parse($("#commandImportText").val());
						                var test = commandsToImport[0].commandName;
						            }
						            catch (e) {
						                alert(trans.sp.incomings.commandsImportError);
						            }
						
						            var amountReplaced = 0,
						                commandsSent = [],
						                i;
						
						            for (i = 0; i < commandsToImport.length; i++) {
						                commandsSent[commandsToImport[i].commandId] = commandsToImport[i].commandName;
						            }
						
						            table.getVillageRows().each(function () {
						                var firstCell = $("td:first", this),
						                    commandId = firstCell.find(":input:first").attr("name");
						
						                //q("inputfield: " + firstCell.find(":input:first").length);
						                //q("commandId = " + commandId + " in cell: " + firstCell.text());
						
						                //assert(commandId, "couldn't find command id inputfield");
						                //assert(commandId.indexOf("command_ids") === 0, "inputfields have been renamed");
						                commandId = parseInt(commandId.match(/\d+/)[0], 10);
						                if (typeof commandsSent[commandId] !== 'undefined') {
						                    var inputField = $(':input[id^="editInput"]', firstCell);
						                    //assert(inputField.length === 1, "couldn't find the inputfield");
						                    inputField.val(commandsSent[commandId]);
						                    inputField.next().click();
						
						                    amountReplaced++;
						                }
						            });
						
						            alert(trans.sp.incomings.commandsImportSuccess
						                .replace("{replaced}", amountReplaced)
						                .replace("{total}", commandsToImport.length));
						        });
						    }
						});
				
						// Sort by attack id (and add extra column)
						$("#sortByAttackId").click(function() {
						    $(this).attr("disabled", true);
						    table.fixTable();
						    table.newColumns.after += 2;
						
						    var diffGroups = user_data.incomings.attackIdDescriptions;
						    function getFancyAttackIdDiffDescription(diff) {
						        var i;
						        for (i = 0; i < diffGroups.length; i++) {
						            if (diff < diffGroups[i].minValue) {
						                return diffGroups[i].text;
						            }
						        }
						
						        return user_data.incomings.attackIdHigherDescription;
						    }
						
						    // new column in header
						    tableHandler.overviewTable.find("tr:first").append("<th>"+trans.sp.incomings.attackId+"</th><th>"+trans.sp.incomings.attackIdDifference+"</th>");
						
						    var rows = table.getVillageRows();
						    rows.sortElements(function (rowA, rowB) {
						        var a = $("input:first", rowA).attr("name").match(/\d+/)[0];
						        var b = $("input:first", rowB).attr("name").match(/\d+/)[0];
						        //q($("input:first", rowA).attr("name") + "=>" + a);
						        return parseInt(a, 10) > parseInt(b, 10) ? 1 : -1;
						    });
						
						    var previousRowAttackId = 0;
						    rows.each(function() {
						        var attackId = parseInt($(this).find("input:first").attr("name").match(/\d+/)[0], 10),
						            diff = 0,
						            diffDescription = "&nbsp;";
						
						        if (previousRowAttackId != 0) {
						            diff = Math.abs(attackId - previousRowAttackId);
						            diffDescription = getFancyAttackIdDiffDescription(diff);
						        }
						        previousRowAttackId = attackId;
						
						        $(this).append("<td align=right>"+attackId+"</td><td>"+diffDescription+"</td>");
						    });
						});
						
						// QUICK sort: performs faster but also freezes the screen (ie no countdowns)
						// --> This might also be good in case the page is refreshing too often otherwise
						$("#sortQuick").click(function () {
						    trackClickEvent("SortQuick");
						    table.fixTable();
						    table.hasTotalRows = true;
						
						    var newTable = "";
						    var targets = [];
						    var commandCounter = 0;
						    var addTotalRow = $('#sortShowTotalRow').is(':checked');
						
						    table.getVillageRows().each(function () {
						        var target = $("td:eq(1)", this).text();
						        var village = getVillageFromCoords(target);
						        if (village.isValid) {
						            commandCounter++;
						            if (targets[village.coord] == undefined) {
						                targets.push(village.coord);
						                targets[village.coord] = [];
						            }
						            targets[village.coord].push($(this));
						        }
						    });
						
						    var mod = 0;
						    $.each(targets, function (i, v) {
						        mod++;
						        var rowColor = "row_" + (mod % 2 == 0 ? 'b' : 'a');
						        var amount = 0;
						        $.each(targets[v], function (index, row) {
						            var villageId = row.find("td:eq(1) a:first").attr("href").match(/village=(\d+)/)[1];
						            newTable += "<tr class='nowrap " + rowColor + "'"
						                + (villageId == game_data.village.id ? " selected" : "") + ">"
						                + row.html() + "</tr>";
						            amount++;
						        });
						
						        if (addTotalRow) {
						            if (amount === 1) {
						                newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + ">&nbsp;</td></tr>";
						            } else {
						                newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + "><b>" + trans.sp.incomings.amount + "&nbsp; " + amount + "</b>&nbsp; &nbsp;</td></tr>";
						            }
						        }
						    });
						
						    var menu = $("tr:first", overviewTable).html();
						    var totalRow = $("tr:last", overviewTable).html();
						    overviewTable.html("<table id='incomings_table' class='vis'>" + menu + newTable + totalRow + "</table>");
						
						    table.setTotals(commandCounter, targets.length);
						});
						
						
						
						
						
						// DYNAMIC sort incoming attacks
						$("#sortIt").click(function () {
						    table.fixTable();
						    trackClickEvent("Sort");
						
						    var rows = table.getVillageRows();
						    rows.sortElements(function (a, b) {
						        a = getVillageFromCoords($("td:eq(1)", a).text());
						        b = getVillageFromCoords($("td:eq(1)", b).text());
						
						        return (a.x * 1000 + a.y) > (b.x * 1000 + b.y) ? 1 : -1;
						    });
						
						    var amountOfVillages = 0;
						    var current = "";
						    rows.each(function () {
						        var village = $("td:eq(1)", this);
						        if (current != village.text()) {
						            current = village.text();
						            amountOfVillages++;
						        }
						        var type = amountOfVillages % 2 == 0 ? 'row_a' : 'row_b';
						
						        var villageId = village.find("a:first").attr("href").match(/village=(\d+)/)[1];
						        this.className = "nowrap " + type + (villageId == game_data.village.id ? " selected" : "");
						    });
						
						    table.setTotals(rows.size(), amountOfVillages);
						});
						/**
						 *
						 * @param {function} filterStrategy return true to hidethe row; false keep row visible (without reverse filter checkbox)
						 * @param {Object} options
						 */
						function filterVillageRows(filterStrategy, options) {
						    options = $.extend({}, {
						        checkboxReverses: true
						    }, options);
						
						    var reverseFilter = options.checkboxReverses && $("#defReverseFilter").is(":checked"),
						        goners = $(),
						        villageCounter = 0;
						
						    trackClickEvent(options.gaEventName);
						
						    table.fixTable();
						
						    table.getVillageRows().each(function () {
						        var self = $(this);
						        if (!reverseFilter != !filterStrategy(self)) {
						            goners = goners.add(self);
						        } else {
						            villageCounter++;
						        }
						    });
						    goners.remove();
						
						    // Show totals
						    table.setTotals(villageCounter);
						}
						
						// Show new attacks only
						$("#filterAttack").click(function () {
						    var strategy = function(row) {
						        return $.trim($("td:first", row).text()) != trans.tw.command.attack;
						    };
						
						    filterVillageRows(strategy, {
						        gaEventName: "FilterNewAttacks",
						        checkboxReverses: false
						    });
						});
						
						
						// Filter rows on column 0 - 3 (command, target, origin, player)
						$("#filterColumn").click(function() {
						    var filter = {
						        index: $("#filterColumnIndex").val(),
						        searchText: $.trim($("#filterColumnValue").val()).toLowerCase()
						    };
						
						    var filterStrategy = function(row) {
						        return row.find("td").eq(filter.index).text().toLowerCase().indexOf(filter.searchText) === -1;
						    };
						
						    filterVillageRows(filterStrategy, {
						        gaEventName: "column-" + $("#filterColumnIndex").text()
						    });
						});
				
				
				    } catch (e) { handleException(e, "overview-incomings"); }
				    //console.timeEnd("overview-incomings");
				}());
            }
			
			// make the editting groups box less wide
			// and add alternating row colors
			$("#edit_group_href").click(function () {
				var groupTable = $("#group_list");
				groupTable.width(300);
			
				groupTable.find("th:first").attr("colspan", "3");
				var mod = 0;
				groupTable.find("tr:gt(0)").each(function () {
					mod++;
					$(this).addClass("row_" + (mod % 2 == 0 ? "a" : "b"));
				});
			});
			
			// change troops overview link to active sangu page
			if (user_data.command.changeTroopsOverviewLink) {
				var troopsOverviewLink = $("#overview_menu a[href*='mode=units']");
				troopsOverviewLink.attr("href", troopsOverviewLink.attr("href") + "&type=own_home");
			}
			
			if (user_data.overviews.addFancyImagesToOverviewLinks) {
				var overviewLinks = $("#overview_menu a");
				overviewLinks.each(function(index) {
					var overviewLink = $(this),
						imageToAdd = "";
					
					switch (index) {
						case 0:
			//				overviewLink.parent()
			//                    .css("background-image", 'url("https://www.tribalwars.vodka/graphic/icons/header.png")')
			//				    .css("background-repeat", "no-repeat")
			//				    .css("background-position", "-324px 0px")
			//				    .css("background-size", "200px Auto");
			//
			//				overviewLink.prepend("&nbsp; &nbsp;");
							break;
						case 1:
							imageToAdd = "graphic/buildings/storage.png";
							break;
						case 2:
							imageToAdd = "graphic/buildings/market.png";
							break;
						case 3:
							if (overviewLink.parent().hasClass("selected")) {
								$("table.modemenu:last a", content_value).each(function(index) {
									imageToAdd = "";
									switch (index) {
										case 1:
											imageToAdd = "graphic/buildings/place.png";
											break;
										case 2:
											imageToAdd = "graphic/pfeil.png";
											break;
										case 3:
										case 4:
											$(this).css("opacity", "0.5");
											break;
										case 5:
											imageToAdd = "graphic/command/support.png";
											break;
										case 6:
											imageToAdd = "graphic/rechts.png";
											break;
									}
									
									if (imageToAdd !== "") {
			                            $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " &gt; " + $(this).text()+"' /> &nbsp;");
									}
								});
							}
							
							imageToAdd = "graphic/unit/unit_knight.png";
							break;
						case 4:
							if (overviewLink.parent().hasClass("selected")) {
								$("table.modemenu:last a", content_value).each(function(index) {
									imageToAdd = "";
									switch (index) {
										case 1:
											imageToAdd = "graphic/command/attack.png";
											break;
										case 2:
											imageToAdd = "graphic/command/support.png";
											break;
										case 3:
											imageToAdd = "graphic/command/return.png";
											break;
									}
									
									if (imageToAdd !== "") {
			                            $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " &gt; " + $(this).text()+"' /> &nbsp;");
									}
								});
							}
						
							imageToAdd = "graphic/command/attack.png";
							break;
						case 5:
							if (overviewLink.parent().hasClass("selected")) {
								$("table.modemenu:last a", content_value).each(function(index) {
									imageToAdd = "";
									switch (index) {
										case 1:
											imageToAdd = "graphic/command/attack.png";
											break;
										case 2:
											imageToAdd = "graphic/command/support.png";
											break;
									}
									
									if (imageToAdd !== "") {
			                            $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " &gt; " + $(this).text()+"' /> &nbsp;");
									}
								});
							}
						
							imageToAdd = "graphic/unit/att.png";
							break;
						case 6:
							imageToAdd = "graphic/buildings/main.png";
							break;
						case 7:
							imageToAdd = "graphic/buildings/smith.png";
							break;
						case 8:
							imageToAdd = "graphic/group_right.png";
			                overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' /> &nbsp;");
							imageToAdd = "graphic/group_left.png";
							break;
						case 9:
							imageToAdd = "graphic/premium/coinbag_14x14.png";
							overviewLink.parent().width(150);
							break;
					}
					if (imageToAdd !== "") {
			            overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' />&nbsp;&nbsp;");
					}
				});
			}
        }

		var logoffLink = $("#linkContainer a:last");
        if (user_data.global.duplicateLogoffLink) {
            $("#linkContainer a:first").after(" - ").after(logoffLink.clone());
        }

        logoffLink.before("<a target='_blank' title='"+trans.sp.sp.moreScriptsTooltip+"' href='"+server_settings.scriptsDatabaseUrl+"'>"+trans.sp.sp.moreScripts+"</a>")
            .before(" - <a target='_top' id='sanguPackageEditSettingsLink' href='"+getUrlString("screen=settings&mode=sangu")+"' title='" + trans.sp.sp.sanguLinkTitle + "'>Sangu Package</a> - ");

        (function() {
            var position = $("#sanguPackageEditSettingsLink").position(),
                options = {
                    left: position.left,
                    top: ($(window).height() - 100)
                },
                content = {
                    body: trans.sp.sp.firstTimeRunEditSettings
                };

            createFixedTooltip("sanguActivatorSettingsTooltip", content, options);
        }());
		
		(function() {
		    //console.time("resourceColoring");
		    try {
		        var storage = parseInt($("#storage").text(), 10);
		
		        // Color resources based on how full the storage place is
		        if (user_data.global.resources.active) {
		            $("#wood,#iron,#stone").each(function () {
		                var x = parseInt(this.innerHTML / storage * 10 - 1, 10);
		                $(this).css("background-color", user_data.global.resources.backgroundColors[x]);
		            });
		        }
		
		        // Blink full resources
		        if (user_data.global.resources.blinkWhenStorageFull) {
		            $("#wood,#iron,#stone").filter(function () {
		                return parseInt(this.innerHTML, 10) == storage;
		            }).css({ "font-weight": "bolder", "color": "black" }).fadeOut().fadeIn();
		        }
		    } catch (e) { handleException(e, "resourcecoloring"); }
		    //console.timeEnd("resourceColoring");
		}());
		// adjust links to incoming attacks/support
		// keep track of current amount of incomings
		if (user_data.global.incomings.editLinks || user_data.global.incomings.track) {
		    (function() {
		        //console.time("incomingsindicator");
		        try {
		            var incoming = $("table.box:last"),
		                incomingAttacksLinks = $("a[href*='subtype=attacks']", incoming),
		                variableReplacer = function (text) {
		                    var difference = "";
		                    if (sinceLastCheckTimeNew > 0) {
		                        difference += "+" + sinceLastCheckTimeNew;
		                        if (sinceLastCheckTimeArrived > 0) {
		                            difference += " ";
		                        }
		                    }
		                    if (sinceLastCheckTimeArrived > 0) {
		                        difference += "-" + sinceLastCheckTimeArrived;
		                    }
		
		                    return text.replace("{difference}", difference)
		                        .replace("{elapsed}", lastCheckTimeElapsed)
		                        .replace("{time}", lastCheckTime)
		                        .replace("{current}", currentAmountOfIncomings
		                        .replace("{saved}", lastKnownAmountOfIncomings));
		                };
		
		            if (incomingAttacksLinks.size() > 0) {
		                if (user_data.global.incomings.editLinks) {
		                    incomingAttacksLinks.attr("href", incomingAttacksLinks.attr("href") + "&page=-1&group=0");
		                }
		                if (user_data.global.incomings.track) {
		                    incomingAttacksLinks.parent().css("white-space", "nowrap");
		
		                    // Split current and new attacks in incomings link
		                    var incomingAttacksAmountLink = incomingAttacksLinks.last();
		                    var currentAmountOfIncomings = incomingAttacksAmountLink.text().match(/\d+/)[0];
		                    var lastKnownAmountOfIncomings = parseInt(pers.get("lastKnownAmountOfIncomings" + game_data.player.sitter), 10) || 0,
		                        sinceLastCheckTimeNew = parseInt(pers.get("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter), 10) || 0,
		                        sinceLastCheckTimeArrived = parseInt(pers.get("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter), 10) || 0;
		
		                    var lastCheckTime = pers.get("lastKnownAmountOfIncomingsTime" + game_data.player.sitter);
		                    var lastCheckTimeElapsed;
		                    if (!lastCheckTime) {
		                        lastCheckTime = trans.sp.incomings.indicator.lastTimeCheckNotYetSet;
		                        lastCheckTimeElapsed = lastCheckTime;
		                    } else {
		                        lastCheckTime = new Date().getTime() - parseInt(lastCheckTime, 10);
		                        lastCheckTimeElapsed = prettyDate(lastCheckTime);
		                        lastCheckTime = twDateFormat(new Date(lastCheckTime));
		                    }
		
		                    if (currentAmountOfIncomings != lastKnownAmountOfIncomings || sinceLastCheckTimeNew > 0 || sinceLastCheckTimeArrived > 0) {
		                        var newAttacks = currentAmountOfIncomings - lastKnownAmountOfIncomings;
		                        if (newAttacks > 0) {
		                            sinceLastCheckTimeNew += newAttacks;
		                            pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, sinceLastCheckTimeNew);
		
		                        } else if (newAttacks < 0) {
		                            sinceLastCheckTimeArrived -= newAttacks;
		                            pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, sinceLastCheckTimeArrived);
		                        }
		
		                        pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings);
		
		                        $("#incomings_amount").html(variableReplacer(user_data.global.incomings.indicator));
		                        incomingAttacksLinks.attr("title", variableReplacer(user_data.global.incomings.lastTimeCheckWarning));
		                        incomingAttacksLinks.fadeOut("slow").fadeIn("slow");
		                    }
		
		                    // extra image to set the lastCheckTime on incomings overview page
		                    if (current_page.screen === "overview_villages" && current_page.mode === "incomings") {
		                        // Tooltip for first time users
		                        if (lastCheckTime == trans.sp.incomings.indicator.lastTimeCheckNotYetSet) {
		                            // show info tooltip
		                            var position = incomingAttacksAmountLink.position();
		                            var options = {
		                                left: position.left - 200,
		                                top: position.top + 35,
		                                width: 250
		                            };
		                            var content = {body: trans.sp.incomings.indicator.lastTimeCheckHintBoxTooltip.replace("{img}", "<img src='graphic/ally_forum.png'>")};
		                            createFixedTooltip("incomingsIndicatorHelp", content, options);
		                        }
		
		                        // change last incomings-check time
		                        incomingAttacksLinks.last().parent().after(
		                            "<td class='box-item' id='changeLastCheckTimeBox' style='white-space: nowrap'><a href='#' id='changeLastCheckTime'>&nbsp;"
		                                + "<img src='graphic/ally_forum.png' style='padding-top: 5px' "
		                                + "title='"+variableReplacer(user_data.global.incomings.indicatorTooltip)+"'/>&nbsp;</a></td>");
		
		                        // Set last incomings-check time
		                        $("#changeLastCheckTime").click(function() {
		                            var newCheckTime = new Date();
		                            pers.set("lastKnownAmountOfIncomingsTime" + game_data.player.sitter, newCheckTime.getTime());
		                            pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings);
		                            pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0);
		                            pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0);
		
		                            pers.setGlobal("fixedToolTip_incomingsIndicatorHelp", 1);
		                            $("#changeLastCheckTimeBox").fadeOut();
		                            window.location.href = window.location.href;
		                        });
		                    }
		                }
		            } else {
		                // When there are no more incomings, stop tracking
		                if (user_data.global.incomings.track) {
		                    pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, 0);
		                    pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0);
		                    pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0);
		                }
		            }
		
		            // change incoming support link
		            if (user_data.global.incomings.editLinks) {
		                var incomingSupport = $("a[href*='subtype=supports']", incoming);
		                if (incomingSupport.size() > 0) {
		                    if (user_data.global.incomings.editLinks) {
		                        incomingSupport.attr("href", incomingSupport.attr("href") + "&page=-1&group=0");
		                    }
		                }
		            }
		        } catch (e) { handleException(e, "incomingsindicator"); }
		        //console.time("incomingsindicator");
		    }());
		}
		if (server_settings.ajaxAllowed && user_data.global.visualizeFriends) {
		    (function() {
		        //console.time("friends");
		        try {
		            function Friends() {
		                this.lastCheck = new Date().getTime();
		                this.online = {
		                    names: "",
		                    amount: 0
		                };
		                this.offlineAmount = 0;
		            }
		
		            /**
		             * Insert a 'friends' link with visual online/offline indication
		             */
		            function updateTWFriendsLink() {
		                var friendsLink = $("<a href='" + getUrlString("&screen=buddies") + "'></a>");
		                friendsLink.html(
		                    trans.sp.rest.friendsOnline
		                        .replace("{friends}", friendsLink.text())
		                        .replace("{onlineimg}", "<img src='graphic/dots/green.png' />")
		                        .replace("{online#}", friends.online.amount)
		                        .replace("{offlineimg}", "<img src='graphic/dots/red.png' />")
		                        .replace("{offline#}", friends.offlineAmount)
		                );
		                if (friends.online.amount > 0) {
		                    friendsLink.attr("title", trans.sp.rest.friendsOnlineTitle.replace("{playerNames}", friends.online.names.substr(1)));
		                }
		                $("#sanguPackageEditSettingsLink").before(friendsLink).before(" - ");
		            }
		
		            /**
		             * Parse the #content_value and update the friends link.
		             * Is called from ajax call.
		             * @param {string} overview the #content_value of the friends page
		             */
		            function parseFriendsTable(overview) {
		                var friendsTable = $("h3+table.vis:first", overview);
		                if (friendsTable.size() == 1) {
		                    var friendRows = friendsTable.find("tr:gt(0)");
		                    friendRows.each(function() {
		                        var friendName = $.trim($("a:first", this).text());
		                        var statusIndicatorImage = $("img:first", this);
		                        if( statusIndicatorImage.length > 0 ) {
		                            if (/red\.png/.test(statusIndicatorImage.attr("src"))) {
		                                friends.offlineAmount++;
		                            } else {
		                                if (friendName != game_data.player.name) {
		                                    friends.online.names += ", " + friendName;
		                                    friends.online.amount++;
		                                }
		                            }
		                        }
		                    });
		
		                    // localStorage save of online friends
		                    pers.set("friendsOnline", JSON.stringify(friends));
		
		                    updateTWFriendsLink();
		                }
		            }
		
		            var friends = pers.get("friendsOnline");
		
		            // check friends page only every 5 minutes (or when on friends page itself)
		            if ($("#village_link").val() == "/game.php?screen=buddies") {
		                friends = new Friends();
		                parseFriendsTable(content_value);
		            }
		            else {
		                if (friends) {
		                    friends = JSON.parse(friends);
		                }
		                if (!friends || friends.lastCheck < new Date().getTime() - 1000 * 60 * 3) {
		                    friends = new Friends();
		                    ajax("buddies", parseFriendsTable);
		                } else {
		                    updateTWFriendsLink();
		                }
		            }
		        } catch (e) { handleException(e, "friends"); }
		        //console.timeEnd("friends");
		    }());
		}
		
		
		
		
		//var end_time = new Date();
		//console.timeEnd("SanguPackage");
		//q("" + pad(Math.abs(start_time.getTime() - end_time.getTime()), 3) + " -> " + location.search);
    }
}

if (location.href.indexOf('sangu.be') !== -1) {
    // sangu.be
(function() {
    // Check current version with version on the sangu.be site
    var lastVersion = $("#sanguPackageVersion"),
        resultBox = $("#versionCheckResult");

    if (lastVersion.length === 1) {
        resultBox.show();
        resultBox.css("padding", "20px");
        resultBox.css("margin", "10px");
        resultBox.css("font-size", 18);
        resultBox.css("height", 30);
        resultBox.css("text-align", "center");

        if ('8.90.0'.indexOf(lastVersion.text()) === 0) {
            resultBox.css("background-color", "green");
            resultBox.text("Je hebt de laatste versie!");
        } else {
            resultBox.css("background-color", "red");
            resultBox.text("Er is een nieuwe versie beschikbaar!");
        }
    }
}());

} else if (location.href.indexOf('tribalwars.nl') !== -1) {
    // TribalWars page
(function (func, GM_xmlhttpRequest) {
var lastCheck = sessionStorage.lastUpdateCheck,
    currentVersion = '8.90.0';

function displayNewVersion() {
    var a = document.createElement('a');
    var linkText = document.createTextNode(" - Sangu Package Update!");
    a.appendChild(linkText);
    a.title = "Er is een update voor het Sangu Package beschikbaar!";
    a.href = "http://sangu.be";
    a.style.color = "black";
    a.style.fontWeight = "bolder";
    a.style.backgroundColor = "yellow";

    document.getElementById("linkContainer").appendChild(a);
}

if (typeof GM_xmlhttpRequest !== "undefined") {
    if (!lastCheck) {
        sessionStorage.lastUpdateCheck = "done";
        try
        {
            // GM_xmlhttpRequest didn't work when put in sangu_ready
            GM_xmlhttpRequest({
                method: "GET",
                url: "http://www.sangu.be/api/sangupackageversion.php",
                synchronous: false,
                onload: function(response) {
                    if (response.responseText !== currentVersion) {
                        sessionStorage.lastUpdateCheck = "hasNew";
                        displayNewVersion();
                    }
                }
            });
        }
        catch (e)
        {
            console.log("error fetching latest version number:");
            console.log(e);
        }
    } else if (lastCheck === "hasNew") {
        displayNewVersion();
    }
}

    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    if (window.mozInnerScreenX !== undefined) {
        // Firefox has troubles with renaming commands, villages, ... (it works some of the time)
        // But waiting for document.ready slows down the script so only wait for this on FF
        // An optimization could be to put document.readys only around those blocks that are
        // problematic.
        script.textContent = '$(document).ready(' + func + ');';

    } else {
        script.textContent = '(' + func + ')();';
    }

    document.body.appendChild(script); // run the script
    document.body.removeChild(script); // clean up
}(sangu_ready, (typeof GM_xmlhttpRequest === "undefined" ? undefined : GM_xmlhttpRequest)));


}