<file_sep>package com.palmergames.bukkit.towny.event;

import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;

/**
 * Author: <NAME> (Zren / Shade)
 * Date: 5/23/12
 *
 * Fired after a resident has been added to a town.
 */
public class TownAddResidentEvent extends Event {

    private static final HandlerList handlers = new HandlerList();
    private Resident resident;
    private Town town;


    public TownAddResidentEvent(Resident resident, Town town) {
        this.resident = resident;
        this.town = town;
    }

    /**
     *
     * @return the resident who has joined a town.
     */
    public Resident getResident() {
        return resident;
    }

    /**
     *
     * @return the town the resident has just joined.
     */
    public Town getTown() {
        return town;
    }

    @Override
    public HandlerList getHandlers() {
        return handlers;
    }
}
<file_sep>package com.palmergames.bukkit.towny.regen;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;

import com.palmergames.bukkit.towny.Towny;
import com.palmergames.bukkit.towny.TownyMessaging;
import com.palmergames.bukkit.towny.TownySettings;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Coord;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.TownBlock;
import com.palmergames.bukkit.towny.object.TownyUniverse;
import com.palmergames.bukkit.towny.object.WorldCoord;
import com.palmergames.bukkit.towny.regen.block.BlockInventoryHolder;
import com.palmergames.bukkit.towny.regen.block.BlockLocation;
import com.palmergames.bukkit.towny.regen.block.BlockMobSpawner;
import com.palmergames.bukkit.towny.regen.block.BlockObject;
import com.palmergames.bukkit.towny.regen.block.BlockSign;
import com.palmergames.bukkit.towny.tasks.ProtectionRegenTask;
import com.palmergames.bukkit.util.BukkitTools;

/**
 * @author ElgarL
 * 
 */
public class TownyRegenAPI {

	//private static Towny plugin = null;
	
	public static void initialize(Towny plugin) {

		//TownyRegenAPI.plugin = plugin;
	}

	// table containing snapshot data of active reversions.
	private static Hashtable<String, PlotBlockData> PlotChunks = new Hashtable<String, PlotBlockData>();

	// List of all old plots still to be processed for Block removal
	private static List<WorldCoord> deleteTownBlockIdQueue = new ArrayList<WorldCoord>();

	// A list of worldCoords which are needing snapshots
	private static List<WorldCoord> worldCoords = new ArrayList<WorldCoord>();
	
	// A holder for each protection regen task
	private static  Hashtable<BlockLocation, ProtectionRegenTask> protectionRegenTasks = new Hashtable<BlockLocation, ProtectionRegenTask>();
	
	// List of protection blocks placed to prevent blockPhysics.
	private static  Set<Block> protectionPlaceholders = new HashSet<Block>();

	/**
	 * Add a TownBlocks WorldCoord for a snapshot to be taken.
	 * 
	 * @param worldCoord
	 */
	public static void addWorldCoord(WorldCoord worldCoord) {

		if (!worldCoords.contains(worldCoord))
			worldCoords.add(worldCoord);
	}

	/**
	 * @return true if there are any TownBlocks to be processed.
	 */
	public static boolean hasWorldCoords() {

		return worldCoords.size() != 0;
	}

	/**
	 * Check if this WorldCoord is waiting for a snapshot to be taken.
	 * 
	 * @param worldCoord
	 * @return true if it's in the queue.
	 */
	public static boolean hasWorldCoord(WorldCoord worldCoord) {

		return worldCoords.contains(worldCoord);
	}

	/**
	 * @return First WorldCoord to be processed.
	 */
	public static WorldCoord getWorldCoord() {

		if (!worldCoords.isEmpty()) {
			WorldCoord wc = worldCoords.get(0);
			worldCoords.remove(0);
			return wc;
		}
		return null;
	}

	/**
	 * @return the plotChunks which are being processed
	 */
	public static Hashtable<String, PlotBlockData> getPlotChunks() {

		return PlotChunks;
	}

	/**
	 * @return true if there are any chunks being processed.
	 */
	public static boolean hasPlotChunks() {

		return !PlotChunks.isEmpty();
	}

	/**
	 * @param plotChunks the plotChunks to set
	 */
	public static void setPlotChunks(Hashtable<String, PlotBlockData> plotChunks) {

		PlotChunks = plotChunks;
	}

	/**
	 * Removes a Plot Chunk from the regeneration Hashtable
	 * 
	 * @param plotChunk
	 */
	public static void deletePlotChunk(PlotBlockData plotChunk) {

		if (PlotChunks.containsKey(getPlotKey(plotChunk))) {
			PlotChunks.remove(getPlotKey(plotChunk));
			TownyUniverse.getDataSource().saveRegenList();
		}
	}

	/**
	 * Adds a Plot Chunk to the regeneration Hashtable
	 * 
	 * @param plotChunk
	 * @param save
	 */
	public static void addPlotChunk(PlotBlockData plotChunk, boolean save) {

		if (!PlotChunks.containsKey(getPlotKey(plotChunk))) {
			//plotChunk.initialize();
			PlotChunks.put(getPlotKey(plotChunk), plotChunk);
			if (save)
				TownyUniverse.getDataSource().saveRegenList();
		}
	}

	/**
	 * Saves a Plot Chunk snapshot to the datasource
	 * 
	 * @param plotChunk
	 */
	public static void addPlotChunkSnapshot(PlotBlockData plotChunk) {

		if (TownyUniverse.getDataSource().loadPlotData(plotChunk.getWorldName(), plotChunk.getX(), plotChunk.getZ()) == null) {
			TownyUniverse.getDataSource().savePlotData(plotChunk);
		}
	}

	/**
	 * Deletes a Plot Chunk snapshot from the datasource
	 * 
	 * @param plotChunk
	 */
	public static void deletePlotChunkSnapshot(PlotBlockData plotChunk) {

		TownyUniverse.getDataSource().deletePlotData(plotChunk);
	}

	/**
	 * Loads a Plot Chunk snapshot from the datasource
	 * 
	 * @param townBlock
	 */
	public static PlotBlockData getPlotChunkSnapshot(TownBlock townBlock) {

		return TownyUniverse.getDataSource().loadPlotData(townBlock);
	}

	/**
	 * Gets a Plot Chunk from the regeneration Hashtable
	 * 
	 * @param townBlock
	 */
	public static PlotBlockData getPlotChunk(TownBlock townBlock) {

		if (PlotChunks.containsKey(getPlotKey(townBlock))) {
			return PlotChunks.get(getPlotKey(townBlock));
		}
		return null;
	}

	private static String getPlotKey(PlotBlockData plotChunk) {

		return "[" + plotChunk.getWorldName() + "|" + plotChunk.getX() + "|" + plotChunk.getZ() + "]";
	}

	public static String getPlotKey(TownBlock townBlock) {

		return "[" + townBlock.getWorld().getName() + "|" + townBlock.getX() + "|" + townBlock.getZ() + "]";
	}

	/**
	 * Regenerate the chunk the player is stood in and store the block data so it can be undone later.
	 * 
	 * @param player
	 */
	public static void regenChunk(Player player) {
		
		try {
			Coord coord = Coord.parseCoord(player);
			World world = player.getWorld();
			Chunk chunk = world.getChunkAt(player.getLocation());
			int maxHeight = world.getMaxHeight();
			
			Object[][][] snapshot = new Object[16][maxHeight][16];
			
			for (int x = 0; x < 16; x++) {
				for (int z = 0; z < 16; z++) {
					for (int y = 0; y < maxHeight; y++) {
						
						//Current block to save
						BlockState state = chunk.getBlock(x, y, z).getState();
						
						if (state instanceof org.bukkit.block.Sign) {
							
							BlockSign sign = new BlockSign(state.getTypeId(), state.getData().getData(), ((org.bukkit.block.Sign) state).getLines());
							sign.setLocation(state.getLocation());
							snapshot[x][y][z] = sign;
							
						} else if (state instanceof CreatureSpawner) {
							
							BlockMobSpawner spawner = new BlockMobSpawner(((CreatureSpawner) state).getSpawnedType());
							spawner.setLocation(state.getLocation());
							spawner.setDelay(((CreatureSpawner) state).getDelay());
							snapshot[x][y][z] = spawner;
							
						} else if ((state instanceof InventoryHolder) && !(state instanceof Player)) {
							
							BlockInventoryHolder holder = new BlockInventoryHolder(state.getTypeId(), state.getData().getData(), ((InventoryHolder) state).getInventory().getContents());
							holder.setLocation(state.getLocation());
							snapshot[x][y][z] = holder;
							
						} else {
						
							snapshot[x][y][z] = new BlockObject(state.getTypeId(), state.getData().getData(), state.getLocation());
									
						}
						
					}
				}
			}
			
			TownyUniverse.getDataSource().getResident(player.getName()).addUndo(snapshot);

			Bukkit.getWorld(player.getWorld().getName()).regenerateChunk(coord.getX(), coord.getZ());

		} catch (NotRegisteredException e) {
			// Failed to get resident
		}
		
		
	}
	
	/**
	 * Restore the relevant chunk using the snapshot data stored in the resident
	 * object.
	 * 
	 * @param snapshot
	 * @param resident
	 */
	public static void regenUndo(Object[][][] snapshot, Resident resident) {

		BlockObject key = ((BlockObject) snapshot[0][0][0]);
		World world = key.getLocation().getWorld();
		Chunk chunk = key.getLocation().getChunk();
		
		int maxHeight = world.getMaxHeight();
		
		for (int x = 0; x < 16; x++) {
			for (int z = 0; z < 16; z++) {
				for (int y = 0; y < maxHeight; y++) {
					
					// Snapshot data we need to update the world.
					Object state = snapshot[x][y][z];
					
					// The block we will be updating
					Block block = chunk.getBlock(x, y, z);
					
					if (state instanceof BlockSign) {

						BlockSign signData = (BlockSign)state;
						block.setTypeIdAndData(signData.getTypeId(), signData.getData(), false);
						
						Sign sign = (Sign) block.getState();
						int i = 0;
						for (String line : signData.getLines())
							sign.setLine(i++, line);
						
						sign.update(true);
						
					} else if (state instanceof BlockMobSpawner) {
						
						BlockMobSpawner spawnerData = (BlockMobSpawner) state;
						
						block.setTypeIdAndData(spawnerData.getTypeId(), spawnerData.getData(), false);
						((CreatureSpawner) block.getState()).setSpawnedType(spawnerData.getSpawnedType());
						((CreatureSpawner) block.getState()).setDelay(spawnerData.getDelay());
						
					} else if ((state instanceof BlockInventoryHolder) && !(state instanceof Player)) {
						
						BlockInventoryHolder containerData = (BlockInventoryHolder) state;
						block.setTypeIdAndData(containerData.getTypeId(), containerData.getData(), false);
						
						// Container to receive the inventory
						InventoryHolder container = (InventoryHolder) block.getState();
						
						// Contents we are respawning.						
						if (containerData.getItems().length > 0)
							container.getInventory().setContents(containerData.getItems());
						
					} else {
						
						BlockObject blockData = (BlockObject) state;						
						block.setTypeIdAndData(blockData.getTypeId(), blockData.getData(), false);
					}
					
					
					

				}
			}

		}

		TownyMessaging.sendMessage(BukkitTools.getServer().getPlayerExact(resident.getName()), TownySettings.getLangString("msg_undo_complete"));

	}

	/////////////////////////////////

	/**
	 * @return true if there are any chunks being processed.
	 */
	public static boolean hasDeleteTownBlockIdQueue() {

		return !deleteTownBlockIdQueue.isEmpty();
	}

	public static boolean isDeleteTownBlockIdQueue(WorldCoord plot) {

		return deleteTownBlockIdQueue.contains(plot);
	}

	public static void addDeleteTownBlockIdQueue(WorldCoord plot) {

		if (!deleteTownBlockIdQueue.contains(plot))
			deleteTownBlockIdQueue.add(plot);
	}

	public static WorldCoord getDeleteTownBlockIdQueue() {

		if (!deleteTownBlockIdQueue.isEmpty()) {
			WorldCoord wc = deleteTownBlockIdQueue.get(0);
			deleteTownBlockIdQueue.remove(0);
			return wc;
		}
		return null;
	}

	/**
	 * Deletes all of a specified block type from a TownBlock
	 * 
	 * @param worldCoord
	 */
	public static void doDeleteTownBlockIds(WorldCoord worldCoord) {

		//Block block = null;
		World world = null;
		int plotSize = TownySettings.getTownBlockSize();

		TownyMessaging.sendDebugMsg("Processing deleteTownBlockIds");

		world = worldCoord.getBukkitWorld();

		if (world != null) {
			/*
			 * if
			 * (!world.isChunkLoaded(MinecraftTools.calcChunk(townBlock.getX()),
			 * MinecraftTools.calcChunk(townBlock.getZ())))
			 * return;
			 */
			int height = world.getMaxHeight() - 1;
			int worldx = worldCoord.getX() * plotSize, worldz = worldCoord.getZ() * plotSize;

			for (int z = 0; z < plotSize; z++)
				for (int x = 0; x < plotSize; x++)
					for (int y = height; y > 0; y--) { //Check from bottom up else minecraft won't remove doors
						Block block = world.getBlockAt(worldx + x, y, worldz + z);
						try {
							if (worldCoord.getTownyWorld().isPlotManagementDeleteIds(block.getTypeId())) {
								block.setType(Material.AIR);
							}
						} catch (NotRegisteredException e) {
							// Not a registered world
						}
						block = null;
					}
		}

	}

	/**
	 * Deletes all of a specified block type from a TownBlock
	 * 
	 * @param townBlock
	 * @param material
	 */
	public static void deleteTownBlockMaterial(TownBlock townBlock, int material) {

		//Block block = null;
		int plotSize = TownySettings.getTownBlockSize();

		TownyMessaging.sendDebugMsg("Processing deleteTownBlockMaterial");

		World world = BukkitTools.getServer().getWorld(townBlock.getWorld().getName());

		if (world != null) {
			/*
			 * if
			 * (!world.isChunkLoaded(MinecraftTools.calcChunk(townBlock.getX()),
			 * MinecraftTools.calcChunk(townBlock.getZ())))
			 * return;
			 */
			int height = world.getMaxHeight() - 1;
			int worldx = townBlock.getX() * plotSize, worldz = townBlock.getZ() * plotSize;

			for (int z = 0; z < plotSize; z++)
				for (int x = 0; x < plotSize; x++)
					for (int y = height; y > 0; y--) { //Check from bottom up else minecraft won't remove doors
						Block block = world.getBlockAt(worldx + x, y, worldz + z);
						if (block.getTypeId() == material) {
							block.setType(Material.AIR);
						}
						block = null;
					}
		}
	}

	/*
	 * Protection Regen follows
	 */
	
	/**
	 * Does a task for this block already exist?
	 * 
	 * @param blockLocation
	 * @return true if a task exists
	 */
	public static boolean hasProtectionRegenTask(BlockLocation blockLocation) {

		for (BlockLocation location : protectionRegenTasks.keySet()) {
			if (location.isLocation(blockLocation)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Fetch the relevant regen task for this block
	 * 
	 * @param blockLocation
	 * @return the stored task, or null if there is none.
	 */
	public static ProtectionRegenTask GetProtectionRegenTask(BlockLocation blockLocation) {

		for (BlockLocation location : protectionRegenTasks.keySet()) {
			if (location.isLocation(blockLocation)) {
				return protectionRegenTasks.get(location);
			}
		}
		return null;
	}

	/**
	 * Add this task to the protection regen queue.
	 * 
	 * @param task
	 */
	public static void addProtectionRegenTask(ProtectionRegenTask task) {

		protectionRegenTasks.put(task.getBlockLocation(), task);
	}

	/**
	 * Remove this task form teh protection regen queue
	 * 
	 * @param task
	 */
	public static void removeProtectionRegenTask(ProtectionRegenTask task) {

		protectionRegenTasks.remove(task.getBlockLocation());
		if (protectionRegenTasks.isEmpty())
			protectionPlaceholders.clear();
	}

	/**
	 * Cancel all regenerating tasks and clear all queues.
	 */
	public static void cancelProtectionRegenTasks() {

		for (ProtectionRegenTask task : protectionRegenTasks.values()) {
			BukkitTools.getServer().getScheduler().cancelTask(task.getTaskId());
			task.replaceProtections();
		}
		protectionRegenTasks.clear();
		protectionPlaceholders.clear();
	}

	/**
	 * Is this a placholder block?
	 * 
	 * @param block
	 * @return true if it is a placeholder
	 */
	public static boolean isPlaceholder(Block block) {

		return protectionPlaceholders.contains(block);
	}

	/**
	 * Add this block as a placeholder (will be replaced when it's regeneration task occurs)
	 * 
	 * @param block
	 */
	public static void addPlaceholder(Block block) {

		protectionPlaceholders.add(block);
	}

	/**
	 * Remove this block from being tracked as a placeholder.
	 * 
	 * @param block
	 */
	public static void removePlaceholder(Block block) {

		protectionPlaceholders.remove(block);
	}
}<file_sep>/**
 * 
 */
package com.palmergames.bukkit.towny.permissions;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import org.bukkit.configuration.MemorySection;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionDefault;

import com.palmergames.bukkit.config.CommentedConfiguration;
import com.palmergames.bukkit.towny.Towny;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Nation;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.object.TownyUniverse;
import com.palmergames.bukkit.towny.object.TownyWorld;
import com.palmergames.bukkit.util.BukkitTools;
import com.palmergames.util.FileMgmt;

/**
 * @author ElgarL
 * 
 */
public class TownyPerms {

	protected static LinkedHashMap<String, Permission> registeredPermissions = new LinkedHashMap<String, Permission>();
	protected static HashMap<String, PermissionAttachment> attachments = new HashMap<String, PermissionAttachment>();
	private static CommentedConfiguration perms;
	private static Towny plugin;
	
	public static void initialize(Towny plugin) {
		TownyPerms.plugin = plugin;
	}
	
	private static Field permissions;

	// Setup reflection (Thanks to Codename_B for the reflection source)
	static {
		try {
			permissions = PermissionAttachment.class.getDeclaredField("permissions");
			permissions.setAccessible(true);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Load the townyperms.yml file.
	 * If it doesn't exist create it from the resource file in the jar.
	 * 
	 * @param filepath
	 * @param defaultRes
	 * @throws IOException
	 */
	public static void loadPerms(String filepath, String defaultRes) throws IOException {

		String fullPath = filepath + FileMgmt.fileSeparator() + defaultRes;

		File file = FileMgmt.unpackResourceFile(fullPath, defaultRes, defaultRes);
		if (file != null) {
			// read the (language).yml into memory
			perms = new CommentedConfiguration(file);
			perms.load();
		}
		
		/*
		 * Only do this once as we are really only interested in Towny perms.
		 */
		collectPermissions();
		
	}
	
	/**
	 * Register a specific residents permissions with Bukkit.
	 * 
	 * @param resident
	 */
	public static void assignPermissions(Resident resident, Player player) {
		
		PermissionAttachment playersAttachment= null;
		
		if (resident == null) {
			try {
				resident = TownyUniverse.getDataSource().getResident(player.getName());
			} catch (NotRegisteredException e) {
				// failed to get resident
				e.printStackTrace();
				return;
			}
		} else {
			player = BukkitTools.getPlayer(resident.getName());
		}
		
		/*
		 * Find the current attachment
		 * or create a new one (if the player is online)
		 */

		if ((player == null) || !player.isOnline()) {
			attachments.remove(resident.getName());
			return;
		}
		
		TownyWorld World = null;

		try {
			World = TownyUniverse.getDataSource().getWorld(player.getLocation().getWorld().getName());
		} catch (NotRegisteredException e) {
			// World not registered with Towny.
			e.printStackTrace();
			return;
		}
		
		if (attachments.containsKey(resident.getName())) {
			playersAttachment = attachments.get(resident.getName());
		} else
			playersAttachment = BukkitTools.getPlayer(resident.getName()).addAttachment(plugin);
		
		/*
		 * Set all our Towny default permissions using reflection else
		 * bukkit will perform a recalculation of perms for each addition.
		 */

		try {
			@SuppressWarnings("unchecked")
			Map<String, Boolean> orig = (Map<String, Boolean>) permissions.get(playersAttachment);
			/*
			 *  Clear the map (faster than removing the attachment and recalculating)
			 */
			orig.clear();
			
			if (World.isUsingTowny()) {
				/*
				 * Fill with the fresh perm nodes
				 */
				orig.putAll(TownyPerms.getResidentPerms(resident));
				
				//System.out.print("Perms set for: " + resident.getName());
			}
			/*
			 * Tell bukkit to update it's permissions
			 */
			playersAttachment.getPermissible().recalculatePermissions();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		/*
		 * Store the attachment for future reference
		 */
		attachments.put(resident.getName(), playersAttachment);
		
	}
	
	/**
	 * Should only be called when a player leaves the server.
	 * 
	 * @param name
	 */
	public static void removeAttachment(String name) {
		
		if (attachments.containsKey(name))
			attachments.remove(name);
		
	}
	
	/**
	 * Update the permissions for all residents of a town (if online)
	 * 
	 * @param town
	 */
	public static void updateTownPerms(Town town) {
		
		for (Resident resident: town.getResidents())
			assignPermissions(resident, null);
		
	}
	
	/**
	 * Update the permissions for all residents of a nation (if online)
	 * 
	 * @param nation
	 */
	public static void updateNationPerms(Nation nation) {
		
		for (Town town: nation.getTowns())
			updateTownPerms(town);
		
	}

	/**
	 * Fetch a list of permission nodes
	 * 
	 * @param path
	 * @return a List of permission nodes.
	 */
	private static List<String> getList(String path) {

		if (perms.contains(path)) {
			return perms.getStringList(path);
		}
		return null;
	}
	
	/**
	 * Returns a sorted map of this residents current permissions.
	 * 
	 * @param resident
	 * @return a sorted Map of permission nodes
	 */
	public static LinkedHashMap<String, Boolean> getResidentPerms(Resident resident) {
		
		Set<String> permList = new HashSet<String>();
		
		// Start by adding the default perms everyone gets
		permList.addAll(getDefault());
		
		//Check for town membership
		if (resident.hasTown()) {
			permList.addAll(getTownDefault());
			// Is Mayor?
			if (resident.isMayor()) permList.addAll(getTownMayor());
				
			//Add town ranks here
			for (String rank: resident.getTownRanks()) {
				permList.addAll(getTownRank(rank));
			}
			
			//Check for nation membership
			if (resident.hasNation()) {
				permList.addAll(getNationDefault());
				// Is King?
				if (resident.isKing()) permList.addAll(getNationKing());
							
				//Add nation ranks here
				for (String rank: resident.getNationRanks()) {
					permList.addAll(getNationRank(rank));
				}
			}
		}
		
		List<String> playerPermArray = sort(new ArrayList<String>(permList));
		LinkedHashMap<String, Boolean> newPerms = new LinkedHashMap<String, Boolean>();

		Boolean value = false;
		for (String permission : playerPermArray) {
			value = (!permission.startsWith("-"));
			newPerms.put((value ? permission : permission.substring(1)), value);
		}
		
		
		
		return newPerms;
		
	}
	
	public static void registerPermissionNodes() {
		
		 plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new
		 Runnable(){

			@Override
			public void run() {

				Permission perm;
				
				/*
				 * Register Town ranks
				 */
				for (String rank : getTownRanks()) {
					perm = new
					Permission(PermissionNodes.TOWNY_COMMAND_TOWN_RANK.getNode(rank),
					"User can grant this town rank to others..",
					PermissionDefault.FALSE, null);
					perm.addParent(PermissionNodes.TOWNY_COMMAND_TOWN_RANK.getNode(), true);
				}
				
				/*
				 * Register Nation ranks
				 */
				for (String rank : getNationRanks()) {
					perm = new
					Permission(PermissionNodes.TOWNY_COMMAND_NATION_RANK.getNode(rank),
					"User can grant this town rank to others..",
					PermissionDefault.FALSE, null);
					perm.addParent(PermissionNodes.TOWNY_COMMAND_NATION_RANK.getNode(), true);
				}
			}
			 
		 },1);
	}

	/*
	 * Getter/Setters for TownyPerms
	 */
	
	/**
	 * Default permissions everyone gets
	 * 
	 * @return a List of permissions
	 */
	public static List<String> getDefault() {

		List<String> permsList = getList("nomad");
		return (permsList == null)? new ArrayList<String>() : permsList;
	}

	/*
	 * Town permission section
	 */

	/**
	 * Fetch a list of all available town ranks
	 * 
	 * @return a list of rank names.
	 */
	public static List<String> getTownRanks() {

		return new ArrayList<String>(((MemorySection) perms.get("towns.ranks")).getKeys(false));
	}

	/**
	 * Default permissions everyone in a town gets
	 * 
	 * @return a list of permissions
	 */
	public static List<String> getTownDefault() {
		
		List<String> permsList = getList("towns.default");
		return (permsList == null)? new ArrayList<String>() : permsList;
	}

	/**
	 * A town mayors permissions
	 * 
	 * @return a list of permissions
	 */
	public static List<String> getTownMayor() {

		List<String> permsList = getList("towns.mayor");
		return (permsList == null)? new ArrayList<String>() : permsList;
	}

	/**
	 * Get a specific ranks permissions
	 * 
	 * @param rank
	 * @return a List of permissions
	 */
	public static List<String> getTownRank(String rank) {

		List<String> permsList = getList("towns.ranks." + rank.toLowerCase());
		return (permsList == null)? new ArrayList<String>() : permsList;
	}

	/*
	 * Nation permission section
	 */

	/**
	 * Fetch a list of all available nation ranks
	 * 
	 * @return a list of rank names.
	 */
	public static List<String> getNationRanks() {

		return new ArrayList<String>(((MemorySection) perms.get("nations.ranks")).getKeys(false));
	}

	/**
	 * Default permissions everyone in a nation gets
	 * 
	 * @return a List of permissions
	 */
	public static List<String> getNationDefault() {

		List<String> permsList = getList("nations.default");
		return (permsList == null)? new ArrayList<String>() : permsList;
	}

	/**
	 * A nations kings permissions
	 * 
	 * @return a List of permissions
	 */
	public static List<String> getNationKing() {

		List<String> permsList = getList("nations.king");
		return (permsList == null)? new ArrayList<String>() : permsList;
	}

	/**
	 * Get a specific ranks permissions
	 * 
	 * @param rank
	 * @return a List of Permissions
	 */
	public static List<String> getNationRank(String rank) {

		List<String> permsList = getList("nations.ranks." + rank.toLowerCase());
		return (permsList == null)? new ArrayList<String>() : permsList;
	}
	
	/*
	 * Permission utility functions taken from GroupManager (which I wrote anyway).
	 */
	
	/**
	 * Update the list of permissions registered with bukkit
	 */
	public static void collectPermissions() {

		registeredPermissions.clear();

		for (Permission perm : BukkitTools.getPluginManager().getPermissions()) {
			registeredPermissions.put(perm.getName().toLowerCase(), perm);
		}

	}
	
	/**
	 * Sort a permission node list by parent/child
	 * 
	 * @param permList
	 * @return List sorted for priority
	 */
	private static List<String> sort(List<String> permList) {
		
		List<String> result = new ArrayList<String>();

		for (String key : permList) {
			String a = key.charAt(0) == '-' ? key.substring(1) : key;
			Map<String, Boolean> allchildren = getAllChildren(a, new HashSet<String>());
			if (allchildren != null) {

				ListIterator<String> itr = result.listIterator();

				while (itr.hasNext()) {
					String node = (String) itr.next();
					String b = node.charAt(0) == '-' ? node.substring(1) : node;

					// Insert the parent node before the child
					if (allchildren.containsKey(b)) {
						itr.set(key);
						itr.add(node);
						break;
					}
				}
			}
			if (!result.contains(key))
				result.add(key);
		}

		return result;
	}

	/**
	 * Fetch all permissions which are registered with superperms.
	 * {can include child nodes)
	 * 
	 * @param includeChildren
	 * @return List of all permission nodes
	 */
	public List<String> getAllRegisteredPermissions(boolean includeChildren) {

		List<String> perms = new ArrayList<String>();

		for (String key : registeredPermissions.keySet()) {
			if (!perms.contains(key)) {
				perms.add(key);

				if (includeChildren) {
					Map<String, Boolean> children = getAllChildren(key, new HashSet<String>());
					if (children != null) {
						for (String node : children.keySet())
							if (!perms.contains(node))
								perms.add(node);
					}
				}
			}

		}
		return perms;
	}

	/**
	 * Returns a map of ALL child permissions registered with bukkit
	 * null is empty
	 * 
	 * @param node
	 * @param playerPermArray current list of perms to check against for
	 *            negations
	 * @return Map of child permissions
	 */
	public static Map<String, Boolean> getAllChildren(String node, Set<String> playerPermArray) {

		LinkedList<String> stack = new LinkedList<String>();
		Map<String, Boolean> alreadyVisited = new HashMap<String, Boolean>();
		stack.push(node);
		alreadyVisited.put(node, true);

		while (!stack.isEmpty()) {
			String now = stack.pop();

			Map<String, Boolean> children = getChildren(now);

			if ((children != null) && (!playerPermArray.contains("-" + now))) {
				for (String childName : children.keySet()) {
					if (!alreadyVisited.containsKey(childName)) {
						stack.push(childName);
						alreadyVisited.put(childName, children.get(childName));
					}
				}
			}
		}
		alreadyVisited.remove(node);
		if (!alreadyVisited.isEmpty())
			return alreadyVisited;

		return null;
	}
	
	/**
	 * Returns a map of the child permissions (1 node deep) as registered with
	 * Bukkit.
	 * null is empty
	 * 
	 * @param node
	 * @return Map of child permissions
	 */
	public static Map<String, Boolean> getChildren(String node) {

		Permission perm = registeredPermissions.get(node.toLowerCase());
		if (perm == null)
			return null;

		return perm.getChildren();

	}

}
<file_sep>package com.palmergames.bukkit.towny;

import ca.xshade.bukkit.questioner.Questioner;
import ca.xshade.questionmanager.Option;
import ca.xshade.questionmanager.Question;
import com.earth2me.essentials.Essentials;
import com.nijiko.permissions.PermissionHandler;
import com.palmergames.bukkit.towny.command.*;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.exceptions.TownyException;
import com.palmergames.bukkit.towny.listeners.*;
import com.palmergames.bukkit.towny.object.*;
import com.palmergames.bukkit.towny.permissions.*;
import com.palmergames.bukkit.towny.questioner.TownyQuestionTask;
import com.palmergames.bukkit.towny.regen.TownyRegenAPI;
import com.palmergames.bukkit.towny.utils.PlayerCacheUtil;
import com.palmergames.bukkit.towny.war.flagwar.TownyWar;
import com.palmergames.bukkit.towny.war.flagwar.listeners.TownyWarBlockListener;
import com.palmergames.bukkit.towny.war.flagwar.listeners.TownyWarCustomListener;
import com.palmergames.bukkit.towny.war.flagwar.listeners.TownyWarEntityListener;
import com.palmergames.bukkit.util.BukkitTools;
import com.palmergames.util.FileMgmt;
import com.palmergames.util.JavaUtil;
import com.palmergames.util.StringMgmt;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Towny Plugin for Bukkit
 * 
 * Website: http://code.google.com/a/eclipselabs.org/p/towny/ Source:
 * http://code.google.com/a/eclipselabs.org/p/towny/source/browse/
 * 
 * @author Shade, ElgarL
 */

public class Towny extends JavaPlugin {

	private String version = "2.0.0";

	public static PermissionHandler permissionHandler;

	private final TownyPlayerListener playerListener = new TownyPlayerListener(this);
	private final TownyBlockListener blockListener = new TownyBlockListener(this);
	private final TownyCustomListener customListener = new TownyCustomListener(this);
	private final TownyEntityListener entityListener = new TownyEntityListener(this);
	private final TownyWeatherListener weatherListener = new TownyWeatherListener(this);
	private final TownyEntityMonitorListener entityMonitorListener = new TownyEntityMonitorListener(this);
	private final TownyWorldListener worldListener = new TownyWorldListener(this);
	private final TownyWarBlockListener townyWarBlockListener = new TownyWarBlockListener(this);
	private final TownyWarCustomListener townyWarCustomListener = new TownyWarCustomListener(this);
	private final TownyWarEntityListener townyWarEntityListener = new TownyWarEntityListener(this);
	
	private TownyUniverse townyUniverse;
	
	private Map<String, PlayerCache> playerCache = Collections.synchronizedMap(new HashMap<String, PlayerCache>());

	private Essentials essentials = null;
	private boolean citizens2 = false;

	private boolean error = false;

	@Override
	public void onEnable() {

		System.out.println("====================      Towny      ========================");

		version = this.getDescription().getVersion();

		townyUniverse = new TownyUniverse(this);
		
		// Setup classes
		BukkitTools.initialize(this);
		TownyTimerHandler.initialize(this);
		TownyEconomyHandler.initialize(this);
		TownyFormatter.initialize(this);
		TownyRegenAPI.initialize(this);
		PlayerCacheUtil.initialize(this);
		TownyPerms.initialize(this);

		if (load()) {
			// Setup bukkit command interfaces
			getCommand("townyadmin").setExecutor(new TownyAdminCommand(this));
			getCommand("townyworld").setExecutor(new TownyWorldCommand(this));
			getCommand("resident").setExecutor(new ResidentCommand(this));
			getCommand("towny").setExecutor(new TownyCommand(this));
			getCommand("town").setExecutor(new TownCommand(this));
			getCommand("nation").setExecutor(new NationCommand(this));
			getCommand("plot").setExecutor(new PlotCommand(this));

			TownyWar.onEnable();

			if (TownySettings.isTownyUpdating(getVersion()))
				update();

			// Register all child permissions for ranks
			TownyPerms.registerPermissionNodes();
		}

		registerEvents();

		TownyLogger.log.info("=============================================================");
		if (isError())
			TownyLogger.log.info("[WARNING] - ***** SAFE MODE ***** " + version);
		else
			TownyLogger.log.info("[Towny] Version: " + version + " - Mod Enabled");
		TownyLogger.log.info("=============================================================");

		if (!isError()) {
			// Re login anyone online. (In case of plugin reloading)
			for (Player player : BukkitTools.getOnlinePlayers())
				if (player != null)
					try {
						getTownyUniverse().onLogin(player);
					} catch (TownyException x) {
						TownyMessaging.sendErrorMsg(player, x.getMessage());
					}
		}
	}

	public void SetWorldFlags() {

		for (Town town : TownyUniverse.getDataSource().getTowns()) {
			TownyMessaging.sendDebugMsg("[Towny] Setting flags for: " + town.getName());

			if (town.getWorld() == null) {
				TownyLogger.log.warning("[Towny Error] Detected an error with the world files. Attempting to repair");
				if (town.hasHomeBlock())
					try {
						TownyWorld world = town.getHomeBlock().getWorld();
						if (!world.hasTown(town)) {
							world.addTown(town);
							TownyUniverse.getDataSource().saveTown(town);
							TownyUniverse.getDataSource().saveWorld(world);
						}
					} catch (TownyException e) {
						// Error fetching homeblock
						TownyLogger.log.warning("[Towny Error] Failed get world data for: " + town.getName());
					}
				else
					TownyLogger.log.warning("[Towny Error] No Homeblock - Failed to detect world for: " + town.getName());
			}
		}

	}

	@Override
	public void onDisable() {

		System.out.println("==============================================================");

		if (TownyUniverse.getDataSource() != null && error == false)
			TownyUniverse.getDataSource().saveQueues();

		if (error == false)
			TownyWar.onDisable();

		if (TownyUniverse.isWarTime())
			getTownyUniverse().getWarEvent().toggleEnd();

		TownyTimerHandler.toggleTownyRepeatingTimer(false);
		TownyTimerHandler.toggleDailyTimer(false);
		TownyTimerHandler.toggleMobRemoval(false);
		TownyTimerHandler.toggleHealthRegen(false);
		TownyTimerHandler.toggleTeleportWarmup(false);
		
		TownyRegenAPI.cancelProtectionRegenTasks();

		playerCache.clear();

		townyUniverse = null;

		System.out.println("[Towny] Version: " + version + " - Mod Disabled");
		System.out.println("=============================================================");

		TownyLogger.shutDown();
	}

	public boolean load() {

		Pattern pattern = Pattern.compile("-b(\\d*?)jnks", Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(getServer().getVersion());

		//TownyEconomyHandler.setupEconomy();

		if (!townyUniverse.loadSettings()) {
			setError(true);
			//getServer().getPluginManager().disablePlugin(this);
			return false;
		}

		setupLogger();

		if (TownySettings.isBypassVersionCheck()) {
			TownyLogger.log.info("[Towny] Bypassing CraftBukkit Version check.");
		} else {

			int bukkitVer = TownySettings.getMinBukkitVersion();

			if (!matcher.find() || matcher.group(1) == null) {
				error = true;
				TownyLogger.log.severe("[Towny Error] Unable to read CraftBukkit Version.");
				TownyLogger.log.severe("[Towny Error] Towny requires version " + bukkitVer + " or higher.");
				TownyLogger.log.severe("[Towny Error] Check your CraftBukkit version or set 'bypass_version_check' to true in the Towny config.");
				getServer().getPluginManager().disablePlugin(this);
				return false;
			}

			int curBuild = Integer.parseInt(matcher.group(1));

			if (curBuild < bukkitVer) {
				error = true;
				TownyLogger.log.severe("[Towny Error] CraftBukkit Version (" + curBuild + ") is outdated! ");
				TownyLogger.log.severe("[Towny Error] Towny requires version " + bukkitVer + " or higher.");
				getServer().getPluginManager().disablePlugin(this);
				return false;
			}

		}

		//Coord.setCellSize(TownySettings.getTownBlockSize());

		//TownyCommand.setUniverse(townyUniverse);

		checkPlugins();

		SetWorldFlags();

		//make sure the timers are stopped for a reset
		TownyTimerHandler.toggleTownyRepeatingTimer(false);
		TownyTimerHandler.toggleDailyTimer(false);
		TownyTimerHandler.toggleMobRemoval(false);
		TownyTimerHandler.toggleHealthRegen(false);
		TownyTimerHandler.toggleTeleportWarmup(false);

		//Start timers
		TownyTimerHandler.toggleTownyRepeatingTimer(true);
		TownyTimerHandler.toggleDailyTimer(true);
		TownyTimerHandler.toggleMobRemoval(true);
		TownyTimerHandler.toggleHealthRegen(TownySettings.hasHealthRegen());
		TownyTimerHandler.toggleTeleportWarmup(TownySettings.getTeleportWarmupTime() > 0);
		resetCache();

		return true;
	}

	private void checkPlugins() {

		List<String> using = new ArrayList<String>();
		Plugin test;

		if (TownySettings.isUsingPermissions()) {
			test = getServer().getPluginManager().getPlugin("GroupManager");
			if (test != null) {
				//groupManager = (GroupManager)test;
				this.getTownyUniverse().setPermissionSource(new GroupManagerSource(this, test));
				using.add(String.format("%s v%s", "GroupManager", test.getDescription().getVersion()));
			} else {
				test = getServer().getPluginManager().getPlugin("PermissionsEx");
				if (test != null) {
					//permissions = (PermissionsEX)test;
					getTownyUniverse().setPermissionSource(new PEXSource(this, test));
					using.add(String.format("%s v%s", "PermissionsEX", test.getDescription().getVersion()));
				} else {
					test = getServer().getPluginManager().getPlugin("bPermissions");
					if (test != null) {
						//permissions = (Permissions)test;
						getTownyUniverse().setPermissionSource(new bPermsSource(this, test));
						using.add(String.format("%s v%s", "bPermissions", test.getDescription().getVersion()));
					} else {
						test = getServer().getPluginManager().getPlugin("Permissions");
						if (test != null) {
							//permissions = (Permissions)test;
							getTownyUniverse().setPermissionSource(new Perms3Source(this, test));
							using.add(String.format("%s v%s", "Permissions", test.getDescription().getVersion()));
						} else {
							getTownyUniverse().setPermissionSource(new BukkitPermSource(this));
							using.add("BukkitPermissions");
						}
					}
				}
			}
		} else {
			// Not using Permissions
			getTownyUniverse().setPermissionSource(new NullPermSource(this));
		}

		if (TownySettings.isUsingEconomy()) {

			if (TownyEconomyHandler.setupEconomy())
				using.add(TownyEconomyHandler.getVersion());
			else
				TownyMessaging.sendErrorMsg("No compatible Economy plugins found. You need iConomy 5.01, or the vault/Register.jar with any of the supported eco systems.");
		}

		test = getServer().getPluginManager().getPlugin("Essentials");
		if (test == null)
			TownySettings.setUsingEssentials(false);
		else if (TownySettings.isUsingEssentials()) {
			this.essentials = (Essentials) test;
			using.add(String.format("%s v%s", "Essentials", test.getDescription().getVersion()));
		}

		test = getServer().getPluginManager().getPlugin("Questioner");
		if (test == null)
			TownySettings.setUsingQuestioner(false);
		else if (TownySettings.isUsingQuestioner())
			using.add(String.format("%s v%s", "Questioner", test.getDescription().getVersion()));

		/*
		 * Test for Citizens2 so we can avoid removing their NPC's
		 */
		test = getServer().getPluginManager().getPlugin("Citizens");
		if (test != null) {
			citizens2 = test.getDescription().getVersion().startsWith("2");
		}

		if (using.size() > 0)
			TownyLogger.log.info("[Towny] Using: " + StringMgmt.join(using, ", "));
	}

	private void registerEvents() {

		final PluginManager pluginManager = getServer().getPluginManager();

		if (!isError()) {
			// Have War Events get launched before regular events.
			pluginManager.registerEvents(townyWarBlockListener, this);
			pluginManager.registerEvents(townyWarEntityListener, this);

			// Manage player deaths and death payments
			pluginManager.registerEvents(entityMonitorListener, this);
			pluginManager.registerEvents(weatherListener, this);
			pluginManager.registerEvents(townyWarCustomListener, this);
			pluginManager.registerEvents(customListener, this);
			pluginManager.registerEvents(worldListener, this);

		}

		// Always register these events.
		pluginManager.registerEvents(playerListener, this);
		pluginManager.registerEvents(blockListener, this);
		pluginManager.registerEvents(entityListener, this);

	}

	private void update() {

		try {
			List<String> changeLog = JavaUtil.readTextFromJar("/ChangeLog.txt");
			boolean display = false;
			TownyLogger.log.info("------------------------------------");
			TownyLogger.log.info("[Towny] ChangeLog up until v" + getVersion());
			String lastVersion = TownySettings.getLastRunVersion(getVersion());
			for (String line : changeLog) { //TODO: crawl from the bottom, then past from that index.
				if (line.startsWith("v" + lastVersion))
					display = true;
				if (display && line.replaceAll(" ", "").replaceAll("\t", "").length() > 0)
					TownyLogger.log.info(line);
			}
			TownyLogger.log.info("------------------------------------");
		} catch (IOException e) {
			TownyMessaging.sendDebugMsg("Could not read ChangeLog.txt");
		}
		TownySettings.setLastRunVersion(getVersion());
	}
	
	/**
	 * Fetch the TownyUniverse instance
	 * 
	 * @return TownyUniverse
	 */
	public TownyUniverse getTownyUniverse() {

		return townyUniverse;
	}

	public String getVersion() {

		return version;
	}
	
	/**
	 * @return the error
	 */
	public boolean isError() {

		return error;
	}

	/**
	 * @param error the error to set
	 */
	protected void setError(boolean error) {

		this.error = error;
	}

	// is permissions active
	public boolean isPermissions() {

		return TownySettings.isUsingPermissions();
	}

	// is Essentials active
	public boolean isEssentials() {

		return (TownySettings.isUsingEssentials() && (this.essentials != null));
	}

	// is Citizens2 active
	public boolean isCitizens2() {

		return citizens2;
	}

	/**
	 * @return Essentials object
	 * @throws TownyException
	 */
	public Essentials getEssentials() throws TownyException {

		if (essentials == null)
			throw new TownyException("Essentials is not installed, or not enabled!");
		else
			return essentials;
	}

	public World getServerWorld(String name) throws NotRegisteredException {

		for (World world : BukkitTools.getWorlds())
			if (world.getName().equals(name))
				return world;

		throw new NotRegisteredException(String.format("A world called '$%s' has not been registered.", name));
	}

	public boolean hasCache(Player player) {

		return playerCache.containsKey(player.getName().toLowerCase());
	}

	public void newCache(Player player) {

		try {
			getTownyUniverse();
			playerCache.put(player.getName().toLowerCase(), new PlayerCache(TownyUniverse.getDataSource().getWorld(player.getWorld().getName()), player));
		} catch (NotRegisteredException e) {
			TownyMessaging.sendErrorMsg(player, "Could not create permission cache for this world (" + player.getWorld().getName() + ".");
		}

	}

	public void deleteCache(Player player) {

		deleteCache(player.getName());
	}

	public void deleteCache(String name) {

		playerCache.remove(name.toLowerCase());
	}

	/**
	 * Fetch the current players cache
	 * Creates a new one, if one doesn't exist.
	 * 
	 * @param player
	 * @return the current (or new) cache for this player.
	 */
	public PlayerCache getCache(Player player) {

		if (!hasCache(player)) {
			newCache(player);
			getCache(player).setLastTownBlock(new WorldCoord(player.getWorld().getName(), Coord.parseCoord(player)));
		}

		return playerCache.get(player.getName().toLowerCase());
	}

	/**
	 * Resets all Online player caches, retaining their location info.
	 */
	public void resetCache() {

		for (Player player : BukkitTools.getOnlinePlayers())
			if (player != null)
				getCache(player).resetAndUpdate(new WorldCoord(player.getWorld().getName(), Coord.parseCoord(player))); //Automatically resets permissions.
	}
	
	/**
	 * Resets all Online player caches if their location equals this one
	 */
	public void updateCache(WorldCoord worldCoord) {

		for (Player player : BukkitTools.getOnlinePlayers())
			if (player != null)
				if (Coord.parseCoord(player).equals(worldCoord))
					getCache(player).resetAndUpdate(worldCoord); //Automatically resets permissions.
	}

	/**
	 * Resets all Online player caches if their location has changed
	 */
	public void updateCache() {

		WorldCoord worldCoord = null;
		
		for (Player player : BukkitTools.getOnlinePlayers()) {
			if (player != null) {
				worldCoord = new WorldCoord(player.getWorld().getName(), Coord.parseCoord(player));
				PlayerCache cache = getCache(player);
				if (cache.getLastTownBlock() != worldCoord)
					cache.resetAndUpdate(worldCoord);
			}
		}
	}

	/**
	 * Resets a specific players cache if their location has changed
	 * 
	 * @param player
	 */
	public void updateCache(Player player) {

		WorldCoord worldCoord = new WorldCoord(player.getWorld().getName(), Coord.parseCoord(player));
		PlayerCache cache = getCache(player);
		
		if (cache.getLastTownBlock() != worldCoord)
			cache.resetAndUpdate(worldCoord);
	}
	
	/**
	 * Resets a specific players cache
	 * 
	 * @param player
	 */
	public void resetCache(Player player) {

		getCache(player).resetAndUpdate(new WorldCoord(player.getWorld().getName(), Coord.parseCoord(player)));
	}

	public void setPlayerMode(Player player, String[] modes, boolean notify) {

		if (player == null)
			return;
		
		try {
			Resident resident = TownyUniverse.getDataSource().getResident(player.getName());
			resident.setModes(modes, notify);
					
		} catch (NotRegisteredException e) {
			// Resident doesn't exist
		}
	}

	/**
	 * Remove ALL current modes (and set the defaults)
	 * 
	 * @param player
	 */
	public void removePlayerMode(Player player) {
		
		try {
			Resident resident = TownyUniverse.getDataSource().getResident(player.getName());
			resident.clearModes();
			
		} catch (NotRegisteredException e) {
			// Resident doesn't exist
		}

	}

	/**
	 * Fetch a list of all the players current modes.
	 * 
	 * @param player
	 * @return list of modes
	 */
	public List<String> getPlayerMode(Player player) {

		return getPlayerMode(player.getName());
	}

	public List<String> getPlayerMode(String name) {

		try {
			Resident resident = TownyUniverse.getDataSource().getResident(name);
			return resident.getModes();
			
		} catch (NotRegisteredException e) {
			// Resident doesn't exist
			return null;
		}
	}

	/**
	 * Check if the player has a specific mode.
	 * 
	 * @param player
	 * @param mode
	 * @return true if the mode is present.
	 */
	public boolean hasPlayerMode(Player player, String mode) {

		return hasPlayerMode(player.getName(), mode);
	}
	
	public boolean hasPlayerMode(String name, String mode) {

		try {
			Resident resident = TownyUniverse.getDataSource().getResident(name);
			return resident.hasMode(mode);
			
		} catch (NotRegisteredException e) {
			// Resident doesn't exist
			return false;
		}
	}

	public String getConfigPath() {

		return getDataFolder().getPath() + FileMgmt.fileSeparator() + "settings" + FileMgmt.fileSeparator() + "config.yml";
	}

	public Object getSetting(String root) {

		return TownySettings.getProperty(root);
	}

	public void log(String msg) {

		if (TownySettings.isLogging())
			TownyLogger.log.info(ChatColor.stripColor(msg));
	}

	public void setupLogger() {

		TownyLogger.setup(getTownyUniverse().getRootFolder(), TownySettings.isAppendingToLog());
	}

	public void appendQuestion(Questioner questioner, Question question) throws Exception {

		for (Option option : question.getOptions())
			if (option.getReaction() instanceof TownyQuestionTask)
				((TownyQuestionTask) option.getReaction()).setTowny(this);
		questioner.appendQuestion(question);
	}

	public boolean parseOnOff(String s) throws Exception {

		if (s.equalsIgnoreCase("on"))
			return true;
		else if (s.equalsIgnoreCase("off"))
			return false;
		else
			throw new Exception(String.format(TownySettings.getLangString("msg_err_invalid_input"), " on/off."));
	}
}
<file_sep>package com.palmergames.bukkit.towny.questioner;

import com.palmergames.bukkit.towny.object.Town;

public class TownQuestionTask extends TownyQuestionTask {

	protected Town town;

	public TownQuestionTask(Town town) {

		this.town = town;
	}

	public Town getTown() {

		return town;
	}

	@Override
	public void run() {

	}

}
<file_sep>package com.palmergames.bukkit.towny.tasks;

import java.util.TimerTask;

import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.TownyUniverse;
import com.palmergames.bukkit.towny.permissions.PermissionNodes;
import com.palmergames.bukkit.util.BukkitTools;

/**
 * @author ElgarL
 * 
 */
public class SetDefaultModes extends TimerTask {

	protected String name;
	protected boolean notify;

	public SetDefaultModes(String name, boolean notify) {

		this.name = name;
		this.notify = notify;
	}

	@Override
	public void run() {

		// Is the player still available
		if (!BukkitTools.isOnline(name))
			return;

		//setup default modes
		String[] modes = TownyUniverse.getPermissionSource().getPlayerPermissionStringNode(name, PermissionNodes.TOWNY_DEFAULT_MODES.getNode()).split(",");
		try {
			TownyUniverse.getDataSource().getResident(name).setModes(modes, notify);
		} catch (NotRegisteredException e) {
			// No resident by this name.
		}
	}

}<file_sep><?xml version="1.0" encoding="UTF-8"?>
<project name="Towny" default="jar" basedir=".">
    <property name="build" value="bin"/>
    <property file="build.properties"/>
    
    <target name="clean">
        <delete dir="${build}"/>
    </target>

    <target name="init" depends="clean">
        <mkdir dir="${build}"/>
    </target>   
    
    <target name="compile" depends="init">
        <!-- Compile the java code -->
        <javac srcdir="src" destdir="${build}" includeantruntime="false" target="1.6" source="1.6">
            <classpath>
                <pathelement location="${env.LIB}/bukkit.jar"/>
                <pathelement location="${env.LIB}/bpermissions.jar"/>
                <pathelement location="${env.LIB}/Essentials.jar"/>
                <pathelement location="${env.LIB}/EssentialsGroupManager.jar"/>
                <pathelement location="${env.LIB}/Permissions.jar"/>
                <pathelement location="${env.LIB}/PermissionsEx.jar"/>
                <pathelement location="${env.LIB}/PermissionsBukkit.jar"/>
                <pathelement location="${env.LIB}/Register.jar"/>
                <pathelement location="${env.LIB}/iConomy.jar"/>
                <pathelement location="${env.LIB}/Questioner.jar"/>
                <pathelement location="${env.LIB}/Vault.jar"/>
                <pathelement location="${env.LIB}/citizensapi-2.0-SNAPSHOT.jar"/>
            </classpath>
        </javac>
    </target>   
    
    <target name="jar" depends="compile">
        <!-- Build the jar file -->
        <jar basedir="${build}" destfile="${env.LIB}/Towny.jar">
	        <fileset dir="./src" includes="ChangeLog.txt"/>
        	<fileset dir="./src" includes="english.yml"/>
        	<fileset dir="./src" includes="german.yml"/>
        	<fileset dir="./src" includes="plugin.yml"/>
        	<fileset dir="./src" includes="spanish.yml"/>
        	<fileset dir="./src" includes="townyperms.yml"/>
          <fileset dir="./src" includes="ToDo.txt"/>
        </jar>
    </target>
</project>