public enum ClickAction {
        
   /**
    * Open a URL for a user when clicked
    * 
    */
    OPEN_URL,
   /**
    * Run a command for a user when clicked
    * 
    */
    RUN_COMMAND,
   /**
    * Suggest a command for a user when clicked
    * 
    */
    SUGGEST_COMMAND,
   /**
    * Change the page for a user when clicked
    * 
    */
    CHANGE_PAGE
        
} public class ConfigHandler {
	
	private HashMap < String, Boolean > noSource = new HashMap < String, Boolean > ();
	
	private boolean Generating = false;
	private int permissionLength = 2;
	private int listLength = 1;
	
	private YamlConfiguration itemsFile = new YamlConfiguration();
	private YamlConfiguration configFile = new YamlConfiguration();
	private YamlConfiguration langFile = new YamlConfiguration();
	
	private static ConfigHandler config;
	
   /**
    * Registers the command executors and events.
    * 
    */
	public void registerEvents() {
	    ItemJoin.getInstance().getCommand("itemjoin").setExecutor(new ChatExecutor());
	    ItemJoin.getInstance().getCommand("itemjoin").setTabCompleter(new ChatTab());
		ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Interfaces(), ItemJoin.getInstance());
		this.registerGlow();
	}
	
   /**
    * Copies files into memory.
    * 
    */
	public void copyFiles() {
		this.copyFile("config.yml", "config-Version", 8);
		this.copyFile("items.yml", "items-Version", 8);
		this.copyFile(LanguageAPI.getLang(true).getFile(), LanguageAPI.getLang(false).getFile().split("-")[0] + "-Version", 8);
	}
	
   /**
    * Registers new instances of the plugin classes.
    * 
    * @param silent - If any messages should be sent.
    */
	private void registerClasses(final boolean silent) {
		final boolean reload = ItemJoin.getInstance().isStarted();
		ItemJoin.getInstance().setStarted(false);
		ServerUtils.clearErrorStatements();
		LogHandler.getFilter(true);
		BungeeAPI.getBungee(true);
		this.copyFiles();
		DependAPI.getDepends(true);
		SchedulerUtils.runAsync(() -> {
			int customItems = (this.getConfigurationSection() != null ? this.getConfigurationSection().getKeys(false).size() : 0);
			if (!silent) {
				DependAPI.getDepends(false).sendUtilityDepends();
				ServerUtils.logInfo(customItems + " Custom item(s) loaded!");
			}
			this.registerPrevent();
			SQL.newData(reload);
		}); {
				ItemDesigner.getDesigner(true); {
					SchedulerUtils.runSingleAsync(() -> {
						ItemJoin.getInstance().setStarted(true);
						this.setPages();
					}); {
					SchedulerUtils.runAsyncLater(100L, () -> {
						final MetricsAPI metrics = new MetricsAPI(ItemJoin.getInstance(), 4115);
						DependAPI.getDepends(false).addCustomCharts(metrics);
						ServerUtils.sendErrorStatements(null);
					});
				}
			}
		}
	}
	
   /**
    * Registers the GLOBAL prevent actions.
    * 
    */
	private void registerPrevent() {
		if (((this.clearEnabled("Join") || this.triggerEnabled("Join") || this.triggerEnabled("First-Join")) || StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "JOIN")) && !StringUtils.isRegistered(PlayerJoin.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerJoin(), ItemJoin.getInstance());
		}
		if (((this.clearEnabled("World-Switch") || this.triggerEnabled("World-Switch")) || StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "WORLD-SWITCH")) && !StringUtils.isRegistered(WorldSwitch.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new WorldSwitch(), ItemJoin.getInstance());
		}
		if (((this.clearEnabled("Quit") || this.triggerEnabled("Quit")) || StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "QUIT")) && !StringUtils.isRegistered(PlayerQuit.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerQuit(), ItemJoin.getInstance());
		}
		if ((StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "RESPAWN") || this.triggerEnabled("Respawn")) && !StringUtils.isRegistered(Respawn.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Respawn(), ItemJoin.getInstance());
		}
		if (StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "GAMEMODE-SWITCH") && !StringUtils.isRegistered(LimitSwitch.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new LimitSwitch(), ItemJoin.getInstance());
		}
		if ((this.clearEnabled("Region-Enter") || StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "REGION-ENTER")) && !StringUtils.isRegistered(PlayerGuard.class.getSimpleName()) && DependAPI.getDepends(false).getGuard().guardEnabled()) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerGuard(), ItemJoin.getInstance());
		}
		if (StringUtils.containsIgnoreCase(this.getHotbarTriggers(), "REGION-LEAVE") && !StringUtils.isRegistered(PlayerGuard.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerGuard(), ItemJoin.getInstance());
		}
		if (!StringUtils.isRegistered(PlayerLogin.class.getSimpleName())) { ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerLogin(), ItemJoin.getInstance()); }
		if ((!StringUtils.splitIgnoreCase(this.getPrevent("Pickups"), "FALSE", ",") && !StringUtils.splitIgnoreCase(this.getPrevent("Pickups"), "DISABLED", ","))) {
			if (ServerUtils.hasSpecificUpdate("1_12") && ReflectionUtils.getBukkitClass("event.entity.EntityPickupItemEvent") != null && !StringUtils.isRegistered(Pickups.class.getSimpleName())) { 
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Pickups(), ItemJoin.getInstance()); 
			} else { LegacyAPI.registerPickups(); }
		}
		if ((!StringUtils.splitIgnoreCase(this.getPrevent("itemMovement"), "FALSE", ",") && !StringUtils.splitIgnoreCase(this.getPrevent("itemMovement"), "DISABLED", ","))) {
			if (!StringUtils.isRegistered(Clicking.class.getSimpleName())) { 
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Clicking(), ItemJoin.getInstance()); 
				if (ServerUtils.hasSpecificUpdate("1_8") && !DependAPI.getDepends(false).protocolEnabled() && !ProtocolManager.isHandling()) { ProtocolManager.handleProtocols(); }
				else if (ServerUtils.hasSpecificUpdate("1_8") && DependAPI.getDepends(false).protocolEnabled() && !ProtocolAPI.isHandling()) { ProtocolAPI.handleProtocols(); }
			}
		}
		if ((!StringUtils.splitIgnoreCase(this.getPrevent("Self-Drops"), "FALSE", ",") && !StringUtils.splitIgnoreCase(this.getPrevent("Self-Drops"), "DISABLED", ","))
		|| (!StringUtils.splitIgnoreCase(this.getPrevent("Death-Drops"), "FALSE", ",") && !StringUtils.splitIgnoreCase(this.getPrevent("Death-Drops"), "DISABLED", ","))) {
			if (!StringUtils.isRegistered(Drops.class.getSimpleName())) { ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Drops(), ItemJoin.getInstance()); }
		}
	}
	
   /**
    * Registers the glow enchantment.
    * 
    */
    public void registerGlow() {
    	if (ServerUtils.hasSpecificUpdate("1_13")) {
	    	try {
	    		Field f = Enchantment.class.getDeclaredField("acceptingNew");
	    		f.setAccessible(true);
	    		f.set(null, true);
	    		Glow glow = new Glow();
	    		Enchantment.registerEnchantment(glow);
	    	} catch (IllegalArgumentException e) { } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
    	}
    }

   /**
    * Gets the file from the specified path.
    * 
    * @param path - The File to be fetched.
    * @return The file.
    */
	public FileConfiguration getFile(final String path) {
		final File file = new File(ItemJoin.getInstance().getDataFolder(), path);
		if (this.configFile == null) { this.getSource(path); }
		try {
			return this.getLoadedConfig(file, false);
		} catch (Exception e) {
			ServerUtils.sendSevereTrace(e);
			ServerUtils.logSevere("Cannot load " + file.getName() + " from disk!");
		}
		return null;
	}
	
   /**
    * Gets the source file from the specified path.
    * 
    * @param path - The File to be loaded.
    * @return The source file.
    */
	public FileConfiguration getSource(final String path) {
		final File file = new File(ItemJoin.getInstance().getDataFolder(), path);
		if (!(file).exists()) {
			try {
				InputStream source;
				final File dataDir = ItemJoin.getInstance().getDataFolder();
				if (!dataDir.exists()) { dataDir.mkdir(); }
				if (!path.contains("lang.yml")) { source = ItemJoin.getInstance().getResource("files/configs/" + path); } 
				else { source = ItemJoin.getInstance().getResource("files/locales/" + path); }
        		if (!file.exists()) { Files.copy(source, file.toPath(), new CopyOption[0]); }
				if (path.contains("items.yml")) { this.Generating = true; }
			} catch (Exception e) {
				ServerUtils.sendSevereTrace(e);
				ServerUtils.logWarn("Cannot save " + path + " to disk!");
				this.noSource.put(path, true);
				return null;
			}
		}
		try {
			YamlConfiguration config = this.getLoadedConfig(file, true);
			this.noSource.put(path, false);
			return config;
		} catch (Exception e) {
			ServerUtils.sendSevereTrace(e);
			ServerUtils.logSevere("Cannot load " + file.getName() + " from disk!");
			this.noSource.put(file.getName(), true);
		}
		return null;
	}

   /**
    * Gets the file and loads it into memory if specified.
    * 
    * @param file - The file to be loaded.
    * @param commit - If the File should be committed to memory.
    * @return The Memory loaded config file.
    */
	public YamlConfiguration getLoadedConfig(final File file, final boolean commit) throws Exception {
		if (file.getName().contains("items.yml")) {
			if (commit) { this.itemsFile.load(file); }
			return this.itemsFile;
		} else if (file.getName().contains("config.yml")) {
			if (commit) { this.configFile.load(file); }
			return this.configFile;
		} else if (file.getName().contains("lang.yml")) {
			if (commit) { this.langFile.load(file); }
			return this.langFile;
		}
		return null;
	}

   /**
    * Copies the specified config file to the data folder.
    * 
    * @param configFile - The name and extension of the config file to be copied.
    * @param version - The version String to be checked in the config file.
    * @param id - The expected version id to be found in the config file.
    */
	private void copyFile(final String configFile, final String version, final int id) {
		this.getSource(configFile);
		File File = new File(ItemJoin.getInstance().getDataFolder(), configFile);
		if (File.exists() && !this.noSource.get(configFile) && this.getFile(configFile).getInt(version) != id) {
			InputStream source;
			if (!configFile.contains("lang.yml")) { source = ItemJoin.getInstance().getResource("files/configs/" + configFile); } 
			else { source = ItemJoin.getInstance().getResource("files/locales/" + configFile); }
			if (source != null) {
				String[] namePart = configFile.split("\\.");
				String renameFile = namePart[0] + "-old-" + StringUtils.getRandom(1, 50000) + namePart[1];
				File renamedFile = new File(ItemJoin.getInstance().getDataFolder(), renameFile);
				if (!renamedFile.exists()) {
					File.renameTo(renamedFile);
					File copyFile = new File(ItemJoin.getInstance().getDataFolder(), configFile);
					copyFile.delete();
					this.getSource(configFile);
					ServerUtils.logWarn("Your " + configFile + " is out of date and new options are available, generating a new one!");
				}
			}
		} else if (this.noSource.get(configFile)) {
			ServerUtils.logSevere("Your " + configFile + " is not using proper YAML Syntax and will not be loaded!");
			ServerUtils.logSevere("Check your YAML formatting by using a YAML-PARSER such as http://yaml-online-parser.appspot.com/");
		}
		if (!this.noSource.get(configFile)) { 
			if (this.Generating && configFile.equalsIgnoreCase("items.yml")) { 
				this.generateItemsFile();
				this.getSource("items.yml");
				this.Generating = false;
			}
			this.getFile(configFile).options().copyDefaults(false);
			if (configFile.contains("lang.yml")) { LanguageAPI.getLang(false).setPrefix(); }
		}
	}
	
   /**
    * Saves the changed configuration data to the File.
    * 
    * @param dataFile - The FileConfiguration being modified.
    * @param file - The file name being accessed.
    */
	public void saveFile(final FileConfiguration dataFile, final File fileFolder, final String file) {
		try {
			dataFile.save(fileFolder); 
			this.getSource(file); 
			this.getFile(file).options().copyDefaults(false); 
		} catch (Exception e) { 
			ItemJoin.getInstance().getServer().getLogger().severe("Could not save data to the " + file + " data file!"); 
			ServerUtils.sendDebugTrace(e); 
		}	
	}
	
   /**
    * Softly reloads the configuration files.
    * Usefully when editing booleans.
    * 
    */
	public void softReload() {
		this.copyFiles();
		this.registerPrevent();
	}
	
   /**
    * Properly reloads the configuration files.
    * 
    * @param silent - If any messages should be sent.
    */
	public void reloadConfigs(final boolean silent) {
		ItemUtilities.getUtilities().closeAnimations();
		ItemUtilities.getUtilities().delToggleCommands();
		ItemUtilities.getUtilities().clearItems();
		config = new ConfigHandler(); 
        config.registerClasses(silent);
	}
	
   /**
    * Sets the number of list and permission pages.
    * 
    */
	public void setPages() {
		SchedulerUtils.runAsync(() -> {
			int customItems = (this.getConfigurationSection() != null ? this.getConfigurationSection().getKeys(false).size() : 0);
			if (customItems > 15) {
				this.permissionLength = (int) Math.ceil((double)customItems / 15) + 1;
			}
			
			int listCount = 0;
			for (World world: Bukkit.getWorlds()) {
				List < String > listItems = new ArrayList < String > ();
				listCount++;
				for (ItemMap itemMap: ItemUtilities.getUtilities().getItems()) {
					if (!listItems.contains(itemMap.getConfigName()) && itemMap.inWorld(world)) {
						listCount++;
						listItems.add(itemMap.getConfigName());
					}
				}
			}
			
			if (listCount > 15) {
				this.listLength = (int) Math.ceil((double)listCount / 15);
			}
		});
	}
	
   /**
    * Gets the number of permission pages.
    * 
    * @return The number of permission pages.
    */
	public int getPermissionPages() {
		return this.permissionLength;
	}
	
   /**
    * Gets the number of list pages.
    * 
    * @return The number of list pages.
    */
	public int getListPages() {
		return this.listLength;
	}
	
   /**
    * Gets the Hotbar slot that is defined to be set.
    * 
    * @return The Integer hotbar value.
    */
	public int getHotbarSlot() { 
		if (this.getFile("config.yml").getString("Settings.HeldItem-Slot") != null 
				&& !this.getFile("config.yml").getString("Settings.HeldItem-Slot").equalsIgnoreCase("DISABLED") 
				&& StringUtils.isInt(this.getFile("config.yml").getString("Settings.HeldItem-Slot"))) {
			return this.getFile("config.yml").getInt("Settings.HeldItem-Slot");
		}
		return -1;
	}
	
   /**
    * Gets the Hotbar Triggers that is defined to be set.
    * 
    * @return The String list of hotbar triggers.
    */
	public String getHotbarTriggers() { 
		if (this.getFile("config.yml").getString("Settings.HeldItem-Triggers") != null 
				&& !this.getFile("config.yml").getString("Settings.HeldItem-Triggers").equalsIgnoreCase("DISABLED") 
				&& !this.getFile("config.yml").getString("Settings.HeldItem-Triggers").equalsIgnoreCase("FALSE")) {
			return this.getFile("config.yml").getString("Settings.HeldItem-Triggers");
		}
		return "";
	}
	
   /**
    * Gets the database table prefix.
    * 
    * @return The database table prefix.
    */
    public String getTable() {
    	return (this.getFile("config.yml").getString("Database.prefix") != null ? this.getFile("config.yml").getString("Database.prefix") : "ij_");
    }
	
   /**
    * Checks if the remote MySQL database is enabled.
    * 
    * @return If the remote MySQL database is enabled.
    */
    public boolean sqlEnabled() {
    	return this.getFile("config.yml").getString("Database.MySQL") != null && this.getFile("config.yml").getBoolean("Database.MySQL");
    }
	
   /**
    * Checks if the specified clear items type is enabled.
    * 
    * @param type - The item clearing trigger.
    * @return If the clear type is enabled.
    */
	public boolean clearEnabled(final String type) {
		if (this.getFile("config.yml").getString("Clear-Items." + type) != null 
		&& !this.getFile("config.yml").getString("Clear-Items." + type).equalsIgnoreCase("DISABLED") && !this.getFile("config.yml").getString("Clear-Items." + type).equalsIgnoreCase("FALSE")) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the specified trigger commands is enabled.
    * 
    * @param type - The commands trigger.
    * @return If the trigger type is enabled.
    */
	public boolean triggerEnabled(final String type) {
		if (this.getFile("config.yml").getString("Active-Commands.triggers") != null && StringUtils.containsIgnoreCase(this.getFile("config.yml").getString("Active-Commands.triggers"), type)
			&& (!this.getFile("config.yml").getString("Active-Commands.enabled-worlds").equalsIgnoreCase("DISABLED") && !this.getFile("config.yml").getString("Active-Commands.enabled-worlds").equalsIgnoreCase("FALSE"))) {
			return true;
		}
		return false;
	}

   /**
    * Checks if Debugging is enabled.
    * 
    * @return If Debugging is enabled.
    */
	public boolean debugEnabled() {
		return this.getFile("config.yml").getBoolean("General.Debugging");
	}
	
   /**
    * Gets the defined Prevent.
    * 
    * @param name - The name of the Prevent.
    * @return The defined Prevent as a String to compare later.
    */
	public String getPrevent(final String name) {
		return this.getFile("config.yml").getString("Prevent." + name);
	}
	
   /**
    * Checks if OP Bypass is enabled for Prevent actions.
    * 
    * @return If OP is defined for the Prevent actions.
    */
	public boolean isPreventOP() {
		return StringUtils.containsIgnoreCase(this.getFile("config.yml").getString("Prevent.Bypass"), "OP");
	}
	
   /**
    * Checks if CREATIVE Bypass is enabled for Prevent actions.
    * 
    * @return If CREATIVE is defined for the Prevent actions.
    */
	public boolean isPreventCreative() {
		return StringUtils.containsIgnoreCase(this.getFile("config.yml").getString("Prevent.Bypass"), "CREATIVE");
	}
	
   /**
    * Checks if items are defined correctly in the items.yml.
    * 
    * @return If items exist in the items.yml.
    */
	public boolean itemsExist() {
		if (this.getConfigurationSection() != null) {
			return true;
		} else if (this.getConfigurationSection() == null) {
			ServerUtils.logWarn("{Config} There are no items detected in the items.yml.");
			ServerUtils.logWarn("{Config} Try adding an item to the items section in the items.yml.");
			return false;
		}
		return false;
	}
	
   /**
    * Gets the material defined for the custom item.
    * 
    * @param nodeLocation - The path to the custom items node.
    * @return The material set for the custom item.
    */
	public ConfigurationSection getMaterialSection(final ConfigurationSection nodeLocation) {
		return (this.getFile("items.yml") != null ? this.getFile("items.yml").getConfigurationSection(nodeLocation.getCurrentPath() + ".id") : null);
	}
	
   /**
    * Gets the list of commands defined for the custom item.
    * 
    * @param nodeLocation - The path to the custom items node.
    * @return The list of commands defined for the custom item.
    */
	public ConfigurationSection getCommandsSection(final ConfigurationSection nodeLocation) {
		return (this.getFile("items.yml") != null ? this.getFile("items.yml").getConfigurationSection(nodeLocation.getCurrentPath()) : null);
	}
	
   /**
    * Gets the Options defined for the custom item.
    * 
    * @param nodeName - The node name of the custom item in the items.yml.
    * @return The list of options defined for the custom item.
    */
	public ConfigurationSection getItemSection(final String nodeName) {
		return (this.getConfigurationSection() != null ? this.getConfigurationSection().getConfigurationSection(nodeName) : null);
	}
	
   /**
    * Gets the ConfigurationSection for the list of custom items.
    * 
    * @return The list of custom items.
    */
	public ConfigurationSection getConfigurationSection() {
		return (this.getFile("items.yml") != null ? this.getFile("items.yml").getConfigurationSection("items") : null);
	}
	
   /**
    * Calculates the exact numer of arbitrary slots,
    * assigning numbers to each slot to uniquely identify each item.
    * 
    * @param slot - The numerical or custom slot value.
    * @return The exact slot ID to be set to the item.
    */
	private int ArbitraryID = 0;
	public String getItemID(String slot) {
		if (slot.equalsIgnoreCase("Arbitrary")) {
			this.ArbitraryID += 1;
			slot += this.ArbitraryID;
		}
		return slot;
	}
	
   /**
    * Registers Events that are utilized by the specified ItemMap.
    * 
    * @param itemMap - The ItemMap that needs its events registered.
    */
	public void registerListeners(final ItemMap itemMap) {
		if (((!itemMap.isGiveOnDisabled() && itemMap.isGiveOnJoin()) || itemMap.isAutoRemove() || (this.getFile("config.yml").getString("Active-Commands.enabled-worlds") != null 
			&& (!this.getFile("config.yml").getString("Active-Commands.enabled-worlds").equalsIgnoreCase("DISABLED") || !this.getFile("config.yml").getString("Active-Commands.enabled-worlds").equalsIgnoreCase("FALSE")))) 
			&& !StringUtils.isRegistered(PlayerJoin.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerJoin(), ItemJoin.getInstance());
		}
		if ((((!itemMap.isGiveOnDisabled() && itemMap.isGiveOnRespawn()) || itemMap.isDeathKeepable()) || itemMap.isAutoRemove()) && !StringUtils.isRegistered(Respawn.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Respawn(), ItemJoin.getInstance());
		}
		if (((!itemMap.isGiveOnDisabled() && itemMap.isGiveOnWorldSwitch()) || itemMap.isAutoRemove()) && !StringUtils.isRegistered(WorldSwitch.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new WorldSwitch(), ItemJoin.getInstance());
		}
		if (!itemMap.isGiveOnDisabled() && (itemMap.isGiveOnRegionEnter() || itemMap.isGiveOnRegionLeave() || itemMap.isGiveOnRegionAccess() || itemMap.isGiveOnRegionEgress()) 
			&& !StringUtils.isRegistered(PlayerGuard.class.getSimpleName()) && DependAPI.getDepends(false).getGuard().guardEnabled()) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerGuard(), ItemJoin.getInstance());
		}
		if (!itemMap.isGiveOnDisabled() && itemMap.isUseOnLimitSwitch() && !StringUtils.isRegistered(LimitSwitch.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new LimitSwitch(), ItemJoin.getInstance());
		}
		if ((itemMap.isAnimated() || itemMap.isDynamic()) && !StringUtils.isRegistered(PlayerQuit.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerQuit(), ItemJoin.getInstance());
		}
		if (itemMap.mobsDrop() && !StringUtils.isRegistered(Entities.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Entities(), ItemJoin.getInstance());
		}
		if (itemMap.blocksDrop() && !StringUtils.isRegistered(Breaking.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Breaking(), ItemJoin.getInstance());
		}
		if (itemMap.isCraftingItem() && !StringUtils.isRegistered(Crafting.class.getSimpleName())) {
			PlayerHandler.cycleCrafting();
			SchedulerUtils.runLater(40L, () -> {
				PlayerHandler.restoreCraftItems();
				if (ServerUtils.hasSpecificUpdate("1_8") && !DependAPI.getDepends(false).protocolEnabled() && !ProtocolManager.isHandling()) { ProtocolManager.handleProtocols(); }
				else if (ServerUtils.hasSpecificUpdate("1_8") && DependAPI.getDepends(false).protocolEnabled() && !ProtocolAPI.isHandling()) { ProtocolAPI.handleProtocols(); }
			});
			if (!StringUtils.isRegistered(PlayerQuit.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new PlayerQuit(), ItemJoin.getInstance());
			}
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Crafting(), ItemJoin.getInstance());
		}
		if ((itemMap.isMovement() || itemMap.isEquip() || itemMap.isInventoryClose())) {
			if (!StringUtils.isRegistered(Clicking.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Clicking(), ItemJoin.getInstance());
				if (ServerUtils.hasSpecificUpdate("1_8") && !DependAPI.getDepends(false).protocolEnabled() && !ProtocolManager.isHandling()) { ProtocolManager.handleProtocols(); }
				else if (ServerUtils.hasSpecificUpdate("1_8") && DependAPI.getDepends(false).protocolEnabled() && !ProtocolAPI.isHandling()) { ProtocolAPI.handleProtocols(); }
			}
			if (DependAPI.getDepends(false).chestSortEnabled() && !StringUtils.isRegistered(ChestSortAPI.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new ChestSortAPI(), ItemJoin.getInstance());
			}
		}
		if (ServerUtils.hasSpecificUpdate("1_12") && itemMap.isStackable() && !StringUtils.isRegistered(Stackable.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Stackable(), ItemJoin.getInstance());
		} else if (itemMap.isStackable()) {
			LegacyAPI.registerStackable();
		}
		if ((itemMap.isDeathKeepable() || itemMap.isDeathDroppable() || itemMap.isSelfDroppable()) && !StringUtils.isRegistered(Drops.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Drops(), ItemJoin.getInstance());
		}
		if (itemMap.getCommands() != null && itemMap.getCommands().length != 0) {
			if (ServerUtils.hasSpecificUpdate("1_8") && !StringUtils.isRegistered(Commands.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Commands(), ItemJoin.getInstance());
			} else {
				LegacyAPI.registerCommands();
			}
		}
		if ((itemMap.isCancelEvents() || itemMap.isSelectable() || itemMap.getInteractCooldown() != 0)) {
			if (!StringUtils.isRegistered(Interact.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Interact(), ItemJoin.getInstance());
			}
		}
		if ((itemMap.isPlaceable() || itemMap.isCountLock()) && !StringUtils.isRegistered(Placement.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Placement(), ItemJoin.getInstance());
		}
		if ((itemMap.isCountLock() || itemMap.isTeleport()) && !StringUtils.isRegistered(Projectile.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Projectile(), ItemJoin.getInstance());
		}
		if (itemMap.isCountLock() || itemMap.isCustomConsumable()) {
			if (ServerUtils.hasSpecificUpdate("1_11") && !StringUtils.isRegistered(Consumes.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Consumes(), ItemJoin.getInstance());
			} else {
				LegacyAPI.registerConsumes();
			}
		}
		if (((itemMap.isItemRepairable() || itemMap.isItemCraftable()) || (itemMap.getIngredients() != null || !itemMap.getIngredients().isEmpty())) && !StringUtils.isRegistered(Recipes.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Recipes(), ItemJoin.getInstance());
		}
		if (itemMap.isItemStore() || itemMap.isItemModify()) {
			if (ServerUtils.hasSpecificUpdate("1_8") && !StringUtils.isRegistered(Storable.class.getSimpleName())) {
				ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Storable(), ItemJoin.getInstance());
			} else {
				LegacyAPI.registerStorable();
			}
		}
		if (itemMap.isMovement() && ServerUtils.hasSpecificUpdate("1_9") && ReflectionUtils.getBukkitClass("event.player.PlayerSwapHandItemsEvent") != null && !StringUtils.isRegistered(Offhand.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new Offhand(), ItemJoin.getInstance());
		}
	}
	
   /**
    * Generates the Data for the FileConfiguration that is specific
    * to the current Server version.
    * 
    */
	public void generateItemsFile() {
		File itemsFile = new File(ItemJoin.getInstance().getDataFolder(), "items.yml");
        FileConfiguration itemsData = YamlConfiguration.loadConfiguration(itemsFile);
        
        if (ServerUtils.hasSpecificUpdate("1_14")) {
			itemsData.set("items.devine-item.commands-sound", "BLOCK_NOTE_BLOCK_PLING");
			itemsData.set("items.map-item.id", "FILLED_MAP");
			itemsData.set("items.gamemode-token.id", "FIREWORK_STAR");
			itemsData.set("items.gamemode-token.commands-sound", "BLOCK_NOTE_BLOCK_PLING");
			itemsData.set("items.bungeecord-item.id", "PURPLE_STAINED_GLASS");
			itemsData.set("items.bungeecord-item.commands-sound", "BLOCK_NOTE_BLOCK_PLING");
			itemsData.set("items.animated-panes.id.1", "<delay:40>BLACK_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.2", "<delay:20>BLUE_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.3", "<delay:20>GREEN_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.4", "<delay:20>MAGENTA_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.5", "<delay:20>ORANGE_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.6", "<delay:20>RED_STAINED_GLASS_PANE");
			itemsData.set("items.banner-item.id", "WHITE_BANNER");
			itemsData.set("items.animated-sign.id", "OAK_SIGN");
			itemsData.set("items.skull-item.id", "PLAYER_HEAD");
			itemsData.set("items.potion-arrow.id", "TIPPED_ARROW");
			itemsData.set("items.potion-arrow.name", "&fDeath Arrow");
			itemsData.set("items.potion-arrow.potion-effect", "WITHER:1:20");
			itemsData.set("items.firework-item.id", "FIREWORK_ROCKET");
			itemsData.set("items.firework-item.firework.colors", "GRAY, WHITE, PURPLE, LIGHT_GRAY, GREEN");
			itemsData.set("items.potion-apple.potion-effect", "JUMP:2:120, NIGHT_VISION:2:400, GLOWING:1:410, REGENERATION:1:160");
			itemsData.set("items.profile-item.id", "PLAYER_HEAD");
			itemsData.set("items.random-pane-1.id", "YELLOW_STAINED_GLASS_PANE");
			itemsData.set("items.random-pane-2.id", "BLUE_STAINED_GLASS_PANE");
			itemsData.set("items.random-pane-3.id", "PINK_STAINED_GLASS_PANE");
        } else if (ServerUtils.hasSpecificUpdate("1_13")) {
			itemsData.set("items.devine-item.commands-sound", "BLOCK_NOTE_BLOCK_PLING");
			itemsData.set("items.map-item.id", "FILLED_MAP");
			itemsData.set("items.gamemode-token.id", "FIREWORK_STAR");
			itemsData.set("items.gamemode-token.commands-sound", "BLOCK_NOTE_BLOCK_PLING");
			itemsData.set("items.bungeecord-item.id", "PURPLE_STAINED_GLASS");
			itemsData.set("items.bungeecord-item.commands-sound", "BLOCK_NOTE_BLOCK_PLING");
			itemsData.set("items.animated-panes.id.1", "<delay:40>BLACK_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.2", "<delay:20>BLUE_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.3", "<delay:20>GREEN_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.4", "<delay:20>MAGENTA_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.5", "<delay:20>ORANGE_STAINED_GLASS_PANE");
			itemsData.set("items.animated-panes.id.6", "<delay:20>RED_STAINED_GLASS_PANE");
			itemsData.set("items.banner-item.id", "WHITE_BANNER");
			itemsData.set("items.animated-sign.id", "SIGN");
			itemsData.set("items.skull-item.id", "PLAYER_HEAD");
			itemsData.set("items.potion-arrow.id", "TIPPED_ARROW");
			itemsData.set("items.potion-arrow.name", "&fDeath Arrow");
			itemsData.set("items.potion-arrow.potion-effect", "WITHER:1:20");
			itemsData.set("items.firework-item.id", "FIREWORK_ROCKET");
			itemsData.set("items.firework-item.firework.colors", "GRAY, WHITE, PURPLE, LIGHT_GRAY, GREEN");
			itemsData.set("items.potion-apple.potion-effect", "JUMP:2:120, NIGHT_VISION:2:400, GLOWING:1:410, REGENERATION:1:160");
			itemsData.set("items.profile-item.id", "PLAYER_HEAD");
			itemsData.set("items.random-pane-1.id", "YELLOW_STAINED_GLASS_PANE");
			itemsData.set("items.random-pane-2.id", "BLUE_STAINED_GLASS_PANE");
			itemsData.set("items.random-pane-3.id", "PINK_STAINED_GLASS_PANE");
		} else if (ServerUtils.hasSpecificUpdate("1_9")) {
			itemsData.set("items.devine-item.commands-sound", "BLOCK_NOTE_PLING");
			itemsData.set("items.map-item.id", "MAP");
			itemsData.set("items.gamemode-token.id", "FIREWORK_CHARGE");
			itemsData.set("items.gamemode-token.commands-sound", "BLOCK_NOTE_PLING");
			itemsData.set("items.bungeecord-item.id", "STAINED_GLASS:12");
			itemsData.set("items.bungeecord-item.commands-sound", "BLOCK_NOTE_PLING");
			itemsData.set("items.animated-panes.id.1", "<delay:40>STAINED_GLASS_PANE:15");
			itemsData.set("items.animated-panes.id.2", "<delay:20>STAINED_GLASS_PANE:11");
			itemsData.set("items.animated-panes.id.3", "<delay:20>STAINED_GLASS_PANE:13");
			itemsData.set("items.animated-panes.id.4", "<delay:20>STAINED_GLASS_PANE:2");
			itemsData.set("items.animated-panes.id.5", "<delay:20>STAINED_GLASS_PANE:1");
			itemsData.set("items.animated-panes.id.6", "<delay:20>STAINED_GLASS_PANE:14");
			itemsData.set("items.banner-item.id", "BANNER");
			itemsData.set("items.animated-sign.id", "SIGN");
			itemsData.set("items.skull-item.id", "SKULL_ITEM:3");
			itemsData.set("items.potion-arrow.id", "TIPPED_ARROW");
			itemsData.set("items.potion-arrow.name", "&fDeath Arrow");
			itemsData.set("items.potion-arrow.potion-effect", "WITHER:1:20");
			itemsData.set("items.firework-item.id", "FIREWORK");
			itemsData.set("items.firework-item.firework.colors", "GRAY, WHITE, PURPLE, SILVER, GREEN");
			itemsData.set("items.potion-apple.potion-effect", "JUMP:2:120, NIGHT_VISION:2:400, GLOWING:1:410, REGENERATION:1:160");
			itemsData.set("items.profile-item.id", "SKULL_ITEM:3");
			itemsData.set("items.random-pane-1.id", "STAINED_GLASS_PANE:4");
			itemsData.set("items.random-pane-2.id", "STAINED_GLASS_PANE:4");
			itemsData.set("items.random-pane-3.id", "STAINED_GLASS_PANE:6");
		} else if (ServerUtils.hasSpecificUpdate("1_8")) {
			itemsData.set("items.devine-item.commands-sound", "NOTE_PLING");
			itemsData.set("items.devine-item.attributes", "{GENERIC_ATTACK_DAMAGE:15.2}");
			itemsData.set("items.map-item.id", "MAP");
			itemsData.set("items.gamemode-token.id", "FIREWORK_CHARGE");
			itemsData.set("items.gamemode-token.commands-sound", "NOTE_PLING");
			itemsData.set("items.bungeecord-item.id", "STAINED_GLASS:12");
			itemsData.set("items.bungeecord-item.commands-sound", "NOTE_PLING");
			itemsData.set("items.animated-panes.id.1", "<delay:40>STAINED_GLASS_PANE:15");
			itemsData.set("items.animated-panes.id.2", "<delay:20>STAINED_GLASS_PANE:11");
			itemsData.set("items.animated-panes.id.3", "<delay:20>STAINED_GLASS_PANE:13");
			itemsData.set("items.animated-panes.id.4", "<delay:20>STAINED_GLASS_PANE:2");
			itemsData.set("items.animated-panes.id.5", "<delay:20>STAINED_GLASS_PANE:1");
			itemsData.set("items.animated-panes.id.6", "<delay:20>STAINED_GLASS_PANE:14");
			itemsData.set("items.banner-item.id", "BANNER");
			itemsData.set("items.animated-sign.id", "SIGN");
			itemsData.set("items.skull-item.id", "SKULL_ITEM:3");
			itemsData.set("items.potion-arrow.id", "ARROW");
			itemsData.set("items.potion-arrow.name", "&fArrow");
			itemsData.set("items.potion-arrow.potion-effect", null);
			itemsData.set("items.firework-item.id", "FIREWORK");
			itemsData.set("items.firework-item.firework.colors", "GRAY, WHITE, PURPLE, SILVER, GREEN");
			itemsData.set("items.potion-apple.potion-effect", "JUMP:2:120, NIGHT_VISION:2:400, INVISIBILITY:1:410, REGENERATION:1:160");
			itemsData.set("items.profile-item.id", "SKULL_ITEM:3");
			itemsData.set("items.random-pane-1.id", "STAINED_GLASS_PANE:4");
			itemsData.set("items.random-pane-2.id", "STAINED_GLASS_PANE:3");
			itemsData.set("items.random-pane-3.id", "STAINED_GLASS_PANE:6");
			itemsData.set("items.offhand-item", null);
		} else if (ServerUtils.hasSpecificUpdate("1_7")) {
			itemsData.set("items.devine-item.commands-sound", "NOTE_PLING");
			itemsData.set("items.devine-item.attributes", "{GENERIC_ATTACK_DAMAGE:15.2}");
			itemsData.set("items.map-item.id", "MAP");
			itemsData.set("items.gamemode-token.id", "FIREWORK_CHARGE");
			itemsData.set("items.gamemode-token.commands-sound", "NOTE_PLING");
			itemsData.set("items.bungeecord-item.id", "STAINED_GLASS:12");
			itemsData.set("items.bungeecord-item.commands-sound", "NOTE_PLING");
			itemsData.set("items.animated-panes.id.1", "<delay:40>STAINED_GLASS_PANE:15");
			itemsData.set("items.animated-panes.id.2", "<delay:20>STAINED_GLASS_PANE:11");
			itemsData.set("items.animated-panes.id.3", "<delay:20>STAINED_GLASS_PANE:13");
			itemsData.set("items.animated-panes.id.4", "<delay:20>STAINED_GLASS_PANE:2");
			itemsData.set("items.animated-panes.id.5", "<delay:20>STAINED_GLASS_PANE:1");
			itemsData.set("items.animated-panes.id.6", "<delay:20>STAINED_GLASS_PANE:14");
			itemsData.set("items.banner-item", null);
			itemsData.set("items.melooooon-item.id", 382);
			itemsData.set("items.melooooon-item.slot", 20);
			itemsData.set("items.melooooon-item.name", "&aWater Melooooon!");
			itemsData.set("items.melooooon-item.interact.-", "'message: &aIts a Water Melooooon!'");
			itemsData.set("items.melooooon-item.commands-sequence", "RANDOM");
			itemsData.set("items.melooooon-item.itemflags", "hide-attributes, self-drops, CreativeBypass");
			itemsData.set("items.melooooon-item.triggers", "join, respawn, world-change, region-enter");
			itemsData.set("items.melooooon-item.enabled-worlds", "world, world_nether, world_the_end");
			itemsData.set("items.animated-sign.id", "SIGN");
			itemsData.set("items.skull-item.id", "SKULL_ITEM:3");
			itemsData.set("items.potion-arrow.id", "ARROW");
			itemsData.set("items.potion-arrow.name", "&fArrow");
			itemsData.set("items.potion-arrow.potion-effect", null);
			itemsData.set("items.firework-item.id", "FIREWORK");
			itemsData.set("items.firework-item.firework.colors", "GRAY, WHITE, PURPLE, SILVER, GREEN");
			itemsData.set("items.potion-apple.potion-effect", "JUMP:2:120, NIGHT_VISION:2:400, INVISIBILITY:1:410, REGENERATION:1:160");
			itemsData.set("items.profile-item.id", "SKULL_ITEM:3");
			itemsData.set("items.random-pane-1.id", "STAINED_GLASS_PANE:4");
			itemsData.set("items.random-pane-2.id", "STAINED_GLASS_PANE:3");
			itemsData.set("items.random-pane-3.id", "STAINED_GLASS_PANE:6");
			itemsData.set("items.offhand-item", null);
		}

		try {
			itemsData.save(itemsFile);
			this.getSource("items.yml");
			this.getFile("items.yml").options().copyDefaults(false);
		} catch (Exception e) {
			ItemJoin.getInstance().getServer().getLogger().severe("Could not save important data changes to the data file items.yml!");
			e.printStackTrace();
		}
	}
	
   /**
    * Gets the instance of the ConfigHandler.
    * 
    * @return The ConfigHandler instance.
    */
    public static ConfigHandler getConfig() { 
        if (config == null) {
        	config = new ConfigHandler(); 
        	config.registerClasses(false);
        }
        return config; 
    } 
} public class ItemHandler {
	
   /**
    * Adds a list of lores to the specified ItemStack.
    * 
    * @param item - The ItemStack to be modified.
    * @param lores - The list of lores to be added to the item.
    * @return The ItemStack with its newly added lores.
    */
	public static ItemStack addLore(final ItemStack item, final String... lores) {
		if (item != null && item.getType() != Material.AIR) {
			ItemMeta meta = item.getItemMeta();
			List<String> newLore = new ArrayList<String>();
			if (meta.hasLore()) { newLore = meta.getLore(); }
			for (String lore : lores) { newLore.add(StringUtils.colorFormat(lore)); }
			meta.setLore(newLore);
			item.setItemMeta(meta);
		}
		return item;
	}
	
   /**
    * Gets the exact name of the ItemStack Material with normal case and no underlines.
    * 
    * @param item - The ItemStack to have its Material name fetched.
    * @return A friendly String version of the Material name with normal case and no underlines.
    */
	public static String getMaterialName(final ItemStack item) {
		try {
			return WordUtils.capitalizeFully(item.getType().name().toLowerCase().replace('_', ' '));
		} catch (NullPointerException e) { ServerUtils.sendDebugTrace(e); }
		return null;
	}
	
   /**
    * Gets the String name of the Bukkit Enchantment.
    * 
    * @param enchant - The Enchantment to have its String name found.
    * @return The String name of the Bukkit Enchantment.
    */
	public static String getEnchantName(final Enchantment enchant) {
		if (!ServerUtils.hasSpecificUpdate("1_13")) { return LegacyAPI.getEnchantName(enchant); } 
		else { return enchant.getKey().getKey().toString(); }
	}
	
   /**
    * Gets the exact Bukkit Enchantment provided its String name.
    * 
    * @param name - Name of the Bukkit Enchantment.
    * @return The proper Bukkit Enchantment instance.
    */
	public static Enchantment getEnchantByName(final String name) {
		if (!ServerUtils.hasSpecificUpdate("1_13")) {
			Enchantment enchantName = LegacyAPI.getEnchant(name);
			if (enchantName != null) { return enchantName; }
		} else {
			try {
				Enchantment enchantName = Enchantment.getByKey(org.bukkit.NamespacedKey.minecraft(name.toLowerCase()));
				if (enchantName != null) {
					return enchantName;
				} else { return LegacyAPI.getEnchant(name); }
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		}
		return null;
	}
	
   /**
    * Gets the current Durability Value of the specified ItemStack.
    * 
    * @param item - The ItemStack to have its Durability found.
    * @return The Durability value of the ItemStack.
    */
	public static short getDurability(final ItemStack item) {
		if (!ServerUtils.hasSpecificUpdate("1_13")) {
			return LegacyAPI.getDurability(item);
		} else { return ((short) ((org.bukkit.inventory.meta.Damageable) item.getItemMeta()).getDamage()); }
	}
	
   /**
    * Sets the specified Durability to the specified ItemStack.
    * 
    * @param item - The ItemStack to have its Durability changed.
    * @param durability - The Durability to be set to the ItemStack.
    * @return The ItemStack with its new Durability.
    */
	public static ItemStack setDurability(final ItemStack item, final int durability) {
		if (item.getType().getMaxDurability() != 0 && durability != 0) {
			if (ServerUtils.hasSpecificUpdate("1_13")) {
				ItemMeta tempMeta = item.getItemMeta();
				((org.bukkit.inventory.meta.Damageable) tempMeta).setDamage(durability);
				item.setItemMeta(tempMeta);
				return item;
			} else {
				return LegacyAPI.setDurability(item, (short)durability);
			}
		}
		return item;
	}
	
   /**
    * Modifies the ItemStack.
    * 
    * @param itemCopy - The copy of the ItemStack to be modified.
    * @param allItems - If the item should not have its amount changed.
    * @param amount - The intended stack size.
    * @return The newly Modified ItemStack.
    */
	public static ItemStack modifyItem(final ItemStack itemCopy, final boolean allItems, final int amount) {
		ItemStack item = new ItemStack(itemCopy);
		if (((item.getAmount() > amount && item.getAmount() != amount) || item.getAmount() < amount) && !allItems) { item.setAmount(item.getAmount() - amount); } 
		else { item = new ItemStack(Material.AIR); }
		return item;
	}
	
   /**
    * Creates a new ItemStack with the specified material, count, 
    * adding a invisible glowing enchant, custom name, and lore.
    * 
    * @param material - The material name and data value of the ItemStack, Example: "WOOL:14".
    * @param count - The stack size of the ItemStack.
    * @param glowing - If the ItemStack should visually glow.
    * @param name - The custom name to be added to the ItemStack.
    * @param lores - The custom lore to be added to the ItemStack.
    */
    public static ItemStack getItem(String material, final int count, final boolean glowing, String name, final String... lores) {
        ItemStack tempItem; if (!ServerUtils.hasSpecificUpdate("1_8") && material.equals("BARRIER")) { material = "WOOL:14"; }
        if (material.equalsIgnoreCase("AIR") || material.equalsIgnoreCase("AIR:0")) { material = "GLASS_PANE"; }
        if (getMaterial(material, null) == null) { material = "STONE"; } 
        if (ServerUtils.hasSpecificUpdate("1_13")) { tempItem = new ItemStack(getMaterial(material, null), count); } 
        else { short dataValue = 0; if (material.contains(":")) { String[] parts = material.split(":"); material = parts[0]; dataValue = (short) Integer.parseInt(parts[1]); } 
        tempItem = LegacyAPI.newItemStack(getMaterial(material, null), count, dataValue); }
        if (glowing) { tempItem.addUnsafeEnchantment(Enchantment.DAMAGE_ALL, 1); }
        ItemMeta tempMeta = tempItem.getItemMeta();
        if (ServerUtils.hasSpecificUpdate("1_8")) { tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_ENCHANTS); }
        if (name != null) { name = StringUtils.colorFormat(name); tempMeta.setDisplayName(name); }
        if (lores != null && lores.length != 0) {
        	ArrayList<String> loreList = new ArrayList<String>();
        	for (String loreString: lores) { 
        		if (!loreString.isEmpty()) {
        			if (loreString.contains("/n")) {
        				String[] loreSplit = loreString.split(" /n ");
        				for (String loreStringSplit : loreSplit) { loreList.add(StringUtils.colorFormat(loreStringSplit)); }
        			} else { loreList.add(StringUtils.colorFormat(loreString)); }
        		} 
        	}
        	tempMeta.setLore(loreList);
        }
        tempItem.setItemMeta(tempMeta); 
        return tempItem;
    }
    
   /**
    * Checks the Players Inventory for an item in the ItemMap's Specified slot,
    * and returns the item if it exists.
    * 
    * @param player - The Player having their Inventory checked.
    * @param itemMap - The ItemMap that is having its slot checked.
    * @return The existing ItemStack from the Players Inventory.
    */
	public static ItemStack getItem(final Player player, final ItemMap itemMap) {
		int craftSlot = StringUtils.getSlotConversion(itemMap.getSlot());
		ItemStack existingItem = null;
		if (StringUtils.isInt(itemMap.getSlot())) {
			existingItem = player.getInventory().getItem(Integer.parseInt(itemMap.getSlot()));
		} else if (itemMap.getSlot().contains("%")) {
			String slot = StringUtils.translateLayout(itemMap.getSlot(), player);
			if (StringUtils.isInt(slot)) {
				existingItem = player.getInventory().getItem(Integer.parseInt(slot));
			}
		} else if (CustomSlot.HELMET.isSlot(itemMap.getSlot())) {
			existingItem = player.getEquipment().getHelmet();
		} else if (CustomSlot.CHESTPLATE.isSlot(itemMap.getSlot())) {
			existingItem = player.getEquipment().getChestplate();
		} else if (CustomSlot.LEGGINGS.isSlot(itemMap.getSlot())) {
			existingItem = player.getEquipment().getLeggings();
		} else if (CustomSlot.BOOTS.isSlot(itemMap.getSlot())) {
			existingItem = player.getEquipment().getBoots();
		} else if (ServerUtils.hasSpecificUpdate("1_9") && CustomSlot.OFFHAND.isSlot(itemMap.getSlot())) {
			existingItem = player.getEquipment().getItemInOffHand();
		} else if (craftSlot != -1) {
			existingItem = player.getOpenInventory().getTopInventory().getItem(craftSlot);
		}
		return (existingItem != null && existingItem.getType() != Material.AIR ? existingItem : null);
	}
    
   /**
    * Gets the Bukkit Material instance of the specified String material name and data value.
    * 
    * @param material - The item ID or Bukkit Material String name.
    * @param data - The data value of the item, usually this is zero.
    * @return The proper Bukkit Material instance.
    */
	public static Material getMaterial(String material, String data) {
		try {
			boolean isLegacy = (data != null);
			if (material.contains(":")) { String[] parts = material.split(":"); material = parts[0]; if (!parts[1].equalsIgnoreCase("0")) { data = parts[1]; isLegacy = true; } }
			if (StringUtils.isInt(material) && !ServerUtils.hasSpecificUpdate("1_13")) {
				return LegacyAPI.findMaterial(Integer.parseInt(material));
			} else if (StringUtils.isInt(material) && ServerUtils.hasSpecificUpdate("1_13") || isLegacy && ServerUtils.hasSpecificUpdate("1_13")) {
				int dataValue;
				if (!StringUtils.isInt(material)) { material = "LEGACY_" + material; }
				if (data != null) { dataValue = Integer.parseInt(data); } else { dataValue = 0; }
				if (!StringUtils.isInt(material)) { return LegacyAPI.getMaterial(Material.getMaterial(material.toUpperCase()), (byte) dataValue); } 
				else { return LegacyAPI.getMaterial(Integer.parseInt(material), (byte) dataValue); }
			} else if (!ServerUtils.hasSpecificUpdate("1_13")) {
				return Material.getMaterial(material.toUpperCase());
			} else {
				return Material.matchMaterial(material.toUpperCase());
			}
		} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return null;
	}
	
   /**
    * Gets the material as defined in the ConfigurationSection.
    * 
    * @param itemNode - The node ConfigurationSection (location) of the config section.
    * @return The material exactly as found in the Configuration Section, without any animation delay.
    */
	public static String getMaterial(final ConfigurationSection itemNode) {
		String material = cutDelay(itemNode.getString(".id"));
		if (ConfigHandler.getConfig().getMaterialSection(itemNode) != null) {
			List<String> materials = new ArrayList<String>();
			for (String materialKey : ConfigHandler.getConfig().getMaterialSection(itemNode).getKeys(false)) {
				String materialList = itemNode.getString(".id." + materialKey);
				if (materialList != null) {
					materials.add(materialList);
				}
			}
			material = cutDelay(itemNode.getString(".id." + ConfigHandler.getConfig().getMaterialSection(itemNode).getKeys(false).iterator().next()));
			return material;
		}
		return material;
	}
	
   /**
    * Checks if the ItemStack List contains the Material.
    * 
    * @param itemstacks - The ItemStacks being checked.
    * @param material - The Material expected.
    * @return If the List contains the Material
    */
	public static boolean containsMaterial(final Collection<ItemStack> itemstacks, final Material material) {
		for (ItemStack item: itemstacks) {
			if (item.getType().equals(material)) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Sets the Skull Texture to the ItemStack.
    * 
    * @param item - The ItemStack to have its Skull Texture changed.
    * @param skullTexture - The Skull Texture to be added to the ItemStack.
    */
    public static ItemStack setSkullTexture(final ItemStack item, final String skullTexture) {
    	try {
    		if (ServerUtils.hasSpecificUpdate("1_8")) {
		        ItemMeta itemMeta = item.getItemMeta();
				GameProfile gameProfile = new GameProfile(UUID.randomUUID(), null);
				gameProfile.getProperties().put("textures", new Property("textures", new String(skullTexture)));
				Field declaredField = itemMeta.getClass().getDeclaredField("profile");
				declaredField.setAccessible(true);
				declaredField.set(itemMeta, gameProfile);
				item.setItemMeta(itemMeta);
    		}
    	} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
    	return item;
    }
    
   /**
    * Sets the Skull Texture to the ItemStack.
    * 
    * @param item - The ItemStack to have its Skull Texture changed.
    * @param skullTexture - The Skull Texture to be added to the ItemStack.
    */
    public static ItemMeta setSkullTexture(final ItemMeta itemMeta, final String skullTexture) {
    	try {
    		if (ServerUtils.hasSpecificUpdate("1_8")) {
				GameProfile gameProfile = new GameProfile(UUID.randomUUID(), null);
				gameProfile.getProperties().put("textures", new Property("textures", new String(skullTexture)));
				Field declaredField = itemMeta.getClass().getDeclaredField("profile");
				declaredField.setAccessible(true);
				declaredField.set(itemMeta, gameProfile);
    		}
    	} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
    	return itemMeta;
    }
	
   /**
    * Gets the current Skull Texture of the ItemMeta.
    * 
    * @param meta - The ItemMeta to have its Skull Texture found.
    * @return The found Skull Texture String value.
    */
	public static String getSkullTexture(final ItemMeta meta) {
		try {
			final Class < ? > cls = ReflectionUtils.getCraftBukkitClass("inventory.CraftMetaSkull");
			final Object real = cls.cast(meta);
			final Field field = real.getClass().getDeclaredField("profile");
			field.setAccessible(true);
			final GameProfile profile = (GameProfile) field.get(real);
			final Collection < Property > props = profile.getProperties().get("textures");
			for (final Property property: props) {
				if (property.getName().equals("textures")) { return property.getValue(); }
			}
		} catch (Exception e) { }
		return "";
	}
	
   /**
    * Gets the current Skull Texture of the ItemMeta.
    * 
    * @param skull - The Skull to have its Skull Texture found.
    * @return The found Skull Texture String value.
    */
	public static String getSkullTexture(final Skull skull) {
		try {
			final Field field = skull.getClass().getDeclaredField("profile");
			field.setAccessible(true);
			final GameProfile profile = (GameProfile) field.get(skull);
			final Collection < Property > props = profile.getProperties().get("textures");
			for (final Property property: props) {
				if (property.getName().equals("textures")) { return property.getValue(); }
			}
		} catch (Exception e) { }
		return "";
	}
	
   /**
    * Sets the Skull Owner name to the ItemMeta.
    * 
    * @param meta - The ItemMeta to have its Skull Owner changed.
    * @param owner - The String name of the Skull Owner to be set.
    * @return The ItemMeta with the new Skull Owner.
    */
	public static ItemMeta setSkullOwner(final ItemMeta meta, final String owner) {
		if (!ServerUtils.hasSpecificUpdate("1_8")) {
			ServerUtils.logDebug("{ItemMap} Minecraft does not support offline player heads below Version 1.8.");
			ServerUtils.logDebug("{ItemMap} Player heads will only be given a skin if the player has previously joined the sever.");
		}
		setStoredSkull(meta, owner);
		return meta;
	}
	
   /**
    * Sets the locale stored skull owner.
    * 
    * @param meta - The referenced ItemMeta.
    * @param owner - The referenced Skull Owner
    */
	public static void setStoredSkull(final ItemMeta meta, final String owner) {
		if (!owner.isEmpty()) {
			SkullMeta skullMeta = (SkullMeta)meta;
			OfflinePlayer player = LegacyAPI.getOfflinePlayer(owner);
			if (DependAPI.getDepends(false).skinsRestorerEnabled()) {
				final String textureValue = DependAPI.getDepends(false).getSkinValue(owner);
				if (textureValue != null) {
					setSkullTexture(meta, textureValue);
				} else if (player != null) {
					try {
						skullMeta.setOwningPlayer(player);
					} catch (Throwable t) {
						LegacyAPI.setSkullOwner(skullMeta, player.getName());
					}
				} else {
					LegacyAPI.setSkullOwner(skullMeta, owner);
				}
			} else if (player != null) {
				try {
					skullMeta.setOwningPlayer(player);
				} catch (Throwable t) {
					LegacyAPI.setSkullOwner(skullMeta, player.getName());
				}
			} else {
				LegacyAPI.setSkullOwner(skullMeta, owner);
			}
		}
	}
	
   /**
	* Stacks two items together.
	* 
	* @param player - The player being referenced.
	* @param item1 - The main item being removed.
	* @param item2 - The secondary item being stacked.
	* @param slot - The new event slot of the main item.
	* @return The Remaining amount to be set (if any).
	*/
	public static int stackItems(final Player player, final ItemStack item1, final ItemStack item2, final int slot) {
		int MINECRAFT_STACK_MAX = 64;
		int DESIRED_STACK_SIZE = item1.getAmount() + item2.getAmount();
		int REMAINING_STACK_SIZE = 0;
		if (DESIRED_STACK_SIZE > MINECRAFT_STACK_MAX) {
			item2.setAmount(MINECRAFT_STACK_MAX);
			item1.setAmount(DESIRED_STACK_SIZE - MINECRAFT_STACK_MAX);
			REMAINING_STACK_SIZE = item1.getAmount();
		} else {
			item2.setAmount(item2.getAmount() + item1.getAmount());
			if (slot == -1) {
				player.getOpenInventory().setCursor(new ItemStack(Material.AIR));
			} else if (slot != -2) {
				player.getInventory().setItem(slot, new ItemStack(Material.AIR));
			}
		}
		return REMAINING_STACK_SIZE;
	}
	
   /**
    * Gets the existing MapView for the image id.
    * 
    * @param id - that will recieve the items.
    * @retrn The existing MapView.
    */
	public static MapView existingView(final int id) {
		MapView view = LegacyAPI.getMapView(id);
		if (view == null) { view = LegacyAPI.createMapView(); }
		return view;
	}
	
   /**
    * Saves any existing players that are on cooldown for each item.
    * 
    */
	public static void saveCooldowns() {
		for (ItemMap itemMap: ItemUtilities.getUtilities().getItems()) {
			for (String key: itemMap.getPlayersOnCooldown().keySet()) {
				if (System.currentTimeMillis() - itemMap.getPlayersOnCooldown().get(key) <= itemMap.getCommandCooldown() * 1000) {
					SQL.getData().saveData(new DataObject(Table.ON_COOLDOWN, key, "GLOBAL", itemMap.getConfigName(), itemMap.getCommandCooldown().toString(), itemMap.getPlayersOnCooldown().get(key).toString()));
				}
			}
		}
	}
	
   /**
    * Removes the Crafting Items from ALL Online Players.
    * 
    * @param saveCrafting - If the Crafting Items should be saved to be returned later.
    */
	public static void purgeCraftItems(final boolean saveCrafting) {
		PlayerHandler.forOnlinePlayers(player -> {
			if (saveCrafting) { saveCraftItems(player); }
			removeCraftItems(player); 
		});
	}
    
   /**
    * Saves the players current crafting items for later retrieval.
    * 
    * @param player - The Player to have its crafting items saved.
    */
    public static void saveCraftItems(final Player player) {
			if (PlayerHandler.getCreativeCraftItems().containsKey(PlayerHandler.getPlayerID(player))) {
				Inventory inv = Bukkit.createInventory(null, 9);
				boolean notNull = false;
				ItemStack[] craftingContents = PlayerHandler.getCreativeCraftItems().get(PlayerHandler.getPlayerID(player));
				for (int k = 0; k <= 4; k++) {
					if (craftingContents != null && craftingContents[k] != null) {
						inv.setItem(k, craftingContents[k]); 
						if (craftingContents[k] != null && craftingContents[k].getType() != Material.AIR) { notNull = true; }
					}
				}
				if (notNull) { SQL.getData().saveData(new DataObject(Table.RETURN_CRAFTITEMS, PlayerHandler.getPlayerID(player), "", serializeInventory(inv))); }
			} else if (PlayerHandler.getOpenCraftItems().containsKey(PlayerHandler.getPlayerID(player))) {
				Inventory inv = Bukkit.createInventory(null, 9);
				boolean notNull = false;
				ItemStack[] craftingContents = PlayerHandler.getOpenCraftItems().get(PlayerHandler.getPlayerID(player));
				for (int k = 0; k <= 4; k++) {
					if (craftingContents != null && craftingContents[k] != null) {
						inv.setItem(k, craftingContents[k]); 
						if (craftingContents[k] != null && craftingContents[k].getType() != Material.AIR) { notNull = true; }
					}
				}
				if (notNull) { SQL.getData().saveData(new DataObject(Table.RETURN_CRAFTITEMS, PlayerHandler.getPlayerID(player), "", serializeInventory(inv))); }
			} else if (PlayerHandler.getCraftItems().containsKey(PlayerHandler.getPlayerID(player))) {
				Inventory inv = Bukkit.createInventory(null, 9);
				boolean notNull = false;
				ItemStack[] craftingContents = PlayerHandler.getCraftItems().get(PlayerHandler.getPlayerID(player));
				for (int k = 0; k <= 4; k++) {
					if (craftingContents != null && craftingContents[k] != null) {
						inv.setItem(k, craftingContents[k]); 
						if (craftingContents[k] != null && craftingContents[k].getType() != Material.AIR) { notNull = true; }
					}
				}
				if (notNull) { SQL.getData().saveData(new DataObject(Table.RETURN_CRAFTITEMS, PlayerHandler.getPlayerID(player), "", serializeInventory(inv))); }
			}
    }
    
   /**
    * Restores the players crafting items to their inventory if they were previously saved.
    * 
    * @param player - The Player to have its crafting items restored.
    */
    public static void restoreCraftItems(final Player player, final TriggerType type) {
    	if (!type.equals(TriggerType.QUIT)) {
	    	DataObject dataObject = SQL.getData().getData(new DataObject(Table.RETURN_CRAFTITEMS, PlayerHandler.getPlayerID(player), "", ""));
	    	Inventory inventory = (dataObject != null ? deserializeInventory(dataObject.getInventory64()) : null);
			Inventory craftView = player.getOpenInventory().getTopInventory();
			if (inventory != null && PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				for (int k = 4; k >= 0; k--) {
					if (inventory.getItem(k) != null && inventory.getItem(k).getType() != Material.AIR) {
					 craftView.setItem(k, inventory.getItem(k).clone());
					}
				}
				PlayerHandler.updateInventory(player, 1L);
				SQL.getData().removeData(dataObject);
			} else if (!PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				SchedulerUtils.runLater(60L, () -> restoreCraftItems(player, type));
			}
    	}
    }
    
   /**
    * Removes all crafting items from the players inventory.
    * 
    * @param player - The Player to have their crafting items removed.
    */
    public static void removeCraftItems(final Player player) {
    	ItemStack[] craftingContents = player.getOpenInventory().getTopInventory().getContents();
	    Inventory craftView = player.getOpenInventory().getTopInventory();
	    if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
	    	for (int k = 0; k < craftingContents.length; k++) {
	    		craftView.setItem(k, new ItemStack(Material.AIR));
	    	}
	    }
    }
    
   /**
    * Returns the custom crafting item to the player after the specified delay.
    * 
    * @param player - the Player having their item returned.
    * @param slot - the slot to return the crafting item to.
    * @param item - the item to be returned.
    * @param delay - the delay to wait before returning the item.
    */
    public static void returnCraftingItem(final Player player, final int slot, final ItemStack item, long delay) {
    	if (item == null) { return; } if (slot == 0) { delay += 1L; }
    	SchedulerUtils.runLater(delay, () -> {
	    	if (!player.isOnline()) { return; }
	    	if (PlayerHandler.isCraftingInv(player.getOpenInventory()) && player.getGameMode() != GameMode.CREATIVE) {
	    	    player.getOpenInventory().getTopInventory().setItem(slot, item);	
	    	    PlayerHandler.updateInventory(player, 1L);
	    	} else {
	    		returnCraftingItem(player, slot, item, 10L);
	    	}
	    });
    }
    
   /**
    * Copies the specified ItemStack contents.
    * 
    * @param contents - The ItemStack contents to be copied.
    * @return The copied ItemStack contents.
    */
    public static ItemStack[] cloneContents(final ItemStack[] contents) {
    	int itr = 0;
    	ItemStack[] copyContents = contents;
    	for (ItemStack itemStack: contents) {
    		if (copyContents[itr] != null) {
    			copyContents[itr] = itemStack.clone();
    		}
    		itr++;
    	}
    	return copyContents;
    }
    
   /**
    * Checks if the ItemStack contents are NULL or empty.
    * 
    * @param contents - The ItemStack contents to be checked.
    * @return If the contents do not exist.
    */
    public static boolean isContentsEmpty(final ItemStack[] contents) {
    	int size = 0; 
    	for (ItemStack itemStack: contents) { 
    		if (itemStack == null || itemStack.getType().equals(Material.AIR)) { 
    			size++; 
    		} 
    	}
    	return (size == contents.length);
    }
    
   /**
    * Converts the Inventory to a Base64 String.
    * This is a way of encrypting a Inventory to be decrypted and referenced later.
    * 
    * @param inventory - The Inventory to be converted.
    * @return The Base64 String of the Inventory.
    */
	public static String serializeInventory(final Inventory inventory) {
	    try {
	    	java.io.ByteArrayOutputStream str = new java.io.ByteArrayOutputStream();
	        org.bukkit.util.io.BukkitObjectOutputStream data = new org.bukkit.util.io.BukkitObjectOutputStream(str);
	        data.writeInt(inventory.getSize());
	        for (int i = 0; i < inventory.getSize(); i++) {
	            data.writeObject(inventory.getItem(i));
	        }
	        data.close();
	        return Base64.getEncoder().encodeToString(str.toByteArray());
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    return "";
	}

   /**
    * Converts the Base64 String to a Inventory.
    * This is a way of decrypting an encrypted Inventory to be referenced.
    * 
    * @param inventoryData - The Base64 String to be converted to an Inventory.
    * @return The Inventory instance that has been deserialized.
    */
	public static Inventory deserializeInventory(final String inventoryData) {
	    try {
	    	java.io.ByteArrayInputStream stream = new java.io.ByteArrayInputStream(Base64.getDecoder().decode(inventoryData));
	        org.bukkit.util.io.BukkitObjectInputStream data = new org.bukkit.util.io.BukkitObjectInputStream(stream);
	        Inventory inventory = Bukkit.createInventory(null, data.readInt());
	        for (int i = 0; i < inventory.getSize(); i++) {
	            inventory.setItem(i, (ItemStack) data.readObject());
	        }
	        data.close();
	        return inventory;
	    } catch (EOFException e) {
	    	return null;
	    } catch (Exception e) {
	        ServerUtils.sendDebugTrace(e);
	    }
	    return null;
	}
	
   /**
    * Gets the custom NBTData of the ItemStack.
    * 
    * @param item - The ItemStack to have its custom NBTData found.
    * @return The String of NBTData found on the ItemStack.
    */
	public static String getNBTData(final ItemStack item) {
		if (dataTagsEnabled() && item != null && item.getType() != Material.AIR) {
			try {
				Object nms = ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack").getMethod("asNMSCopy", ItemStack.class).invoke(null, item);
				Class<?> itemClass = ReflectionUtils.getMinecraftClass("ItemStack");
				Object cacheTag = itemClass.getMethod(MinecraftMethod.getTag.getMethod(itemClass)).invoke(nms);
				if (cacheTag != null) {
					String data = (String) cacheTag.getClass().getMethod(MinecraftMethod.getString.getMethod(cacheTag, String.class), String.class).invoke(cacheTag, "ItemJoin");
					String data1 = (String) cacheTag.getClass().getMethod(MinecraftMethod.getString.getMethod(cacheTag, String.class), String.class).invoke(cacheTag, "ItemJoin Name");
					String data2 = (String) cacheTag.getClass().getMethod(MinecraftMethod.getString.getMethod(cacheTag, String.class), String.class).invoke(cacheTag, "ItemJoin Slot");
					if (data1 != null && data2 != null && !data1.isEmpty() && !data2.isEmpty()) {
						return data1 + " " + data2;
					} else if (data != null && !data.isEmpty()) { 
						return data.replace("Slot: ", "");
					}
				}
			} catch (Exception e) {
				ServerUtils.logSevere("{ItemMap} An error has occured when getting NBTData to an item.");
				ServerUtils.sendDebugTrace(e);
			}
		}
		return null;
	}
	
   /**
    * Checks if the ItemStack contains plugin specific NBTData.
    * 
    * @param item - The ItemStack to be checked for custom NBTData.
    * @return If the ItemStack has plugin specific NBTData.
    */
	public static boolean containsNBTData(final ItemStack item) {
		if (dataTagsEnabled() && item != null && item.getType() != Material.AIR && getNBTData(item) != null) {
			return true;
		} else if (!dataTagsEnabled()) { 
			if (item != null && item.hasItemMeta() && item.getItemMeta().hasDisplayName()
				&& StringUtils.colorDecode(item) != null && !StringUtils.colorDecode(item).isEmpty()) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Attempts to fetch the designated slot of an item.
    * 
    * @param material - The ItemStack to be checked for a designated slot.
    * @return The proper designated slot name.
    */
	public static String getDesignatedSlot(final Material material) {
		String name = material.name().contains("_") ? material.name().split("_")[1] : material.name();
		String hand = (ServerUtils.hasSpecificUpdate("1_13") ? "hand" : "mainhand");
		return (name != null ? (name.equalsIgnoreCase("HELMET") ? "head" : name.equalsIgnoreCase("CHESTPLATE") ? "chest" : name.equalsIgnoreCase("LEGGINGS") ? "legs" : name.equalsIgnoreCase("BOOTS") ? "feet" : 
			    name.equalsIgnoreCase("HOE") ? hand : name.equalsIgnoreCase("SWORD") ? hand : name.equalsIgnoreCase("SHOVEL") ? hand : name.equalsIgnoreCase("AXE") ? hand : name.equalsIgnoreCase("PICKAXE") ? hand : "noslot") : "noslot");
	}
	
   /**
    * Checks if NBTData is enabled for the current server version.
    * 
    * @return If NBTData is enabled.
    */
	public static boolean dataTagsEnabled() {
		if (ServerUtils.hasSpecificUpdate("1_8")) {
			return ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.DataTags");
		}
		return false;
	}
	
   /**
    * Checks if the server is using the new skull method.
    * 
    * @return If the server is using the new skull method.
    */
	public static boolean usesOwningPlayer() {
		try {
			if (Class.forName("org.bukkit.inventory.meta.SkullMeta").getMethod("getOwningPlayer") != null) { return true; }
		} catch (Exception e) { }
		return false;
	}
	
   /**
    * Gets the Integer Delay of the specified String.
    * 
    * @param context - The String to have the Delay found.
    * @return The Delay of the String as an Integer.
    */
	public static int getDelay(final String context) {
		try { if (StringUtils.returnInteger(context) != null) { return StringUtils.returnInteger(context); } } 
		catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return 0;
	}
	
   /**
    * Gets the delay format including the proper delay Integer of the String.
    * 
    * @param context - The String to have the Delay found.
    * @return The Delay Format of the String with the proper Integer value.
    */
	public static String getDelayFormat(final String context) {
		if (StringUtils.containsIgnoreCase(context, "<delay:" + StringUtils.returnInteger(context) + ">") 
				|| StringUtils.containsIgnoreCase(context, "delay:" + StringUtils.returnInteger(context) + "") 
				|| StringUtils.containsIgnoreCase(context, "<delay: " + StringUtils.returnInteger(context) + ">")
				|| StringUtils.containsIgnoreCase(context, "delay: " + StringUtils.returnInteger(context) + "")) {
			return ("<delay:" + StringUtils.returnInteger(context) + ">");
		}
		return null;
	}
	
   /**
    * Removes the delay formatting from the specified String.
    * 
    * @param context - The String to have the Delay Formatting removed.
    * @return The String with the removed Delay Formatting.
    */
	public static String cutDelay(final String context) {
		if (getDelayFormat(context) != null) {
			return context.replace(getDelayFormat(context), "");
		} 
		return context;
	}
	
   /**
    * Removes the delay formatting from the specified String List.
    * 
    * @param context - The String List to have the Delay Formatting removed.
    * @return The String List with the removed Delay Formatting.
    */
	public static List<String> cutDelay(final List <String> context) {
		List<String> newContext = new ArrayList<String>();
		for (String minorContext : context) {
			newContext.add(cutDelay(minorContext));
		}
		return newContext;
	}
	
   /**
	* Checks if the book pages contains a JSONEvent.
	* 
	* @param formatPage - The page to be formatted..
	* @return If the book page contains a JSONEvent.
	*/
	public static boolean containsJSONEvent(final String formatPage) {
		if (formatPage.contains(JSONEvent.TEXT.matchType) || formatPage.contains(JSONEvent.SHOW_TEXT.matchType) || formatPage.contains(JSONEvent.OPEN_URL.matchType) || formatPage.contains(JSONEvent.RUN_COMMAND.matchType)) {
			return true;
		}
		return false;
	}
	
   /**
	* Checks to see if the open_url is correctly defined with https or http.
	* 
	* @param itemMap - The ItemMap being modified.
	* @param type - The JSONEvent type.
	* @param inputResult - The input for the JSONEvent.
	*/
	public static void safteyCheckURL(final ItemMap itemMap, final JSONEvent type, final String inputResult) {
		if (type.equals(JSONEvent.OPEN_URL)) {
			if (!StringUtils.containsIgnoreCase(inputResult, "https") && !StringUtils.containsIgnoreCase(inputResult, "http")) {
				ServerUtils.logSevere("{ItemMap} The URL Specified for the clickable link in the book " + itemMap.getConfigName() + " is missing http or https and will not be clickable.");
				ServerUtils.logWarn("{ItemMap} A URL designed for a clickable link should resemble this link structure: https://www.google.com/");
			}
		}
	}
	
	
   /**
	* Defines the JSONEvents for their action, event, and matchType.
	* 
	*/
	public enum JSONEvent {
		TEXT("nullEvent", "text", "<text:"),
		SHOW_TEXT("hoverEvent", "show_text", "<show_text:"),
		OPEN_URL("clickEvent", "open_url", "<open_url:"),
		RUN_COMMAND("clickEvent", "run_command", "<run_command:"),
		CHANGE_PAGE("clickEvent", "change_page", "<change_page:");
		public final String event;
		public final String action;
		public final String matchType;
		private JSONEvent(String Event, String Action, String MatchType) {
			this.event = Event;
			this.action = Action;
			this.matchType = MatchType;
		}
	}
	
   /**
    * Checks if the specified String slot is a Custom Slot.
    * 
    * @param slot - The slot to be checked.
    * @return If the slot is a custom slot.
    */
	public static boolean isCustomSlot(final String slot) {
		if (slot.equalsIgnoreCase("Offhand") || slot.equalsIgnoreCase("Arbitrary") || slot.equalsIgnoreCase("Helmet") 
				|| slot.equalsIgnoreCase("Chestplate") || slot.equalsIgnoreCase("Leggings") || slot.equalsIgnoreCase("Boots") || isCraftingSlot(slot) || slot.contains("%")) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the specified String slot is a Crafting Slot.
    * 
    * @param slot - The slot to be checked.
    * @return If the slot is a crafting slot.
    */
	public static boolean isCraftingSlot(final String slot) {
		if (slot.equalsIgnoreCase("CRAFTING[0]") || slot.equalsIgnoreCase("CRAFTING[1]") 
				|| slot.equalsIgnoreCase("CRAFTING[2]") || slot.equalsIgnoreCase("CRAFTING[3]") || slot.equalsIgnoreCase("CRAFTING[4]")) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the Material is a Legacy Skull Item or Player Skull.
    * 
    * @param material - The Material to be checked.
    * @return If the Material is a Skull/Player Head.
    */
	public static boolean isSkull(final Material material) {
		if (material.toString().equalsIgnoreCase("SKULL_ITEM") || material.toString().equalsIgnoreCase("PLAYER_HEAD")) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the ItemStack is a Writable Book.
    * 
    * @param item - The ItemStack to be checked.
    * @return If the ItemStack is a Writable Book.
    */
	public static boolean isBookQuill(ItemStack item) {
		if (item != null && item.getType() != null && (item.getType().toString().equalsIgnoreCase("WRITABLE_BOOK") || item.getType().toString().equalsIgnoreCase("BOOK_AND_QUILL"))) {
			return true; 
		} 
		return false;
	}
} public class PermissionsHandler {

   /**
    * Checks if the permission is a custom permission.
    * This fetches the proper permission node, so if a custom permission is not
    * defined for the item, it returns the default permission node itemjoin.world.itemname.
    * 
    * @param permissionNode - The custom permission node for the item.
    * @param item - The node of the current item.
    * @param worldName - The name of the current world.
    * @return The permission node of the item.
    */
	public static String customPermissions(final String permissionNode, final String item, final String worldName) {
		if (permissionNode != null) {
			return permissionNode;
		}
		return "itemjoin." + worldName + "." + item;
	}
	
   /**
    * Checks if the sender has permission.
    * 
    * @param sender - The entity that is having their permissions checked.
    * @param permission - The permission the sender is expected to have.
    * @return If the entity has the proper permission.
    */
	public static boolean hasPermission(final CommandSender sender, final String permission) {
		if (sender.hasPermission(permission) || sender.hasPermission("itemjoin.*") || sender.hasPermission("itemjoin.all") || isDeveloper(sender) || (sender instanceof ConsoleCommandSender)) {
			return true;
		} else if (!ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-OP") && sender.isOp()) {
			if (permission.equalsIgnoreCase("itemjoin.use") || permission.equalsIgnoreCase("itemjoin.reload") || permission.equalsIgnoreCase("itemjoin.updates")
					|| permission.equalsIgnoreCase("itemjoin.upgrade") || permission.equalsIgnoreCase("itemjoin.menu") 
					|| permission.equalsIgnoreCase("itemjoin.purge") || permission.equalsIgnoreCase("itemjoin.get") || permission.equalsIgnoreCase("itemjoin.get.others")
							|| permission.equalsIgnoreCase("itemjoin.remove") || permission.equalsIgnoreCase("itemjoin.remove.others") || permission.equalsIgnoreCase("itemjoin.disable") 
							|| permission.equalsIgnoreCase("itemjoin.disable.others") || permission.equalsIgnoreCase("itemjoin.enable") || permission.equalsIgnoreCase("itemjoin.enable.others")
							|| permission.equalsIgnoreCase("itemjoin.list") || permission.equalsIgnoreCase("itemjoin.query")) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * If Debugging Mode is enabled, the plugin developer will be allowed to execute ONLY this plugins commands for help and support purposes.
    * 
    * @param sender - The entity executing the plugin command.
    * @return If the command sender is the developer of the plugin.
    */
	private static boolean isDeveloper(final CommandSender sender) {
		if (ConfigHandler.getConfig().debugEnabled()) {
			if (sender instanceof Player) {
				try { 
					if (ServerUtils.hasSpecificUpdate("1_8") && ((Player)sender).getUniqueId().toString().equalsIgnoreCase("ad6e8c0e-6c47-4e7a-a23d-8a2266d7baee")) { return true; }
					else if (sender.getName().equalsIgnoreCase("RockinChaos")) { return true; }
				} catch (Exception e) { if (sender.getName().equalsIgnoreCase("RockinChaos")) { return true; } }
			}
		}
		return false;
	}
	
   /**
    * Checks if custom items have permission requirements to get or use them.
    * 
    * @return If the custom items require certain permissions to be given or used.
    */
	public static boolean receiveEnabled() {
		return ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-Get");
	}
} public class PlayerHandler {
	
	private static HashMap<String, ItemStack[]> craftingItems = new HashMap<String, ItemStack[]>();
	private static HashMap<String, ItemStack[]> craftingOpenItems = new HashMap<String, ItemStack[]>();
	private static HashMap<String, ItemStack[]> creativeCraftingItems = new HashMap<String, ItemStack[]>();
	private static final int PLAYER_CRAFT_INV_SIZE = 5;
	
   /**
    * Restores the crafting items for all currently online players.
    * 
    */
    public static void restoreCraftItems() {
    	forOnlinePlayers(player -> { ItemHandler.restoreCraftItems(player, TriggerType.DEFAULT); } );
    }
    
   /**
    * Safely closes the players inventory in order to call the InventoryCloseEvent.
    * Fixes a bug with player.closeInventory() not calling the event by default, breaking crafting items.
    * 
    * @param player - The player to have their inventory closed.
    */
    public static void safeInventoryClose(final Player player) {
    	player.openInventory(Bukkit.createInventory(player.getInventory().getHolder(), 9));
    	player.closeInventory();	
    }
    
    public static boolean isEnabled(final Player player, final String item) {
    	DataObject dataItem = SQL.getData().getData(new DataObject(Table.ENABLED_PLAYERS, getPlayerID(player), player.getWorld().getName(), item, Boolean.toString(true)));
    	DataObject dataPlayer = SQL.getData().getData(new DataObject(Table.ENABLED_PLAYERS, getPlayerID(player), player.getWorld().getName(), "ALL", Boolean.toString(true)));
    	DataObject dataGlobal = SQL.getData().getData(new DataObject(Table.ENABLED_PLAYERS, getPlayerID(player), "Global", "ALL", Boolean.toString(true)));
    	DataObject dataALL = SQL.getData().getData(new DataObject(Table.ENABLED_PLAYERS, null, "Global", "ALL", Boolean.toString(true)));
    	final boolean enabled = (((dataItem != null ? Boolean.valueOf(dataItem.getEnabled()) : (dataPlayer != null ? Boolean.valueOf(dataPlayer.getEnabled()) : ((dataGlobal != null ? Boolean.valueOf(dataGlobal.getEnabled()) : (dataALL != null ? Boolean.valueOf(dataALL.getEnabled()) : true)))))));
    	if (!enabled) { ServerUtils.logDebug("{ItemMap} " + player.getName() + " will not receive any items, they have custom items are disabled."); }
    	return enabled;
    }
    
   /**
    * Checks if the Entity is a real player.
    * 
    * @param entity - The entity being checked.
    * @return If the entity is a real Player.
    */
    public static boolean isPlayer(final Entity entity) {
    	try {
	    	if (DependAPI.getDepends(false).citizensEnabled() && net.citizensnpcs.api.CitizensAPI.getNPCRegistry().isNPC(entity)) {
	    		return false;
	    	} else if (!(entity instanceof Player)) { 
	    		return false; 
	    	} else if (PlayerHandler.getPlayerID((Player)entity) == null || PlayerHandler.getPlayerID((Player)entity).isEmpty()) { 
	    		return false;
	    	} else if (((Player)entity).getAddress().getHostString() == null) {
	    		return false;
	    	}
    	} catch (Exception e) { return false; }
    	return true;
    }
	
   /**
    * Checks if the InventoryView is a player crafting inventory.
    * 
    * @param view - The InventoryView to be checked.
    * @return If the currently open inventory is a player crafting inventory.
    */
    public static boolean isCraftingInv(final InventoryView view) {
        return ((!view.getType().name().equalsIgnoreCase("HOPPER") && !view.getType().name().equalsIgnoreCase("BREWING")) ? view.getTopInventory().getSize() == PLAYER_CRAFT_INV_SIZE : false);
    }
	
   /**
    * Checks if the player is currently in creative mode.
    * 
    * @param player - The player to be checked.
    * @return If the player is currently in creative mode.
    */
	public static boolean isCreativeMode(final Player player) {
		if (player.getGameMode() == GameMode.CREATIVE) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the player is currently in adventure mode.
    * 
    * @param player - The player to be checked.
    * @return If the player is currently in adventure mode.
    */
	public static boolean isAdventureMode(final Player player) {
		if (player.getGameMode() == GameMode.ADVENTURE) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the player is has an open menu while left clicking.
    * 
    * @param view - The InventoryView being compared.
    * @param view - The action being checked.
    * @return If the player is currently interacting with an open menu.
    */
	public static boolean isMenuClick(final InventoryView view, final Action action) {
		if (!isCraftingInv(view) && (action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK)) {
			return true;
		}
		return false;
	}
	
   /**
    * Gets the current crafting slot contents of the player.
    * 
    * @param player - the Player to get the crafting contents of.
    * @return The ItemStack list of crafting slot contents.
    */
    public static ItemStack[] getTopContents(final Player player) {
		ItemStack[] tempContents = player.getOpenInventory().getTopInventory().getContents();
		ItemStack[] contents = new ItemStack[5];
		if (contents != null && tempContents != null) { 
			for (int i = 0; i <= 4; i++) { 
				contents[i] = tempContents[i].clone(); 
			} 
			return contents;
		}
		return tempContents;
    }
	
   /**
    * Sets the currently selected hotbar slot for the specified player.
    * 
    * @param player - The player to have their slot set.
    */
	public static void setHotbarSlot(final Player player, int slot) {
		if (slot != -1 && slot <= 8 && slot >= 0) {
			player.getInventory().setHeldItemSlot(slot);
		}
	}
	
   /**
    * Gets the current ItemStack in the players Main Hand,
    * If it is empty it will get the ItemStack in the Off Hand,
    * If the server version is below MC 1.9 it will use the 
    * legacy hand method to get the single hand.
    * 
    * @param player - The player to be checked.
    * @return The current ItemStack in the players hand.
    */
	public static ItemStack getHandItem(final Player player) {
		if (ServerUtils.hasSpecificUpdate("1_9") && player.getInventory().getItemInMainHand().getType() != null && player.getInventory().getItemInMainHand().getType() != Material.AIR) {
			return player.getInventory().getItemInMainHand();
		} else if (ServerUtils.hasSpecificUpdate("1_9") && player.getInventory().getItemInOffHand().getType() != null && player.getInventory().getItemInOffHand().getType() != Material.AIR) {
			return player.getInventory().getItemInOffHand();
		} else if (!ServerUtils.hasSpecificUpdate("1_9")) {
			return LegacyAPI.getInHandItem(player);
		}
		return null;
	}
	
   /**
    * Gets the current ItemStack in the players hand.
    * If the server version is below MC 1.9 it will use the 
    * legacy hand method to get the single hand.
    * 
    * @param player - The player to be checked.
    * @param type - The hand type to get.
    * @return The current ItemStack in the players hand.
    */
	public static ItemStack getPerfectHandItem(final Player player, final String type) {
		if (ServerUtils.hasSpecificUpdate("1_9") && type != null && type.equalsIgnoreCase("HAND")) {
			return player.getInventory().getItemInMainHand();
		} else if (ServerUtils.hasSpecificUpdate("1_9") && type != null && type.equalsIgnoreCase("OFF_HAND")) {
			return player.getInventory().getItemInOffHand();
		} else if (!ServerUtils.hasSpecificUpdate("1_9")) {
			return LegacyAPI.getInHandItem(player);
		}
		return null;
	}
	
   /**
    * Gets the current ItemStack in the players Main Hand.
    * If the server version is below MC 1.9 it will use the 
    * legacy hand method to get the single hand.
    * 
    * @param player - The player to be checked.
    * @return The current ItemStack in the players hand.
    */
	public static ItemStack getMainHandItem(final Player player) {
		if (ServerUtils.hasSpecificUpdate("1_9")) {
			return player.getInventory().getItemInMainHand();
		} else if (!ServerUtils.hasSpecificUpdate("1_9")) {
			return LegacyAPI.getInHandItem(player);
		}
		return null;
	}
	
   /**
    * Gets the current ItemStack in the players Off Hand.
    * If the server version is below MC 1.9 it will use the 
    * legacy hand method to get the single hand.
    * 
    * @param player - The player to be checked.
    * @return The current ItemStack in the players hand.
    */
	public static ItemStack getOffHandItem(final Player player) {
		if (ServerUtils.hasSpecificUpdate("1_9")) {
			return player.getInventory().getItemInOffHand();
		} else if (!ServerUtils.hasSpecificUpdate("1_9")) {
			return LegacyAPI.getInHandItem(player);
		}
		return null;
	}
	
   /**
    * Sets the specified ItemStack to the players Main Hand.
    * If the server version is below MC 1.9 it will use the 
    * legacy hand method to get the single hand.
    * 
    * @param player - The player to have the item set.
    * @param item - The ItemStack to be set.
    */
	public static void setMainHandItem(final Player player, final ItemStack item) {
		if (ServerUtils.hasSpecificUpdate("1_9")) {
			player.getInventory().setItemInMainHand(item);
		} else if (!ServerUtils.hasSpecificUpdate("1_9")) {
			LegacyAPI.setInHandItem(player, item);
		}
	}
	
   /**
    * Sets the specified ItemStack to the players Off Hand.
    * If the server version is below MC 1.9 it will use the 
    * legacy hand method to get the single hand.
    * 
    * @param player - The player to have the item set.
    * @param item - The ItemStack to be set.
    */
	public static void setOffHandItem(final Player player, final ItemStack item) {
		if (ServerUtils.hasSpecificUpdate("1_9")) {
			player.getInventory().setItemInOffHand(item);
		} else if (!ServerUtils.hasSpecificUpdate("1_9")) {
			LegacyAPI.setInHandItem(player, item);
		}
	}
	
   /**
    * Resolves a bug where canceling an experience level event causes it to visually glitch
    * and remain showing the uncanceled experience levels.
    * 
    * This simply gets the players current experience levels and resets 
    * them to cause a clientside update.
    * 
    * @param player - The player to have their levels set.
    */
	public static void updateExperienceLevels(final Player player) {
		SchedulerUtils.runLater(1L, () -> {
			player.setExp(player.getExp());
			player.setLevel(player.getLevel());
		});
	}
	
   /**
    * Updates the specified players inventory.
    * 
    * @param player - The player to have their inventory updated.
    * @param delay - The ticks to wait before updating the inventory.
    */
	public static void updateInventory(final Player player) {
		updateInventory(player, null, 0L);
	}
	
   /**
    * Updates the specified players inventory.
    * 
    * @param player - The player to have their inventory updated.
    * @param delay - The ticks to wait before updating the inventory.
    */
	public static void updateInventory(final Player player, final long delay) {
		updateInventory(player, null, delay);
	}
	
   /**
    * Updates the specified players inventory.
    * 
    * @param player - The player to have their inventory updated.
    * @param itemMap - The ItemMap expected to be updated.
    * @param delay - The ticks to wait before updating the inventory.
    */
	public static void updateInventory(final Player player, final ItemMap itemMap, final long delay) {
		SchedulerUtils.runAsyncLater(delay, () -> {
			try {
				for (int i = 0; i < 36; i++) {
					if (itemMap == null || itemMap.isReal(player.getInventory().getItem(i))) { 
					    ReflectionUtils.sendPacketPlayOutSetSlot(player, player.getInventory().getItem(i), (i < 9 ? (i + 36) : i)); 
					}
				}
				if (ServerUtils.hasSpecificUpdate("1_9")) { 
					if (itemMap == null || itemMap.isReal(getOffHandItem(player))) { 
						ReflectionUtils.sendPacketPlayOutSetSlot(player, getOffHandItem(player), 45); 
					} 
				}
				if (isCraftingInv(player.getOpenInventory())) {
					for (int i = 4; i >= 0; i--) { 
						if (itemMap == null || itemMap.isReal(player.getInventory().getItem(i)) || itemMap.isCraftingItem()) { 
							ReflectionUtils.sendPacketPlayOutSetSlot(player, player.getOpenInventory().getTopInventory().getItem(i), i); 
						}
					}
					for (int i = 0; i <= 3; i++) { 
						if (itemMap == null || itemMap.isReal(player.getInventory().getItem(i))) { 
							ReflectionUtils.sendPacketPlayOutSetSlot(player, player.getInventory().getItem(i + 36), (8 - i)); 
						}
					}
				}
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		});
	}
	
   /**
    * Gets the current skull owner of the specified item.
    * 
    * @param item - The item to have its skull owner fetched.
    * @return The ItemStacks current skull owner.
    */
	public static String getSkullOwner(final ItemStack item) {
		if (ServerUtils.hasSpecificUpdate("1_12") && item != null && item.hasItemMeta() && ItemHandler.isSkull(item.getType()) 
				&& ((SkullMeta) item.getItemMeta()).hasOwner() && ItemHandler.usesOwningPlayer() != false) {
			String owner =  ((SkullMeta) item.getItemMeta()).getOwningPlayer().getName();
			if (owner != null) { return owner; }
		} else if (item != null && item.hasItemMeta() 
				&& ItemHandler.isSkull(item.getType())
				&& ((SkullMeta) item.getItemMeta()).hasOwner()) {
			String owner = LegacyAPI.getSkullOwner(((SkullMeta) item.getItemMeta()));
			if (owner != null) { return owner; }
		} 
		return "NULL";
	}

   /**
    * Gets the Player instance from their String name.
    * 
    * @param playerName - The player name to be transformed.
    * @return The fetched Player instance.
    */
	public static Player getPlayerString(final String playerName) {
		Player args = null;
		try { args = Bukkit.getPlayer(UUID.fromString(playerName)); } catch (Exception e) { }
		if (playerName != null && DependAPI.getDepends(false).nickEnabled()) {
			try { 
				de.domedd.betternick.api.nickedplayer.NickedPlayer np = new de.domedd.betternick.api.nickedplayer.NickedPlayer(LegacyAPI.getPlayer(playerName));
				if (np.isNicked()) { return LegacyAPI.getPlayer(np.getRealName()); }
				else { return LegacyAPI.getPlayer(playerName); }
			} catch (NoClassDefFoundError e) {
				if (BetterNick.getApi().isPlayerNicked(LegacyAPI.getPlayer(playerName))) { return LegacyAPI.getPlayer(BetterNick.getApi().getRealName(LegacyAPI.getPlayer(playerName))); }
				else { return LegacyAPI.getPlayer(playerName); }
			}
		} else if (playerName != null && DependAPI.getDepends(false).nickAPIEnabled()) {
			if (xyz.haoshoku.nick.api.NickAPI.isNicked(xyz.haoshoku.nick.api.NickAPI.getPlayerOfNickedName(playerName))) {
				return xyz.haoshoku.nick.api.NickAPI.getPlayerOfNickedName(playerName);
			} else { return LegacyAPI.getPlayer(playerName); }
		} else if (args == null) { return LegacyAPI.getPlayer(playerName); }
		return args;
	}
	
   /**
    * Gets the UUID of the Player.
    * If the UUID does not exist it will fetch their String name.
    * 
    * @param player - The player to have their UUID fetched.
    * @return The UUID of the player or if not found, their String name.
    */
	public static String getPlayerID(final Player player) {
		try {
			if (player != null && ServerUtils.hasSpecificUpdate("1_8") && player.getUniqueId() != null) {
				return player.getUniqueId().toString();
			} else if (player != null && DependAPI.getDepends(false).nickEnabled()) {
				try {
					de.domedd.betternick.api.nickedplayer.NickedPlayer np = new de.domedd.betternick.api.nickedplayer.NickedPlayer(player);
					if (np.isNicked()) { 
						if (ServerUtils.hasSpecificUpdate("1_8") && np.getUniqueId() != null) {
							return np.getUniqueId().toString();
						} else {
							return np.getRealName();
						}
					} else { return player.getName(); }
				} catch (NoClassDefFoundError e) {
					if (BetterNick.getApi().isPlayerNicked(player)) { return BetterNick.getApi().getRealName(player);
					} else { return player.getName(); }
				}
			} else if (player != null && DependAPI.getDepends(false).nickAPIEnabled()) {
				if (xyz.haoshoku.nick.api.NickAPI.isNicked(player)) {
					return xyz.haoshoku.nick.api.NickAPI.getOriginalName(player);
				} else { return player.getName(); }
			} else if (player != null) {
				return player.getName();
			}
		} catch (Exception e) { 
			if (player != null) { return player.getName(); }
			ServerUtils.sendDebugTrace(e);
		}
		return "";
	}
	
   /**
    * Gets the UUID of the OfflinePlayer.
    * If the UUID does not exist it will fetch their String name.
    * 
    * @param player - The OfflinePlayer instance to have their UUID fetched.
    * @return The UUID of the player or if not found, their String name.
    */
	public static String getOfflinePlayerID(final OfflinePlayer player) {
		try {
			if (player != null && ServerUtils.hasSpecificUpdate("1_8") && player.getUniqueId() != null) {
				return player.getUniqueId().toString();
			} else if (player != null && DependAPI.getDepends(false).nickEnabled()) {
				try {
					de.domedd.betternick.api.nickedplayer.NickedPlayer np = new de.domedd.betternick.api.nickedplayer.NickedPlayer((BetterNick) player);
					if (np.isNicked()) { 
						if (ServerUtils.hasSpecificUpdate("1_8") && np.getUniqueId() != null) {
							return np.getUniqueId().toString();
						} else {
							return np.getRealName();
						}
					} else { return player.getName(); }
				} catch (NoClassDefFoundError e) {
					if (BetterNick.getApi().isPlayerNicked((Player) player)) { return BetterNick.getApi().getRealName((Player) player);
					} else { return player.getName(); }
				}
			} else if (player != null && DependAPI.getDepends(false).nickAPIEnabled()) {
				if (xyz.haoshoku.nick.api.NickAPI.isNickedName(player.getName())) {
					return xyz.haoshoku.nick.api.NickAPI.getOriginalName(xyz.haoshoku.nick.api.NickAPI.getPlayerOfNickedName(player.getName()));
				} else { return player.getName(); }
			} else if (player != null) {
				return player.getName();
			}
		} catch (Exception e) { 
			if (player != null) { return player.getName(); }
			ServerUtils.sendDebugTrace(e);
		}
		return "";
	}
	
   /**
    * Quick saves the current inventories crafting items.
    * 
    * @oaram player - The player having their crafting items saved.
    */
    public static void quickCraftSave(Player player) {
    	if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
    		ItemStack[] contents = new ItemStack[5];
    		if (contents != null && player.getOpenInventory().getTopInventory().getContents() != null) {
    			for (int i = 0; i <= 4; i++) {
    				contents[i] = player.getOpenInventory().getTopInventory().getContents()[i].clone();
    			}
    		}
    		craftingItems.put(PlayerHandler.getPlayerID(player), contents);
    	}
    }
    
   /**
    * Emulates the Player dropping the ItemStack.
    * 
    * @param player - The Player being referenced.
    * @param item - The item to be dropped.
    */
    public static void dropItem(final Player player, final ItemStack item) { 
    	Location location = player.getLocation();
    	location.setY(location.getY() + 1);
    	Item dropped = player.getWorld().dropItem(location, item);
		dropped.setVelocity(location.getDirection().multiply(.30));
    }
    
   /**
    * Gets the crafting items HashMap of players crafting contents.
    * 
    * @return The HashMap of players and their crafting contents.
    */
    public static HashMap<String, ItemStack[]> getCraftItems() {
    	return craftingItems;
    }
    
   /**
    * Adds the Player and their Crafting items to a HashMap.
    * 
    * @param player - The player being referenced.
    * @param items - THe items to be added.
    */
    public static void addCraftItems(final Player player, final ItemStack[] items) {
    	craftingItems.put(PlayerHandler.getPlayerID(player), items);
    }
    
   /**
    * Gets the crafting items HashMap of players prior to creative crafting contents.
    * 
    * @return The HashMap of players and their prior to creative crafting contents.
    */
    public static HashMap<String, ItemStack[]> getCreativeCraftItems() {
    	return creativeCraftingItems;
    }
    
   /**
    * Adds the Player and their Crafting items to a HashMap.
    * 
    * @param player - The player being referenced.
    * @param items - THe items to be added.
    */
    public static void addCreativeCraftItems(final Player player, final ItemStack[] items) {
    	creativeCraftingItems.put(PlayerHandler.getPlayerID(player), items);
    }
    
   /**
    * Removves the Player and their Crafting items from a HashMap.
    * 
    * @param player - The player being referenced.
    */
    public static void removeCreativeCraftItems(final Player player) {
    	creativeCraftingItems.remove(PlayerHandler.getPlayerID(player));
    }
    
   /**
    * Gets the crafting items HashMap of players prior to opened inventory crafting contents.
    * 
    * @return The HashMap of players and their prior to opened inventory crafting contents.
    */
    public static HashMap<String, ItemStack[]> getOpenCraftItems() {
    	return craftingOpenItems;
    }
    
   /**
    * Adds the Player and their Crafting items to a HashMap.
    * 
    * @param player - The player being referenced.
    * @param items - THe items to be added.
    */
    public static void addOpenCraftItems(final Player player, final ItemStack[] items) {
    	craftingOpenItems.put(PlayerHandler.getPlayerID(player), items);
    }
    
   /**
    * Removves the Player and their Crafting items from a HashMap.
    * 
    * @param player - The player being referenced.
    */
    public static void removeOpenCraftItems(final Player player) {
    	craftingOpenItems.remove(PlayerHandler.getPlayerID(player));
    }
    
   /**
    * Constantly cycles through the players crafting slots saving them to a HashMap for later use.
    * 
    */
    public static void cycleCrafting() {
    	SchedulerUtils.runAsyncTimer(15L, 0L, () -> {
    		Collection < ? > playersOnlineNew = null;
    		Player[] playersOnlineOld;
    		try {
    			if (Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).getReturnType() == Collection.class) {
    				if (Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).getReturnType() == Collection.class) {
    					playersOnlineNew = ((Collection < ? > ) Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).invoke(null, new Object[0]));
    					for (Object objPlayer: playersOnlineNew) {
    						if (((Player) objPlayer).isOnline() && PlayerHandler.isCraftingInv(((Player) objPlayer).getOpenInventory())) {
    							ItemStack[] tempContents = ((Player) objPlayer).getOpenInventory().getTopInventory().getContents();
    							ItemStack[] contents = new ItemStack[5];
    							if (contents != null && tempContents != null) {
	    							for (int i = 0; i <= 4; i++) {
	    								if (tempContents[i] != null) { 
	    									contents[i] = tempContents[i].clone();
	    								}
	    							}
    							}
    							craftingItems.put(PlayerHandler.getPlayerID(((Player) objPlayer)), contents);
    						} else {
    							craftingItems.remove(PlayerHandler.getPlayerID((Player) objPlayer));
    						}
    					}
    				}
    			} else {
    				playersOnlineOld = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).invoke(null, new Object[0]));
    				for (Player player: playersOnlineOld) {
    					if (player.isOnline() && PlayerHandler.isCraftingInv(player.getOpenInventory())) {
    						ItemStack[] tempContents = player.getOpenInventory().getTopInventory().getContents();
    						ItemStack[] contents = new ItemStack[5];
    						if (contents != null && tempContents != null) {
    							for (int i = 0; i <= 4; i++) {
    								contents[i] = tempContents[i].clone();
    							}
    						}
    						craftingItems.put(PlayerHandler.getPlayerID(player), contents);
    					} else {
    						craftingItems.remove(PlayerHandler.getPlayerID(player));
    					}
    				}
    			}
    		} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
    	});
    }
	
   /**
    * Gets the Nearby Players from the specified Players Location inside the Range.
    * 
    * @param player - The Player that is searching for Nearby Players.
    * @param range - The distance to check for Nearby Players.
    * @return The String name of the Nearby Player.
    */
    public static String getNearbyPlayer(final Player player, final int range) {
	    ArrayList < Location > sight = new ArrayList < Location > ();
	    ArrayList < Entity > entities = (ArrayList < Entity > ) player.getNearbyEntities(range, range, range);
	    Location origin = player.getEyeLocation();
	    sight.add(origin.clone().add(origin.getDirection()));
	    sight.add(origin.clone().add(origin.getDirection().multiply(range)));
	    sight.add(origin.clone().add(origin.getDirection().multiply(range + 3)));
	   	for (int i = 0; i < sight.size(); i++) {
	    	for (int k = 0; k < entities.size(); k++) {
	    		if (Math.abs(entities.get(k).getLocation().getX() - sight.get(i).getX()) < 1.3) {
	    			if (Math.abs(entities.get(k).getLocation().getY() - sight.get(i).getY()) < 1.5) {
	    				if (Math.abs(entities.get(k).getLocation().getZ() - sight.get(i).getZ()) < 1.3) {
	    					if (entities.get(k) instanceof Player) {
	    						if (ServerUtils.hasSpecificUpdate("1_8")) {
	    							return entities.get(k).getName();
	    						} else {
	    							return ((Player) entities.get(k)).getName();
	    						}
	    					}
	    				}
	    			}
	    		}
	    	}
	    }
    	return (LanguageAPI.getLang(false).getLangMessage("placeholders.PLAYER_INTERACT") != null ? LanguageAPI.getLang(false).getLangMessage("placeholders.PLAYER_INTERACT") : "INVALID");
    }
	
   /**
    * Executes an input of methods for the currently online players.
    * 
    * @param input - The methods to be executed.
    */
    public static void forOnlinePlayers(final Consumer<Player> input) {
		try {
		  /** New method for getting the current online players.
			* This is for MC 1.12+
			*/
			if (Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).getReturnType() == Collection.class) {
				for (Object objPlayer: ((Collection < ? > ) Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).invoke(null, new Object[0]))) { 
					input.accept(((Player) objPlayer));
				}
			} 
		  /** New old for getting the current online players.
			* This is for MC versions below 1.12.
			* 
			* @deprecated Legacy version of getting online players.
			*/
			else {
				for (Player player: ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).invoke(null, new Object[0]))) {
					input.accept(player);
				}
			}
		} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
	}
} public class UpdateHandler {
    private final String HOST = "https://api.github.com/repos/RockinChaos/" + ItemJoin.getInstance().getName().toLowerCase() + "/releases/latest";
    private String versionExact = ItemJoin.getInstance().getDescription().getVersion();
    private String localeVersion = this.versionExact.split("-")[0];
    private String latestVersion;
    private boolean betaVersion = this.versionExact.contains("-SNAPSHOT") || this.versionExact.contains("-BETA") || this.versionExact.contains("-ALPHA");
    private boolean devVersion = this.localeVersion.equals("${project.version}");
    
    private File jarRef;
    private int BYTE_SIZE = 2048;
    
    private boolean updatesAllowed = ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.CheckforUpdates");
    
    private static UpdateHandler updater;
        
   /**
    * Initializes the UpdateHandler and Checks for Updates upon initialization.
    *
    */
    public UpdateHandler() {
       this.jarRef = ItemJoin.getInstance().getPlugin();
       this.checkUpdates(ItemJoin.getInstance().getServer().getConsoleSender(), true);
    }
    
   /**
    * If the GitHub host has an available update, attenots to download the jar file.
    * Downloads and write the new data to the plugin jar file.
    * 
    * @param sender - The executor of the update checking.
    */
    public void forceUpdates(final CommandSender sender) {
    	if (this.updateNeeded(sender, false)) {
    		ServerUtils.messageSender(sender, "&aAn update has been found!");
    		ServerUtils.messageSender(sender, "&aAttempting to update from " + "&ev" + this.localeVersion + " &ato the new "  + "&ev" + this.latestVersion);
    		try {
    			String uri = this.HOST.replace("repos/", "").replace("api.", "").replace("latest", "download/" + "v" + this.latestVersion + "/" + ItemJoin.getInstance().getName().toLowerCase() + ".jar") + "?_=" + System.currentTimeMillis();
    			HttpURLConnection httpConnection = (HttpURLConnection) new URL(uri).openConnection();
    			httpConnection.setRequestProperty("User-Agent", "Mozilla/5.0...");
    			BufferedInputStream in = new BufferedInputStream(httpConnection.getInputStream());
    			FileOutputStream fos = new FileOutputStream(this.jarRef);
    			BufferedOutputStream bout = new BufferedOutputStream(fos, this.BYTE_SIZE);
    			String progressBar = "&a::::::::::::::::::::::::::::::";
    			byte[] data = new byte[this.BYTE_SIZE];
    			long cloudFileSize = httpConnection.getContentLength();
    			long fetchedSize = 0;
    			int bytesRead;
    			while ((bytesRead = in .read(data, 0, this.BYTE_SIZE)) >= 0) {
    				bout.write(data, 0, bytesRead);
    				fetchedSize += bytesRead;
    				final int currentProgress = (int)(((double) fetchedSize / (double) cloudFileSize) * 30);
    				if ((((fetchedSize * 100) / cloudFileSize) % 25) == 0 && currentProgress > 10) {
    					ServerUtils.messageSender(sender, progressBar.substring(0, currentProgress + 2) + "&c" + progressBar.substring(currentProgress + 2));
    				}
    			}
    			bout.close(); in.close(); fos.close();
    			ServerUtils.messageSender(sender, "&aSuccessfully updated to v" + this.latestVersion + "!");
    			ServerUtils.messageSender(sender, "&aYou must restart your server for this to take affect.");
    		} catch (Exception e) {
    			ServerUtils.messageSender(sender, "&cAn error has occurred while trying to update the plugin " + ItemJoin.getInstance().getName() + ".");
    			ServerUtils.messageSender(sender, "&cPlease try again later, if you continue to see this please contact the plugin developer.");
    			ServerUtils.sendDebugTrace(e);
    		}
    	} else {
    		if (this.betaVersion) {
    			ServerUtils.messageSender(sender, "&aYou are running a SNAPSHOT!");
    			ServerUtils.messageSender(sender, "&aIf you find any bugs please report them!");
    		}
    		ServerUtils.messageSender(sender, "&aYou are up to date!");
    	}
    }
    
   /**
    * Checks to see if an update is required, notifying the console window and online op players.
    * 
    * @param sender - The executor of the update checking.
    * @param onStart - If it is checking for updates on start.
    */
    public void checkUpdates(final CommandSender sender, final boolean onStart) {
    	if (this.updateNeeded(sender, onStart) && this.updatesAllowed) {
    		if (this.betaVersion) {
    			ServerUtils.messageSender(sender, "&cYour current version: &bv" + this.localeVersion + "-SNAPSHOT");
    			ServerUtils.messageSender(sender, "&cThis &bSNAPSHOT &cis outdated and a release version is now available.");
    		} else {
    			ServerUtils.messageSender(sender, "&cYour current version: &bv" + this.localeVersion + "-RELEASE");
    		}
    		ServerUtils.messageSender(sender, "&cA new version is available: " + "&av" + this.latestVersion + "-RELEASE");
    		ServerUtils.messageSender(sender, "&aGet it from: https://github.com/RockinChaos/" + ItemJoin.getInstance().getName().toLowerCase() + "/releases/latest");
    		ServerUtils.messageSender(sender, "&aIf you wish to auto update, please type /" + ItemJoin.getInstance().getName() + " Upgrade");
    		this.sendNotifications();
    	} else if (this.updatesAllowed) {
    		if (this.betaVersion) {
    			ServerUtils.messageSender(sender, "&aYou are running a SNAPSHOT!");
    			ServerUtils.messageSender(sender, "&aIf you find any bugs please report them!");
    		} else if (this.devVersion) {
    			ServerUtils.messageSender(sender, "&aYou are running a DEVELOPER SNAPSHOT!");
    			ServerUtils.messageSender(sender, "&aIf you find any bugs please report them!");
    			ServerUtils.messageSender(sender, "&aYou will not receive any updates requiring you to manually update.");
    		}
    		ServerUtils.messageSender(sender, "&aYou are up to date!");
    	}
    }
    
   /**
    * Directly checks to see if the GitHub host has an update available.
    * 
    * @param sender - The executor of the update checking.
    * @param onStart - If it is checking for updates on start.
    * @return If an update is needed.
    */
    private boolean updateNeeded(final CommandSender sender, final boolean onStart) {
    	if (this.updatesAllowed) {
    		if (!onStart) { ServerUtils.messageSender(sender, "&aChecking for updates..."); }
    		try {
    			URLConnection connection = new URL(this.HOST + "?_=" + System.currentTimeMillis()).openConnection();
    			BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    			String JsonString = StringUtils.toString(reader); 
			    JSONObject objectReader = (JSONObject) JSONValue.parseWithException(JsonString);
			    String gitVersion = objectReader.get("tag_name").toString();
    			reader.close();
    			if (gitVersion.length() <= 7) {
    				this.latestVersion = gitVersion.replaceAll("[a-z]", "").replace("-SNAPSHOT", "").replace("-BETA", "").replace("-ALPHA", "").replace("-RELEASE", "");
    				String[] latestSplit = this.latestVersion.split("\\.");
    				String[] localeSplit = this.localeVersion.split("\\.");
    				if (this.devVersion) {
    					return false;
    				} else if ((Integer.parseInt(latestSplit[0]) > Integer.parseInt(localeSplit[0]) || Integer.parseInt(latestSplit[1]) > Integer.parseInt(localeSplit[1]) || Integer.parseInt(latestSplit[2]) > Integer.parseInt(localeSplit[2]))
    						|| (this.betaVersion && (Integer.parseInt(latestSplit[0]) == Integer.parseInt(localeSplit[0]) && Integer.parseInt(latestSplit[1]) == Integer.parseInt(localeSplit[1]) && Integer.parseInt(latestSplit[2]) == Integer.parseInt(localeSplit[2])))) {
    					return true;
    				}
    			}
    		} catch (FileNotFoundException e) {
    			return false;
    		} catch (Exception e) {
    			ServerUtils.messageSender(sender, "&c&l[403] &cFailed to check for updates, GitHub has detected too many access requests, try again later.");
    			ServerUtils.sendDebugTrace(e);
    			return false;
    		}
    	} else if (!onStart) {
    		ServerUtils.messageSender(sender, "&cUpdate checking is currently disabled in the config.yml");
    		ServerUtils.messageSender(sender, "&cIf you wish to use the auto update feature, you will need to enable it.");
        }
    	return false;
    }
    
   /**
    * Sends out notifications to all online op players that 
    * an update is available at the time of checking for updates.
    * 
    */
    private void sendNotifications() {
    	try {
    		Collection < ? > playersOnline = null;
    		Player[] playersOnlineOld = null;
    		if (Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).getReturnType() == Collection.class) {
    			if (Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).getReturnType() == Collection.class) {
    				playersOnline = ((Collection < ? > ) Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).invoke(null, new Object[0]));
    				for (Object objPlayer: playersOnline) {
    					if (((Player) objPlayer).isOp()) {
    						ServerUtils.messageSender(((Player) objPlayer), "&eAn update has been found!");
    						ServerUtils.messageSender(((Player) objPlayer), "&ePlease update to the latest version: v" + this.latestVersion);
    					}
    				}
    			}
    		} else {
    			playersOnlineOld = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class < ? > [0]).invoke(null, new Object[0]));
    			for (Player objPlayer: playersOnlineOld) {
    				if (objPlayer.isOp()) {
						ServerUtils.messageSender(objPlayer, "&eAn update has been found!");
						ServerUtils.messageSender(objPlayer, "&ePlease update to the latest version: v" + this.latestVersion);
    				}
    			}
    		}
    	} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
    }
    
    
   /**
    * Gets the exact string version from the plugin yml file.
    * 
    * @return The exact server version.
    */
    public String getVersion() {
    	return this.versionExact;
    }
    
   /**
    * Gets the plugin jar file directly.
    * 
    * @return The plugins jar file.
    */
    public File getJarReference() {
    	return this.jarRef;
    }
    
   /**
    * Gets the instance of the UpdateHandler.
    * 
    * @param regen - If the instance should be regenerated.
    * @return The UpdateHandler instance.
    */
    public static UpdateHandler getUpdater(final boolean regen) { 
        if (updater == null || regen) { updater = new UpdateHandler(); }
        return updater; 
    } 
} public class ItemMap {
	
	private String configName;
	private ConfigurationSection nodeLocation;
	private Integer probability = -1;
	
	private ItemStack tempItem = null;
	private ItemMeta tempMeta = null;
	private Material material = Material.AIR;
	private Short dataValue = 0;
	
	private String customName = null;
	private List < String > customLore = new ArrayList < String > ();

	private List<String> AllSlots = new ArrayList<String>();
	private Integer InvSlot = 0;
	private String CustomSlot = null;
	private boolean craftingItem = false;
	
	private boolean giveNext = false;
	private boolean moveNext = false;
	private boolean dropFull = false;
	
	private String Arbitrary = null;
	private String itemValue = null;
	
	private Integer count = 1;
	private Map < String, Double > attributes = new HashMap < String, Double > ();
	
	private Short durability = null;
	private Integer data = null;
	private Integer modelData = null;
	
	private String author;
	private String title;
	private Object generation;
	private List < String > bookPages = new ArrayList < String > ();
	private List < List <String> > listPages = new ArrayList < List <String> > ();
	
	private short mapId = -1;
	private MapView mapView = null;
	private String customMapImage = null;
    
    private FireworkEffect firework = null;
    private Type fireworkType = null;
    private boolean fireworkFlicker = false;
    private boolean fireworkTrail = false;
    private Integer power = 0;
    private List<DyeColor> fireworkColor = new ArrayList<DyeColor>();
    private DyeColor chargeColor = null;
    
    private String skullOwner = null;
    private String skullTexture = null;
    private boolean headDatabase = false;
    
    private List <PotionEffect> effect = new ArrayList<PotionEffect>();
    private List <Pattern> bannerPatterns = new ArrayList<Pattern>();
    
    private Map < Character, String > ingredients = new HashMap < Character, String > ();
    private List <Character> recipe = Arrays.asList( 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' );
    
    private String leatherColor;
    private String leatherHex;
    
    private String teleportEffect;
    private String teleportSound;
	private Double teleportSoundVolume = 1.0;
	private Double teleportSoundPitch = 1.0;
    
	private Integer interactCooldown = 0;
	private boolean customConsumable = false;
	private Map < String, Integer > enchants = new HashMap < String, Integer > ();
	
	private Map < String, String > nbtProperty = new HashMap < String, String > ();
	private List < Object > nbtProperties = new ArrayList < Object > ();
	private Map < String, Long > playersOnInteractCooldown = new HashMap < String, Long > ();
	private HashMap < String, Long > storedSpammedPlayers = new HashMap < String, Long > ();
	private int spamtime = 1;
	
	
//  ============================================== //
//         Drop Chances for each item.          //
//  ============================================== //
	private Map < EntityType, Double > mobsDrop = new HashMap < EntityType, Double > ();
	private Map < Material, Double > blocksDrop = new HashMap < Material, Double > ();
//  ============================================== //
	
//  ============================================== //
//         NBT Information for each item.          //
//  ============================================== //
    private String newNBTData;
    private Object newNBTTag;
    private String legacySecret;
//  ============================================== //
	
//  ============================================== //
//     ItemAnimation Information for each item.    //
//  ============================================== //
	private List < String > dynamicNames = new ArrayList < String > ();
	private List < List < String > > dynamicLores = new ArrayList < List <String> > ();
	private List < String > dynamicMaterials = new ArrayList < String > ();
	private List < String > dynamicOwners = new ArrayList < String > ();
	private List < String > dynamicTextures = new ArrayList < String > ();
	private boolean materialAnimated = false;
	private Map < Player, ItemAnimation > localeAnimations = new HashMap < Player, ItemAnimation > ();
//  ====================================================================================================== //
	
	
//  ============================================== //
//      ItemCommand Information for each item.     //
//  ============================================== //
	private ItemCommand[] commands = new ItemCommand[0];
	private Integer cooldownSeconds = 0;
	private Integer commandsReceive = 0;
	private String cooldownMessage;
	private Sound commandSound;
	private Double commandSoundVolume = 1.0;
	private Double commandSoundPitch = 1.0;
	private String commandParticle;
	private String itemCost;
	private Integer cost = 0;
	private Integer warmDelay = 0;
	private List < Player > warmPending = new ArrayList < Player > ();
	private boolean useCooldown = false;
	private boolean subjectRemoval = false;
	private CommandSequence sequence;
	private List<String> disposableConditions = new ArrayList<String>();
	private List<String> triggerConditions = new ArrayList<String>();
	private Map < String, List<String> > commandConditions = new HashMap < String, List<String> > ();
	private String disposableMessage = null;
	private String triggerMessage = null;
	private Map < String, String > commandMessages = new HashMap < String, String > ();
	private Map < String, Long > playersOnCooldown = new HashMap < String, Long > ();
	private HashMap < String, Long > playersOnCooldownTick = new HashMap < String, Long > ();
//  ============================================================================================= //
	
	
//  ============================================== //
//            Itemflags for each item.             //
//  ============================================== //
	private String itemflags;
	
	private boolean vanillaItem = false;
	private boolean vanillaStatus = false;
	private boolean vanillaControl = false;
	private boolean unbreakable = false;
	private boolean countLock = false;
	private boolean teleportArrow = false;
	private boolean cancelEvents = false;
	private boolean itemStore = false;
	private boolean itemModify = false;
	private boolean noCrafting = false;
	private boolean noRepairing = false;
	private boolean animate = false;
	private boolean dynamic = false;
	private boolean glowing = false;
	private boolean overwritable = false;
	private boolean blockPlacement = false;
	private boolean hideAttributes = false;
	private boolean hideFlags = false;
	private boolean hideDurability = false;
	private boolean blockEquip = false;
	private boolean blockMovement = false;
	private boolean closeInventory = false;
	private boolean selfDroppable = false;
	private boolean deathDroppable = false;
	private boolean deathKeepable = false;
	private boolean disposable = false;
	private boolean itemChangable = false;
	private boolean alwaysGive = false;
	private boolean autoRemove = false;
	private boolean stackable = false;
	private boolean selectable = false;
	private boolean CreativeBypass = false;
	private boolean AllowOpBypass = false;
	
	private boolean onlyFirstJoin = false;
    private boolean onlyFirstLife = false;
	private boolean onlyFirstWorld = false;
	private boolean ipLimited = false;
//  ============================================== //
	
//  ============================================== //
//             Triggers for each item.             //
//  ============================================== //
	private boolean giveOnDisabled = false;
	private boolean giveOnJoin = false;
	private boolean giveOnRespawn = false;
	private boolean giveOnWorldSwitch = false;
	private boolean giveOnRegionEnter = false;
	private boolean giveOnRegionLeave = false;
	private boolean giveOnRegionAccess = false;
	private boolean giveOnRegionEgress = false;
	private boolean useOnLimitSwitch = false;
	
	private String triggers = null;
	private String limitModes = null;
//  ============================================== //
	
	private String toggleNode = null;
	private String toggleMessage = null;
	private List<String> toggleCommands = new ArrayList < String > ();
	private List<PluginCommand> togglePlugins = new ArrayList < PluginCommand > ();
	
	private String permissionNode = null;
	private boolean permissionNeeded = false;
	private boolean opPermissionNeeded = false;
	
	private List < String > contents = new ArrayList < String > ();
	
	private List < String > enabledRegions = new ArrayList < String > ();
	private List < String > enabledWorlds = new ArrayList < String > ();
	private List < String > disabledWorlds = new ArrayList < String > ();
// ======================================================================================== //
	
   /**
    * Creates a new ItemMap instance.
    * Typically used in the creation of items.
    * 
    * @param designer - The ItemDesigner instance that is creating the ItemMap.
    * @param internalName - The node name of the ItemMap.
    * @param slot - The slot of the ItemMap.
    */
	public ItemMap(final String internalName, final String slot) {
        this.nodeLocation = ConfigHandler.getConfig().getItemSection(internalName);
        this.configName = internalName;
        this.setItemValue(ConfigHandler.getConfig().getItemID(slot));
        this.setSlot(slot);
        if (ItemHandler.isCraftingSlot(slot)) { this.craftingItem = true; }
        
        if (this.nodeLocation != null) {
        	this.setMultipleSlots();
	        this.setCount(this.nodeLocation.getString(".count"));
			this.setCommandCost();
			this.setCommandReceive();
			this.setCommandWarmDelay();
			this.setCommandSound();
			this.setCommandParticle();
			this.setCommandCooldown();
			this.setCommandSequence();
			this.setCommands(ItemCommand.arrayFromString(this, this.sequence == CommandSequence.RANDOM_LIST));
			this.setToggleCommands(this.nodeLocation.getString(".toggle"));
			this.setConditions();
	        this.setInteractCooldown();
	        this.setPlayersOnCooldown();
	        this.setTeleportArrow();
	        this.setLimitModes();
	        this.setTriggers();
	        this.setItemflags();
			this.setWorlds();
			this.setRegions();
			this.setTogglePerm(this.nodeLocation.getString(".toggle-permission"));
			this.setToggleMessage(this.nodeLocation.getString(".toggle-message"));
	        this.setPerm(this.nodeLocation.getString(".permission-node"));
	        this.setPermissionNeeded(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items"));
	    	this.setOPPermissionNeeded(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items-OP"));
        }
	}
	
   /**
    * Creates a new ItemMap instance.
    * Called when copying an ItemMap, sadly this has to exist.
    * 
    * Welcome to nothing!
    * 
    */
	public ItemMap() { }
//  ========================================================================================================= //
	
//  ============================================== //
//   Setter functions for first ItemMap creation.  //
//  ============================================== //
   /**
    * Sets the ItemMaps Multiple Slots.
    * 
    */
	private void setMultipleSlots() {
        if (this.nodeLocation.getString(".slot") != null && !this.nodeLocation.getString(".slot").isEmpty() && this.nodeLocation.getString(".slot").contains(",")) {
        	String[] slots = this.nodeLocation.getString(".slot").replace(" ", "").split(",");
			for (String slot: slots) { 
				if (slot.startsWith("C[") || slot.startsWith("C(")) { slot = slot.replace("C", "CRAFTING"); }
				if (slot.startsWith("CRAFTING")) { slot = slot.replace("(", "[").replace(")", "]"); }
				this.AllSlots.add(slot); 
			}
        }
	}
	
   /**
    * Sets the ItemMaps Commands Cost.
    * 
    */
	private void setCommandCost() {
		if (this.nodeLocation.getString("commands-item") != null && !this.nodeLocation.getString("commands-item").isEmpty()) { this.itemCost = this.nodeLocation.getString("commands-item"); }
		if (this.nodeLocation.getString("commands-cost") != null && StringUtils.isInt(this.nodeLocation.getString("commands-cost"))) { this.cost = this.nodeLocation.getInt("commands-cost"); }
	}
	
   /**
    * Sets the ItemMaps Commands Receive.
    * 
    */
	private void setCommandReceive() {
		if (this.nodeLocation.getString("commands-receive") != null && StringUtils.isInt(this.nodeLocation.getString("commands-receive"))) { this.commandsReceive = this.nodeLocation.getInt("commands-receive"); }
	}
	
   /**
    * Sets the ItemMaps Commands Warmup Delay.
    * 
    */
	private void setCommandWarmDelay() {
		if (this.nodeLocation.getString("commands-warmup") != null && StringUtils.isInt(this.nodeLocation.getString("commands-warmup"))) { this.warmDelay = this.nodeLocation.getInt("commands-warmup"); }
	}
	
   /**
    * Sets the ItemMaps Commands Sound.
    * 
    */
	private void setCommandSound() {
		try { 
			if (this.nodeLocation.getString(".commands-sound") != null) { 
				final String sound = this.nodeLocation.getString(".commands-sound");
				if (sound.contains(":")) {
					final String[] soundParts = sound.split(":");
					this.commandSound = Sound.valueOf(soundParts[0]);
					try {
						this.commandSoundVolume = Double.valueOf(soundParts[1]);
						this.commandSoundPitch = Double.valueOf(soundParts[2]);
					} catch (Exception e) { 
						ServerUtils.logSevere("{ItemMap} The formatting for the item " + this.configName + " commands-sound is incorrect and will not be set!"); 
						ServerUtils.sendDebugTrace(e);
					}
				} else {
					this.commandSound = Sound.valueOf(this.nodeLocation.getString(".commands-sound"));
				}
			} 
		} catch (Exception e) { 
			ServerUtils.logSevere("{ItemMap} Your server is running MC " + ReflectionUtils.getServerVersion() + " and this version of Minecraft does not have the defined command-sound " + this.nodeLocation.getString(".commands-sound") + "."); 
			ServerUtils.sendDebugTrace(e);
		}
	}
	
   /**
    * Sets the ItemMaps Commands Particle.
    * 
    */
	private void setCommandParticle() {
		if (this.nodeLocation.getString(".commands-particle") != null) { this.commandParticle = this.nodeLocation.getString(".commands-particle"); }
	}
	
   /**
    * Sets the ItemMaps Commands Cooldown.
    * 
    */
	private void setCommandCooldown() {
		this.useCooldown = this.nodeLocation.getString("commands-cooldown") != null;
		if (this.useCooldown) { this.cooldownSeconds = this.nodeLocation.getInt("commands-cooldown"); }
		this.cooldownMessage = this.nodeLocation.getString("cooldown-message");
	}
	
   /**
    * Sets the ItemMaps Commands Sequence.
    * 
    */
	private void setCommandSequence() {
		if (this.nodeLocation.getString("commands-sequence") != null) { 
		    if (StringUtils.containsIgnoreCase(this.nodeLocation.getString("commands-sequence"), "SEQUENTIAL")) { this.sequence = CommandSequence.SEQUENTIAL; }
		    else if (StringUtils.containsIgnoreCase(this.nodeLocation.getString("commands-sequence"), "RANDOM_SINGLE")) { this.sequence = CommandSequence.RANDOM_SINGLE; }
		    else if (StringUtils.containsIgnoreCase(this.nodeLocation.getString("commands-sequence"), "RANDOM_LIST")) { this.sequence = CommandSequence.RANDOM_LIST; }
			else if (StringUtils.containsIgnoreCase(this.nodeLocation.getString("commands-sequence"), "RANDOM")) { this.sequence = CommandSequence.RANDOM; }
		    else if (StringUtils.containsIgnoreCase(this.nodeLocation.getString("commands-sequence"), "REMAIN")) { this.sequence = CommandSequence.REMAIN; }
		}
	}
	
   /**
    * Sets the ItemMaps Interact Cooldown.
    * 
    */
	private void setInteractCooldown() {
        if (this.nodeLocation.getString(".use-cooldown") != null) {
        	this.interactCooldown = this.nodeLocation.getInt(".use-cooldown");
        }
	}
	
   /**
    * Sets the ItemMaps Teleport Arrow.
    * 
    */
	private void setTeleportArrow() {
        this.teleportEffect = this.nodeLocation.getString(".teleport-effect");
        final String sound = this.nodeLocation.getString(".teleport-sound");
        if (sound != null && sound.contains(":")) {
        	
        }
		if (sound != null && sound.contains(":")) {
			final String[] soundParts = sound.split(":");
			this.teleportSound = soundParts[0];
			try {
				this.teleportSoundVolume = Double.valueOf(soundParts[1]);
				this.teleportSoundPitch = Double.valueOf(soundParts[2]);
			} catch (Exception e) { 
				ServerUtils.logSevere("{ItemMap} The formatting for the item " + this.configName + " teleport-sound is incorrect and will not be set!"); 
				ServerUtils.sendDebugTrace(e);
			}
		} else {
			this.teleportSound = sound;
		}
	}
	
   /**
    * Sets the ItemMaps ItemFlags.
    * 
    */
	private void setItemflags() {
		if (this.nodeLocation.getString(".itemflags") != null) {
			this.itemflags = this.nodeLocation.getString(".itemflags");
			this.vanillaItem = StringUtils.containsIgnoreCase(this.itemflags, "vanilla");
			this.vanillaStatus = StringUtils.containsIgnoreCase(this.itemflags, "vanilla-status");
			this.vanillaControl = StringUtils.containsIgnoreCase(this.itemflags, "vanilla-control");
			this.disposable = StringUtils.containsIgnoreCase(this.itemflags, "disposable");
			this.blockPlacement = StringUtils.containsIgnoreCase(this.itemflags, "placement");
			this.blockMovement = StringUtils.containsIgnoreCase(this.itemflags, "inventory-modify") || StringUtils.containsIgnoreCase(this.itemflags, "inventory-close");
			this.blockEquip = StringUtils.containsIgnoreCase(this.itemflags, "cancel-equip");
			this.closeInventory = StringUtils.containsIgnoreCase(this.itemflags, "inventory-close");
			this.itemChangable = StringUtils.containsIgnoreCase(this.itemflags, "allow-modifications") || StringUtils.containsIgnoreCase(this.itemflags, "item-changable");
			this.alwaysGive = StringUtils.containsIgnoreCase(this.itemflags, "always-give");
			this.autoRemove = StringUtils.containsIgnoreCase(this.itemflags, "auto-remove");
			this.stackable = StringUtils.containsIgnoreCase(this.itemflags, "stackable");
			this.selectable = StringUtils.containsIgnoreCase(this.itemflags, "selectable");
			this.dynamic = StringUtils.containsIgnoreCase(this.itemflags, "dynamic");
			this.animate = StringUtils.containsIgnoreCase(this.itemflags, "animate");
			this.glowing = StringUtils.containsIgnoreCase(this.itemflags, "glowing") || StringUtils.containsIgnoreCase(this.itemflags, "glow");
			this.giveNext = StringUtils.containsIgnoreCase(this.itemflags, "give-next");
			this.moveNext = StringUtils.containsIgnoreCase(this.itemflags, "move-next");
			this.dropFull = StringUtils.containsIgnoreCase(this.itemflags, "drop-full");
			this.itemStore = StringUtils.containsIgnoreCase(this.itemflags, "item-store");
			this.itemModify = StringUtils.containsIgnoreCase(this.itemflags, "item-modifiable");
			this.noCrafting = StringUtils.containsIgnoreCase(this.itemflags, "item-craftable");
			this.noRepairing = StringUtils.containsIgnoreCase(this.itemflags, "item-repairable");
			this.cancelEvents = StringUtils.containsIgnoreCase(this.itemflags, "cancel-events");
			this.countLock = StringUtils.containsIgnoreCase(this.itemflags, "count-lock");
			this.teleportArrow = StringUtils.containsIgnoreCase(this.itemflags, "teleport");
			this.overwritable = StringUtils.containsIgnoreCase(this.itemflags, "overwrite");
			this.ipLimited = StringUtils.containsIgnoreCase(this.itemflags, "ip-limit");
			this.deathKeepable = StringUtils.containsIgnoreCase(this.itemflags, "death-keep");
			this.deathDroppable = StringUtils.containsIgnoreCase(this.itemflags, "death-drops");
			this.selfDroppable = StringUtils.containsIgnoreCase(this.itemflags, "self-drops");
			
			// Shared with Triggers //
			this.setOnlyFirstJoin((StringUtils.containsIgnoreCase(this.itemflags, "first-join")  ? true : this.onlyFirstJoin));
			this.setOnlyFirstLife((StringUtils.containsIgnoreCase(this.itemflags, "first-life")  ? true : this.onlyFirstLife));
			this.onlyFirstWorld = (StringUtils.containsIgnoreCase(this.itemflags, "first-world") ? true : this.onlyFirstWorld);
			this.AllowOpBypass = (StringUtils.containsIgnoreCase(this.itemflags, "AllowOpBypass") ? true : this.AllowOpBypass);
			this.CreativeBypass = (StringUtils.containsIgnoreCase(this.itemflags, "CreativeBypass") ? true : this.CreativeBypass);
		}
	}
	
   /**
    * Sets the ItemMaps Limit Modes.
    * 
    */
	private void setLimitModes() {
		this.limitModes = this.nodeLocation.getString(".limit-modes");
	}
	
   /**
    * Sets the ItemMaps Triggers.
    * 
    */
	private void setTriggers() {
		final String defaultTriggers = ConfigHandler.getConfig().getFile("config.yml").getString("Settings.Default-Triggers");
		this.triggers = (this.nodeLocation.getString("triggers") != null ? this.nodeLocation.getString("triggers") : (defaultTriggers != null && !defaultTriggers.isEmpty() ? defaultTriggers : "JOIN"));
		this.giveOnDisabled = StringUtils.splitIgnoreCase(this.triggers, "DISABLED", ",");
		this.giveOnJoin = StringUtils.splitIgnoreCase(this.triggers, "JOIN", ",");
		this.giveOnRespawn = StringUtils.splitIgnoreCase(this.triggers, "RESPAWN", ",");
		this.giveOnWorldSwitch = StringUtils.splitIgnoreCase(this.triggers, "WORLD-CHANGE", ",") || StringUtils.splitIgnoreCase(this.triggers, "WORLD-SWITCH", ",");
		this.giveOnRegionEnter = StringUtils.splitIgnoreCase(this.triggers, "REGION-ENTER", ",");
		this.giveOnRegionLeave = StringUtils.splitIgnoreCase(this.triggers, "REGION-REMOVE", ",") || StringUtils.splitIgnoreCase(this.triggers, "REGION-EXIT", ",") || StringUtils.splitIgnoreCase(this.triggers, "REGION-LEAVE", ",");
		this.giveOnRegionAccess = StringUtils.splitIgnoreCase(this.triggers, "REGION-ACCESS", ",");
		this.giveOnRegionEgress = StringUtils.splitIgnoreCase(this.triggers, "REGION-EGRESS", ","); 
		if (this.giveOnRegionAccess || this.giveOnRegionEgress) { this.giveOnRegionEnter = false; this.giveOnRegionLeave = false; }
		this.useOnLimitSwitch = StringUtils.splitIgnoreCase(this.triggers, "GAMEMODE-SWITCH", ",");
		this.setOnlyFirstJoin(StringUtils.splitIgnoreCase(this.triggers, "FIRST-JOIN", ","));
		this.setOnlyFirstLife(StringUtils.splitIgnoreCase(this.triggers, "FIRST-LIFE", ","));
		this.setOnlyFirstWorld(StringUtils.splitIgnoreCase(this.triggers, "FIRST-WORLD", ","));
	}
	
   /**
    * Sets the ItemMaps Stored Contents.
    * 
    */
	public void setContents() {
		if (this.material != null && StringUtils.containsIgnoreCase(this.getMaterial().toString(), "SHULKER") && this.nodeLocation.getString(".contents") != null && this.nodeLocation.getStringList(".contents") != null && !this.nodeLocation.getStringList(".contents").isEmpty()) {
			this.contents = this.nodeLocation.getStringList(".contents");
		} else if (this.material != null && !StringUtils.containsIgnoreCase(this.getMaterial().toString(), "SHULKER") && this.nodeLocation.getString(".contents") != null && this.nodeLocation.getStringList(".contents") != null && !this.nodeLocation.getStringList(".contents").isEmpty()) {
			ServerUtils.logWarn("{ItemMap} The item " + this.getConfigName() + " cannot have contents set as it does not support it.");
		}
	}
	
   /**
    * Sets the ItemMaps Enabled Regions.
    * 
    */
	private void setRegions() {
		if (this.nodeLocation.getString(".enabled-regions") != null && !this.nodeLocation.getString(".enabled-regions").isEmpty()) {
			String[] enabledParts = this.nodeLocation.getString(".enabled-regions").replace(" ,  ", ",").replace(" , ", ",").replace(",  ", ",").replace(", ", ",").split(",");
			for (String region: enabledParts) {
				this.enabledRegions.add(region); 
				DependAPI.getDepends(false).getGuard().addLocaleRegion(region);
			}
		} else if (isGiveOnRegionEnter() || isGiveOnRegionLeave()) { 
			DependAPI.getDepends(false).getGuard().addLocaleRegion("UNDEFINED"); 
			this.enabledRegions.add("UNDEFINED"); }
	}
	
   /**
    * Sets the ItemMaps Conditions.
    * 
    */
	private void setConditions() {
		if (this.nodeLocation.getString(".trigger-fail-message") != null && !this.nodeLocation.getString(".trigger-fail-message").isEmpty()) {
			this.triggerMessage = this.nodeLocation.getString(".trigger-fail-message");
		}
		if (this.nodeLocation.getStringList(".trigger-conditions") != null && !this.nodeLocation.getStringList(".trigger-conditions").isEmpty()) {
			this.triggerConditions = this.nodeLocation.getStringList(".trigger-conditions");
		} else if (this.nodeLocation.getString(".trigger-conditions") != null && !this.nodeLocation.getString(".trigger-conditions").isEmpty()) {
			this.triggerConditions.add(this.nodeLocation.getString(".trigger-conditions"));
		} 
		if (this.nodeLocation.getString(".disposable-fail-message") != null && !this.nodeLocation.getString(".disposable-fail-message").isEmpty()) {
			this.disposableMessage = this.nodeLocation.getString(".disposable-fail-message");
		}
		if (this.nodeLocation.getStringList(".disposable-conditions") != null && !this.nodeLocation.getStringList(".disposable-conditions").isEmpty()) {
			this.disposableConditions = this.nodeLocation.getStringList(".disposable-conditions");
		} else if (this.nodeLocation.getString(".disposable-conditions") != null && !this.nodeLocation.getString(".disposable-conditions").isEmpty()) {
			this.disposableConditions.add(this.nodeLocation.getString(".disposable-conditions"));
		}
		for (Action action : Action.values()) {
			if (this.nodeLocation.getString(action.config() + "-fail-message") != null && !this.nodeLocation.getString(action.config() + "-fail-message").isEmpty()) {
				this.commandMessages.put(action.config(), this.nodeLocation.getString(action.config() + "-fail-message"));
			}
			if (this.nodeLocation.getStringList(action.config() + "-conditions") != null && !this.nodeLocation.getStringList(action.config() + "-conditions").isEmpty()) {
				this.commandConditions.put(action.config(), this.nodeLocation.getStringList(action.config() + "-conditions"));
			} else if (this.nodeLocation.getString(action.config() + "-conditions") != null && !this.nodeLocation.getString(action.config() + "-conditions").isEmpty()) {
				List < String > commandCond = new ArrayList < String > ();
				commandCond.add(this.nodeLocation.getString(action.config() + "-conditions"));
				this.commandConditions.put(action.config(), commandCond);
			}
		}
	}
	
   /**
    * Sets the ItemMaps Enabled Worlds.
    * 
    */
	private void setWorlds() {
		SchedulerUtils.run(() -> {
			if (this.nodeLocation.getString(".enabled-worlds") != null && !this.nodeLocation.getString(".enabled-worlds").isEmpty()) {
				String[] enabledParts = this.nodeLocation.getString(".enabled-worlds").replace(" ,  ", ",").replace(" , ", ",").replace(",  ", ",").replace(", ", ",").split(",");
				for (String enabledWorld : enabledParts) {
					if (enabledWorld.equalsIgnoreCase("ALL") || enabledWorld.equalsIgnoreCase("GLOBAL")) {
						this.enabledWorlds.add("ALL");
					} else {
						for (World world: Bukkit.getServer().getWorlds()) {
							if (enabledWorld.equalsIgnoreCase(world.getName())) {
								this.enabledWorlds.add(world.getName());
							} else if (enabledWorld.contains("*") && world.getName().toUpperCase().startsWith(enabledWorld.split("\\*")[0].toUpperCase())) {
								this.enabledWorlds.add(enabledWorld);
							}
						}
					}
				}
			} else { this.enabledWorlds.add("ALL"); }
			if (this.nodeLocation.getString(".disabled-worlds") != null && !this.nodeLocation.getString(".disabled-worlds").isEmpty()) {
				String[] disabledParts = this.nodeLocation.getString(".disabled-worlds").replace(" ,  ", ",").replace(" , ", ",").replace(",  ", ",").replace(", ", ",").split(",");
				for (String disabledWorld : disabledParts) {
					if (disabledWorld.equalsIgnoreCase("ALL") || disabledWorld.equalsIgnoreCase("GLOBAL")) {
						this.disabledWorlds.add("ALL");
					} else {
						for (World world: Bukkit.getServer().getWorlds()) {
							if (disabledWorld.equalsIgnoreCase(world.getName())) {
								this.disabledWorlds.add(world.getName());
							} else if (disabledWorld.contains("*") && world.getName().toUpperCase().startsWith(disabledWorld.split("\\*")[0].toUpperCase())) {
								this.disabledWorlds.add(disabledWorld);
							}
						}
					}
				}
			}
		});
	}
	
   /**
    * Sets the Players On Cooldown from the SQLite Database.
    * 
    */
	private void setPlayersOnCooldown() {
		if (this.cooldownSeconds > 0) {
			List<DataObject> dataList = SQL.getData().getDataList(new DataObject(Table.ON_COOLDOWN, null, null, this.getConfigName(), String.valueOf(this.getCommandCooldown()), null));
			for (DataObject dataObject : dataList) {
				if (dataObject != null) {
					this.playersOnCooldown.put(dataObject.getPlayerId(), Long.parseLong(dataObject.getDuration()));
					SQL.getData().removeData(new DataObject(Table.ON_COOLDOWN, null, null, this.getConfigName(), String.valueOf(this.getCommandCooldown()), null));
				}
			}
		}
	}
	
   /**
    * Sets the ItemMaps Temporary ItemStack.
    * 
    */
	public void renderItemStack() {
        if (this.dataValue != null) {
        	this.tempItem = LegacyAPI.newItemStack(this.material, this.count, this.dataValue);
        } else { this.tempItem = new ItemStack(this.material, this.count); }
	}
//  ======================================================================================================================================================================================== //

//  ===================== //
//  ~ Setting Functions ~ //
//  ===================== //
   /**
    * Sets the Temporary ItemStack.
    * 
    * @param temp - The ItemStack to be set.
    */
	public void setTempItem(final ItemStack temp) {
		this.tempItem = temp;
	}
	
   /**
    * Sets the Temporary ItemMeta.
    * 
    * @param temp - The ItemMeta to be set.
    */
	public void setTempMeta(final ItemMeta temp) {
		this.tempMeta = temp;
	}
	
   /**
    * Sets the Material.
    * 
    * @param mat - The Material to be set.
    */
	public void setMaterial(final Material mat) {
		this.material = mat;
	}
	
   /**
    * Sets the Custom Display Name.
    * 
    * @param customName - The Display Name to be set.
    */
	public void setCustomName(final String customName) {
		this.customName = customName;
	}
	
   /**
    * Sets the Dynamic Display Names.
    * 
    * @param names - The Dynamic Display Names to be set.
    */
	public void setDynamicNames(final List<String> names) {
		this.dynamicNames = names;
	}
	
   /**
    * Sets the Custom Display Lore.
    * 
    * @param customLore - The Display Lore to be set.
    */
	public void setCustomLore(final List < String > customLore) {
		this.customLore = new ArrayList < String > ();
		Iterator < String > iterator = customLore.iterator();
		while (iterator.hasNext()) {
			String s = iterator.next();
			this.customLore.add(s);
		}
	}
	
   /**
    * Sets the Dynamic Display Lore.
    * 
    * @param lores - The Dynamic Display Lore to be set.
    */
	public void setDynamicLores(final List<List<String>> lores) {
		this.dynamicLores = lores;
	}
	
   /**
    * Sets the Dynamic Materials.
    * 
    * @param mats - The Dynamic Materials to be set.
    */
	public void setDynamicMaterials(final List<String> mats) {
		this.dynamicMaterials = mats;
		this.materialAnimated = true;
	}
	
   /**
    * Sets the Dynamic Skull Owners.
    * 
    * @param owners - The Dynamic Skull Owners to be set.
    */
	public void setDynamicOwners(final List<String> owners) {
		this.dynamicOwners = owners;
	}
	
   /**
    * Sets the Dynamic Skull Textures.
    * 
    * @param textures - The Dynamic Skull Textures to be set.
    */
	public void setDynamicTextures(final List<String> textures) {
		this.dynamicTextures = textures;
	}
	
   /**
    * Removes the Player from the AnimationHandler.
    * 
    * @param player - The Player to be removed.
    */
	public void removeFromAnimationHandler(final Player player) {
		this.localeAnimations.remove(player);
	}
	
   /**
    * Sets the Limit Modes.
    * 
    * @param str - The Limit Modes to be set.
    */
	public void setLimitModes(final String str) {
		this.limitModes = str;
	}
	
   /**
    * Sets the Slot.
    * 
    * @param slot - The Slot to be set.
    */
	public void setSlot(final String slot) {
		if (ItemHandler.isCustomSlot(slot)) {
			this.CustomSlot = slot;
			this.InvSlot = null;
		} else if (StringUtils.isInt(slot)) {
			this.InvSlot = Integer.parseInt(slot);
			this.CustomSlot = null;
		}
	}
	
   /**
    * Sets the Multiple Slots.
    * 
    * @param slots - The Multiple Slots to be set.
    */
	public void setMultipleSlots(final List<String> slots) {
		this.AllSlots = slots;
	}
	
   /**
    * Sets the Disabled Worlds.
    * 
    * @param worlds - The Disabled Worlds to be set.
    */
	public void setDisabledWorlds(final List<String> worlds) {
		this.disabledWorlds = worlds;
	}
	
   /**
    * Sets the Enabled Worlds.
    * 
    * @param worlds - The Enabled Worlds to be set.
    */
	public void setEnabledWorlds(final List<String> worlds) {
		this.enabledWorlds = worlds;
	}
	
   /**
    * Sets the Enabled Regions.
    * 
    * @param regions - The Enabled Regions to be set.
    */
	public void setEnabledRegions(final List<String> regions) {
		this.enabledRegions = regions;
	}
	
   /**
    * Sets the Stored Contents.
    * 
    * @param contents - The Stored Contents to be set.
    */
	public void setContents(final List<String> contents) {
		this.contents = contents;
	}
	
   /**
    * Sets the Enchantments.
    * 
    * @param enchantments - The Enchantments to be set.
    */
	public void setEnchantments(final Map<String, Integer> enchantments) {
		this.enchants = enchantments;
	}
	
   /**
    * Sets the ItemFlags.
    * 
    * @param itemflags - The ItemFlags to be set.
    */
	public void setItemFlags(final String itemflags) {
		this.itemflags = itemflags;
	}
	
   /**
    * Sets the Triggers.
    * 
    * @param triggers - The Triggers to be set.
    */
	public void setTriggers(final String triggers) {
		this.triggers = triggers;
	}
	
   /**
    * Sets the CommandSequence.
    * 
    * @param sequence - The CommandSequence to be set.
    */
	public void setCommandSequence(final CommandSequence sequence) {
		this.sequence = sequence;
	}
	
   /**
    * Sets the Commands Particle.
    * 
    * @param s - The Commands Particle to be set.
    */
	public void setCommandParticle(final String s) {
		this.commandParticle = s;
	}
	
   /**
    * Sets the Commands Cooldown.
    * 
    * @param i - The Commands Cooldown Seconds.
    */
	public void setCommandCooldown(final int i) {
		this.cooldownSeconds = i;
	}
	
   /**
    * Sets the Commands Cooldown Message.
    * 
    * @param s - The Commands Cooldown Message to be set.
    */
	public void setCooldownMessage(final String s) {
		this.cooldownMessage = s;
	}
	
   /**
    * Sets the Trigger Message.
    * 
    * @param s - The Trigger Message to be set.
    */
	public void setTriggerMessage(final String s) {
		this.triggerMessage = s;
	}
	
   /**
    * Sets the Trigger Conditions.
    * 
    * @param s - The Trigger Conditions to be set.
    */
	public void setTriggerConditions(final List<String> s) {
		this.triggerConditions = s;
	}
	
   /**
    * Sets the Disposable Message.
    * 
    * @param s - The Disposable Message to be set.
    */
	public void setDisposableMessage(final String s) {
		this.disposableMessage = s;
	}
	
   /**
    * Sets the Disposable Conditions.
    * 
    * @param s - The Disposable Conditions to be set.
    */
	public void setDisposableConditions(final List<String> s) {
		this.disposableConditions = s;
	}
	
   /**
    * Sets the Commands Messages.
    * 
    * @param s - The Commands Messages to be set.
    */
	public void setCommandMessages(final Map<String, String> s) {
		this.commandMessages = s;
	}
	
   /**
    * Sets the Commands Conditions.
    * 
    * @param s - The Commands Conditions to be set.
    */
	public void setCommandConditions(final Map<String, List<String>> s) {
		this.commandConditions = s;
	}
	
   /**
    * Sets the stack size.
    * 
    * @param count - The stack size to be set.
    */
	public void setCount(final String count) {
		if (count != null && StringUtils.isInt(count) && Integer.parseInt(count) != 0) {
			this.count = Integer.parseInt(count);
		} else { this.count = 1; }
	}
	
   /**
    * Sets the ItemStack attributes.
    * 
    * @param attributeList - The list of attributes to be set.
    */
	public void setAttributes(final Map < String, Double > attributeList) {
		if (attributeList != null && !attributeList.isEmpty()) {
			this.attributes = attributeList;
		}
	}
	
   /**
    * Sets the ItemStack Durability.
    * 
    * @param durability - The ItemStack Durability to be set.
    */
	public void setDurability(final Short durability) {
		this.durability = durability;
	}
	
   /**
    * Sets the ItemStack Data.
    * 
    * @param data - The ItemStack Data to be set.
    */
	public void setData(final Integer data) {
		this.data = data;
	}
	
   /**
    * Sets the ItemStack Model Data.
    * 
    * @param data - The ItemStack Model Data to be set.
    */
	public void setModelData(final Integer data) {
		this.modelData = data;
	}
	
   /**
    * Sets the MobsDrop.
    * 
    * @param mobsDrop - The mobsDrop to be set.
    */
	public void setMobsDrop(final Map<EntityType, Double> mobsDrop) {
		this.mobsDrop = mobsDrop;
	}
	
   /**
    * Sets the BlocksDrop.
    * 
    * @param blocksDrop - The blocksDrop to be set.
    */
	public void setBlocksDrop(final Map<Material, Double> blocksDrop) {
		this.blocksDrop = blocksDrop;
	}
	
   /**
    * Sets the Probability.
    * 
    * @param probability - The Probability to be set.
    */
	public void setProbability(final Integer probability) {
		this.probability = probability;
	}
	
   /**
    * Sets the Commands Sound.
    * 
    * @param sound - The Commands Sound to be set.
    */
	public void setCommandSound(final Sound sound) {
		this.commandSound = sound;
	}
	
   /**
    * Sets the Commands Sound Volume.
    * 
    * @param sound - The Commands Sound Volume to be set.
    */
	public void setCommandVolume(final Double volume) {
		this.commandSoundVolume = volume;
	}
	
   /**
    * Sets the Commands Sound Pitch.
    * 
    * @param sound - The Commands Sound Pitch to be set.
    */
	public void setCommandPitch(final Double pitch) {
		this.commandSoundPitch = pitch;
	}
	
   /**
    * Sets the Commands Cost.
    * 
    * @param cost - The Commands Cost to be set.
    */
	public void setCommandCost(final Integer cost) {
		this.cost = cost;
	}
	
   /**
    * Sets the Commands Item Cost.
    * 
    * @param itemCost - The Commands Item Cost to be set.
    */
	public void setItemCost(final String itemCost) {
		this.itemCost = itemCost;
	}
	
   /**
    * Sets the Commands Warmup Delay.
    * 
    * @param delay - The Commands Warmup Delay to be set.
    */
	public void setWarmDelay(final Integer delay) {
		this.warmDelay = delay;
	}
	
   /**
    * Adds the Player as Warmup Pending.
    * 
    * @param player - The Player to be set as Warmup pending.
    */
	private void addWarmPending(final Player player) {
        if (!this.warmPending.contains(player)) {
        	this.warmPending.add(player);
        }
	}
	
   /**
    * Removes the Player from pending Warmup.
    * 
    * @param player - The Player to be removed from Warmup pending.
    */
	private void delWarmPending(final Player player) {
        if (this.warmPending.contains(player)) {
        	this.warmPending.remove(player);
        }
	}
	
   /**
    * Sets the Config Name.
    * 
    * @param name - The Config Name to be set.
    */
	public void setConfigName(final String name) {
		this.configName = name;
	}
	
   /**
    * Sets the Banner Patterns.
    * 
    * @param patterns - The Banner Patterns to be set.
    */
	public void setBannerPatterns(final List <Pattern> patterns) {
		this.bannerPatterns = patterns;
	}
	
   /**
    * Sets the recipe ingredients.
    * 
    * @param ingredients - The recipe ingredients to be set.
    */
	public void setIngredients(final Map <Character, String> ingredients) {
		this.ingredients = ingredients;
	}
	
   /**
    * Sets the recipe pattern.
    * 
    * @param recipe - The recipe pattern to be set.
    */
	public void setRecipe(final List <Character> recipe) {
		this.recipe = recipe;
	}
	
   /**
    * Sets the Node Location.
    * 
    * @param node - The Node Location to be set.
    */
	public void setNodeLocation(final ConfigurationSection node) {
		this.nodeLocation = node;
	}
	
   /**
    * Sets the ItemStacks Data Value.
    * 
    * @param dataValue - The ItemStacks Data Value to be set.
    */
	public void setDataValue(final Short dataValue) {
		if (dataValue == null || dataValue == 0) {
			this.dataValue = null;
			return;
		}
		this.dataValue = dataValue;
	}
	
   /**
    * Sets the Permission.
    * 
    * @param permission - The Permission to be set.
    */
	public void setPerm(final String permission) {
		this.permissionNode = permission == null || permission.length() == 0 ? null : permission;
	}
	
   /**
    * Sets the Toggle Permission.
    * 
    * @param permission - The Permission to be set.
    */
	public void setTogglePerm(final String permission) {
		this.toggleNode = permission == null || permission.length() == 0 ? null : permission;
	}
	
   /**
    * Sets the Toggle Message.
    * 
    * @param message - The Message to be set.
    */
	public void setToggleMessage(final String message) {
		this.toggleMessage = message;
	}
	
   /**
    * Sets the ItemStack to be given only on First Join.
    * 
    * @param bool - The value to be set.
    */
	public void setOnlyFirstJoin(final boolean bool) {
		this.onlyFirstJoin = bool;
		if (bool && !this.giveOnRegionEnter && !this.giveOnRegionLeave && !this.giveOnRegionAccess && !this.giveOnRegionEgress) { 
			this.giveOnJoin = true; 
			this.giveOnRespawn = false; 
		}
	}
	
   /**
    * Sets the ItemStack to be given only on First Join but will always be given upon respawn.
    * 
    * @param bool - The value to be set.
    */
	public void setOnlyFirstLife(final boolean bool) {
		this.onlyFirstLife = bool;
		if (bool && !this.giveOnRegionEnter && !this.giveOnRegionLeave && !this.giveOnRegionAccess && !this.giveOnRegionEgress) { 
			this.giveOnJoin = true; 
			this.giveOnRespawn = true;
		}
	}
	
   /**
    * Sets the ItemStack to be given only on First World.
    * 
    * @param bool - The value to be set.
    */
	public void setOnlyFirstWorld(final boolean bool) {
		this.onlyFirstWorld = bool;
		if (bool && !this.giveOnRegionEnter && !this.giveOnRegionLeave && !this.giveOnRegionAccess && !this.giveOnRegionEgress) { 
			this.giveOnJoin = true; 
			this.giveOnWorldSwitch = true; 
			this.giveOnRespawn = false;
		}
	}
	
   /**
    * Sets the ItemStack to be given only on Join.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnJoin(final boolean bool) {
		this.giveOnJoin = bool;
	}
	
   /**
    * Sets the ItemStack to be given only on World Switch.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnWorldSwitch(final boolean bool) {
		this.giveOnWorldSwitch = bool;
	}
	
   /**
    * Sets the ItemStack to be given only on Respawn.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnRespawn(final boolean bool) {
		this.giveOnRespawn = bool;
	}
	
   /**
    * Sets the ItemStack to be given only on Region Enter.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnRegionEnter(final boolean bool) {
		this.giveOnRegionEnter = bool;
	}
	
   /**
    * Sets the ItemStack to be given only on Region Leave.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnRegionLeave(final boolean bool) {
		this.giveOnRegionLeave = bool;
	}
	
   /**
    * Sets the ItemStack to be given only on region enter and removed on region leave.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnRegionAccess(final boolean bool) {
		this.giveOnRegionAccess = bool;
	}
	
   /**
    * Sets the ItemStack to be given only on region leave and removed on region enter.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnRegionEgress(final boolean bool) {
		this.giveOnRegionEgress = bool;
	}
	
   /**
    * Sets the ItemStack to not be given.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveOnDisabled(final boolean bool) {
		this.giveOnDisabled = bool;
	}
	
   /**
    * Sets the Use on Limit Switch.
    * 
    * @param bool - The value to be set.
    */
	public void setUseOnLimitSwitch(final boolean bool) {
		this.useOnLimitSwitch = bool;
	}
	
   /**
    * Sets the IP Limits.
    * 
    * @param bool - The value to be set.
    */
	public void setIpLimited(final boolean bool) {
		this.ipLimited = bool;
	}
	
   /**
    * Sets the Interact cooldown.
    * 
    * @param cooldown - The value to be set.
    */
	public void setInteractCooldown(final int cooldown) {
        this.interactCooldown = cooldown;
	}
	
   /**
    * Sets the Teleport Effect.
    * 
    * @param name - The value to be set.
    */
	public void setTeleportEffect(final String name) {
        this.teleportEffect = name;
	}
	
   /**
    * Sets the Teleport Sound.
    * 
    * @param name - The value to be set.
    */
	public void setTeleportSound(final String name) {
        this.teleportSound = name;
	}
	
   /**
    * Sets the Teleport Volume.
    * 
    * @param volume - The value to be set.
    */
	public void setTeleportVolume(final Double volume) {
        this.teleportSoundVolume = volume;
	}
	
   /**
    * Sets the Teleport Pitch.
    * 
    * @param pitch - The value to be set.
    */
	public void setTeleportPitch(final Double pitch) {
        this.teleportSoundPitch = pitch;
	}
	
   /**
    * Sets the Permissions to be Required.
    * 
    * @param bool - The value to be set.
    */
	public void setPermissionNeeded(final boolean bool) {
		this.permissionNeeded = bool;
	}
	
   /**
    * Sets the OP Permissions to be Required.
    * 
    * @param bool - The value to be set.
    */
	public void setOPPermissionNeeded(final boolean bool) {
		this.opPermissionNeeded = bool;
	}
	
   /**
    * Sets the Vanilla Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setVanilla(final boolean bool) {
		this.vanillaItem = bool;
	}
	
   /**
    * Sets the Vanilla Status Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setVanillaStatus(final boolean bool) {
		this.vanillaStatus = bool;
	}
	
   /**
    * Sets the Vanilla Control Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setVanillaControl(final boolean bool) {
		this.vanillaControl = bool;
	}
	
   /**
    * Sets the Give Next Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setGiveNext(final boolean bool) {
		this.giveNext = bool;
	}
	
   /**
    * Sets the Move Next Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setMoveNext(final boolean bool) {
		this.moveNext = bool;
	}
	
   /**
    * Sets the Drop Full Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setDropFull(final boolean bool) {
		this.dropFull = bool;
	}
	
   /**
    * Sets the Unbreakable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setUnbreakable(final boolean bool) {
		this.unbreakable = bool;
	}
	
   /**
    * Sets the Count Lock Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setCountLock(final boolean bool) {
		this.countLock = bool;
	}
	
   /**
    * Sets the Teleport Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setTeleport(final boolean bool) {
		this.teleportArrow = bool;
	}
	
   /**
    * Sets the Cancel Events Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setCancelEvents(final boolean bool) {
		this.cancelEvents = bool;
	}
	
   /**
    * Sets the Item Store Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setItemStore(final boolean bool) {
		this.itemStore = bool;
	}
	
   /**
    * Sets the Item Modify Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setItemModify(final boolean bool) {
		this.itemModify = bool;
	}
	
   /**
    * Sets the Item Craftable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setItemCraftable(final boolean bool) {
		this.noCrafting = bool;
	}
	
   /**
    * Sets the Item Repairable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setItemRepairable(final boolean bool) {
		this.noRepairing = bool;
	}
	
   /**
    * Sets the Item Changable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setItemChangable(final boolean bool) {
		this.itemChangable = bool;
	}
	
   /**
    * Sets the Always Give Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setAlwaysGive(final boolean bool) {
		this.alwaysGive = bool;
	}
	
   /**
    * Sets the Auto Remove Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setAutoRemove(final boolean bool) {
		this.autoRemove = bool;
	}
	
   /**
    * Sets the Stackable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setStackable(final boolean bool) {
		this.stackable = bool;
	}
	
   /**
    * Sets the Selectable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setSelectable(final boolean bool) {
		this.selectable = bool;
	}
	
   /**
    * Sets the Animate Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setAnimate(final boolean bool) {
		this.animate = bool;
	}
	
   /**
    * Sets the Dynamic Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setDynamic(final boolean bool) {
		this.dynamic = bool;
	}
	
   /**
    * Sets the Glowing Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setGlowing(final boolean bool) {
		this.glowing = bool;
	}
	
   /**
    * Sets the Overwritable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setOverwritable(final boolean bool) {
		this.overwritable = bool;
	}
	
   /**
    * Sets the Placeable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setPlaceable(final boolean bool) {
		this.blockPlacement = bool;
	}
	
   /**
    * Sets the Attributes Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setAttributesInfo(final boolean bool) {
		this.hideAttributes = bool;
	}
	
   /**
    * Sets the Flags.
    * 
    * @param bool - The value to be set.
    */
	public void setFlagsInfo(final boolean bool) {
		this.hideFlags = bool;
	}
	
   /**
    * Sets the Durability Bar Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setDurabilityBar(final boolean bool) {
		this.hideDurability = bool;
	}
	
   /**
    * Sets the Movement Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setMovement(final boolean bool) {
		this.blockMovement = bool;
	}
	
   /**
    * Sets the Equip Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setEquip(final boolean bool) {
		this.blockEquip = bool;
	}
	
   /**
    * Sets the Inventory Close Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setCloseInventory(final boolean bool) {
		this.closeInventory = bool;
	}
	
   /**
    * Sets the Dispoable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setDisposable(final boolean bool) {
		this.disposable = bool;
	}
	
   /**
    * Sets the Self Droppable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setSelfDroppable(final boolean bool) {
		this.selfDroppable = bool;
	}
	
   /**
    * Sets the Death Droppable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setDeathDroppable(final boolean bool) {
		this.deathDroppable = bool;
	}
	
   /**
    * Sets the Death Keepable Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setDeathKeepable(final boolean bool) {
		this.deathKeepable = bool;
	}
	
   /**
    * Sets the CreativeBypass Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setCreativeBypass(final boolean bool) {
		this.CreativeBypass = bool;
	}
	
   /**
    * Sets the OPBypass Flag.
    * 
    * @param bool - The value to be set.
    */
	public void setOpBypass(final boolean bool) {
		this.AllowOpBypass = bool;
	}
	
   /**
    * Sets the Book Author.
    * 
    * @param auth - The Book Author to be set.
    */
	public void setAuthor(final String auth) {
		this.author = auth;
	}
	
   /**
    * Sets the Book Title.
    * 
    * @param title - The Book Title to be set.
    */
	public void setTitle(final String title) {
		this.title = title;
	}
	
   /**
    * Sets the Book Generation.
    * 
    * @param gen - The Book Generation to be set.
    */
	public void setGeneration(final org.bukkit.inventory.meta.BookMeta.Generation gen) {
		this.generation = gen;
	}
	
   /**
    * Sets the Book Pages.
    * 
    * @param pages - The Book Pages to be set.
    */
	public void setPages(final List <String> pages) {
		this.bookPages = pages;
	}
	
   /**
    * Sets the Book List Pages.
    * 
    * @param pages - The Book List Pages to be set.
    */
	public void setListPages(final List <List <String> > pages) {
		this.listPages = pages;
	}
	
   /**
    * Sets the Map ID.
    * 
    * @param id - The Map ID to be set.
    */
	public void setMapID(final int id) {
		this.mapId = (short) id;
	}
	
   /**
    * Sets the MapView.
    * 
    * @param view - The MapView to be set.
    */
	public void setMapView(final MapView view) {
		this.mapView = view;
	}
	
   /**
    * Sets the Map Image.
    * 
    * @param mapIMG - The Map Image to be set.
    */
	public void setMapImage(final String mapIMG) {
		this.customMapImage = mapIMG;
	}
	
   /**
    * Sets the FireworkEffect.
    * 
    * @param fire - The FireworkEffeect to be set.
    */
	public void setFirework(final FireworkEffect fire) {
		this.firework = fire;
	}
	
   /**
    * Sets the Firework Type.
    * 
    * @param buildType - The Firework Type to be set.
    */
	public void setFireworkType(final Type buildType) {
		this.fireworkType = buildType;
	}
	
   /**
    * Sets the Firework Colors.
    * 
    * @param colors - The Firework Colors to be set.
    */
	public void setFireworkColor(final List<DyeColor> colors) {
		this.fireworkColor = colors;
	}
	
   /**
    * Sets the Firework Power.
    * 
    * @param power - The Firework Power to be set.
    */
	public void setFireworkPower(final int power) {
		this.power = power;
	}
	
   /**
    * Sets the Firework Trail.
    * 
    * @param bool - The value to be set.
    */
	public void setFireworkTrail(final boolean bool) {
		this.fireworkTrail = bool;
	}
	
   /**
    * Sets the Firework Flicker.
    * 
    * @param bool - The value to be set.
    */
	public void setFireworkFlicker(final boolean bool) {
		this.fireworkFlicker = bool;
	}
	
   /**
    * Sets the Firework Charge Color.
    * 
    * @param dyeColor - The Firework Charge Color to be set.
    */
	public void setChargeColor(final DyeColor dyeColor) {
		this.chargeColor = dyeColor;
	}
	
   /**
    * Sets the Skull Owner.
    * 
    * @param skull - The Skull Owner to be set.
    */
	public void setSkull(final String skull) {
		this.skullOwner = skull;
	}
	
   /**
    * Sets the Skull Texture.
    * 
    * @param skull - The Skull Texture to be set.
    */
	public void setSkullTexture(final String skull) {
		this.skullTexture = skull;
	}
	
   /**
    * Sets the HeadDatabase Head.
    * 
    * @param head - The value to be set.
    */
	public void setHeadDatabase(final boolean head) {
		this.headDatabase = head;
	}
	
   /**
    * Sets the PotionEffect.
    * 
    * @param pootion - The PortionEffect to be set.
    */
	public void setPotionEffect(final List <PotionEffect> potion) {
		this.effect = potion;
	}
	
   /**
    * Sets the Leather Color.
    * 
    * @param color - The Leather Color to be set.
    */
	public void setLeatherColor(final String color) {
		this.leatherColor = color;
	}
	
   /**
    * Sets the Leather HexColor.
    * 
    * @param hex - The Leather HexColor to be set.
    */
	public void setLeatherHex(final String hex) {
		this.leatherHex = hex;
	}
	
   /**
    * Sets the NBTData.
    * 
    * @param nbt - The NBT Data to be set.
    * @oaram tag - The Object Tag to be set.
    */
	public void setNewNBTData(final String nbt, final Object tag) {
		this.newNBTData = nbt;
		this.newNBTTag = tag;
	}
	
   /**
    * Sets the NBT Properties.
    * 
    * @oaram tags - The Object Tags to be set.
    */
	public void setNBTProperties(final Map<String, String> tagValues, final List<Object> tags) {
		this.nbtProperty = tagValues;
		this.nbtProperties = tags;
	}
	
   /**
    * Sets the NBT Values.
    * 
    * @oaram tags - The Object Tags to be set.
    */
	public void setNBTValues(final Map<String, String> tagValues) {
		this.nbtProperty = tagValues;
	}
	
   /**
    * Sets the Legacy NBTData (Secret).
    * 
    * @param nbt - The NBT Data to be set.
    */
	public void setLegacySecret(final String nbt) {
		this.legacySecret = nbt;
	}
	
   /**
    * Sets the Arbitrary.
    * 
    * @param arb - The Arbitrary to be set.
    */
	public void setArbitrary(final String arb) {
		this.Arbitrary = arb;
	}
	
   /**
    * Sets the Item Value (Arbitrary ID).
    * 
    * @param str - The Item Value to be set.
    */
	public void setItemValue(final String str) {
		this.itemValue = str;
	}
	
   /**
    * Sets the ItemStack as Subject to Removal.
    * 
    * @param bool - The value to be set.
    */
	private void setSubjectRemoval(final boolean bool) {
		this.subjectRemoval = bool;
	}
	
   /**
    * Sets the ItemCommands.
    * 
    * @param commands - The ItemCommands to be set.
    */
    public void setCommands(final ItemCommand[] commands) {
        this.commands = commands;
    }
    
   /**
    * Sets the Toggle Commands.
    * 
    * @param commands - The Toggle Commands to be set.
    */
    private void setToggleCommands(final String toggleSingle) {
    	final List<String> commandList = new ArrayList<String>();
    	if ((toggleSingle != null && this.nodeLocation.getStringList(".toggle") != null && !this.nodeLocation.getStringList(".toggle").isEmpty())
    			|| (toggleSingle == null && this.toggleCommands != null && !this.toggleCommands.isEmpty())) {
    		for (String command : (toggleSingle != null ? this.nodeLocation.getStringList(".toggle") : this.toggleCommands)) {
    			PluginCommand cmd = null;
    			try {
    				Constructor<PluginCommand> pluginCommand = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
    				pluginCommand.setAccessible(true);
    				cmd = (PluginCommand)pluginCommand.newInstance(new Object[]{(command.contains(" ") ? command.split(" ")[0] : command), ItemJoin.getInstance()});
    			} catch (Exception e) {
    				ServerUtils.sendDebugTrace(e);
    			}
	    		cmd.setDescription(this.configName);
            	cmd.setExecutor(new ChatToggleExecutor());
            	cmd.setTabCompleter(new ChatToggleTab());
	    		this.togglePlugins.add(cmd);
	    		commandList.add(command);
    		}
    	} else if (toggleSingle != null && !toggleSingle.isEmpty() && !toggleSingle.equalsIgnoreCase(" ")) {
			PluginCommand cmd = null;
		    try {
		    	Constructor<PluginCommand> pluginCommand = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
		    	pluginCommand.setAccessible(true);
		    	cmd = (PluginCommand)pluginCommand.newInstance(new Object[]{(toggleSingle.contains(" ") ? toggleSingle.split(" ")[0] : toggleSingle), ItemJoin.getInstance()});
		    } catch (Exception e) {
		    	ServerUtils.sendDebugTrace(e);
		    }
    		cmd.setDescription(this.configName);
            cmd.setExecutor(new ChatToggleExecutor());
            cmd.setTabCompleter(new ChatToggleTab());
    		this.togglePlugins.add(cmd);
    		commandList.add(toggleSingle);
    	}
    	ServerUtils.registerCommands(this.togglePlugins);
        this.toggleCommands = commandList;
    }
    
   /**
    * Sets the Toggle Commands.
    * 
    */
	public void setToggleCommands(final List<String> cmds) {
		this.toggleCommands = cmds;
		this.setToggleCommands((String)null);
	}
    
   /**
    * Deletes the Toggle Commands.
    * 
    * @param commands - The Toggle Commands to be deleted.
    */
    public void delToggleCommands() {
    	if (this.togglePlugins != null && !this.togglePlugins.isEmpty()) {
    		ServerUtils.unregisterCommands(this.togglePlugins);
    	}
    }
	
   /**
    * Sets the Custom Consumable.
    * 
    * @param bool - The value to be set.
    */
    public void setCustomConsumable(final boolean bool) {
    	customConsumable = bool;
    }
	
   /**
    * Sets the Commands Receive.
    * 
    * @param val - The Commands Recieve to be set.
    */
	public void setCommandReceive(final Integer val) {
		this.commandsReceive = val;
	}
    
//  ================================================================================================================================================================================= //
	
//  ====================== //
//  ~ Accessor Functions ~ //
//  ====================== //
   /**
    * Gets the Custom Display Name.
    * 
    * @return The Custom Display Name.
    */
	public String getCustomName() {
		return this.customName;
	}
	
   /**
    * Gets the Dynamic Display Names.
    * 
    * @return The Dynamic Display Names.
    */
	public List<String> getDynamicNames() {
		return this.dynamicNames;
	}
	
   /**
    * Gets the Custom Display Lore.
    * 
    * @return The Custom Display Lore.
    */
	public List<String> getCustomLore() {
		return this.customLore;
	}
	
   /**
    * Gets the Dynamic Display Lores.
    * 
    * @return The Dynamic Display Lores.
    */
	public List<List<String>> getDynamicLores() {
		return this.dynamicLores;
	}
	
   /**
    * Gets the Dynamic Materials.
    * 
    * @return The Dynamic Materials.
    */
	public List<String> getDynamicMaterials() {
		return this.dynamicMaterials;
	}
	
   /**
    * Gets the Dynamic Skull Owners.
    * 
    * @return The Dynamic Skull Owners.
    */
	public List<String> getDynamicOwners() {
		return this.dynamicOwners;
	}
	
   /**
    * Gets the Dynamic Skull Textures.
    * 
    * @return The Dynamic Skull Textures.
    */
	public List<String> getDynamicTextures() {
		return this.dynamicTextures;
	}
	
   /**
    * Gets the AnimationHandlers.
    * 
    * @return The AnimationsHandlers.
    */
	public Map<Player, ItemAnimation> getAnimationHandler() {
		return this.localeAnimations;
	}
	
   /**
    * Gets the Slot.
    * 
    * @return The Slot.
    */
	public String getSlot() {
		if (this.CustomSlot != null) { return this.CustomSlot; } 
		else if (this.InvSlot != null) { return this.InvSlot.toString(); }
		return null;
	}
	
   /**
    * Gets the Slot.
    * 
    * @return The Slot.
    */
	public String getUISlot() {
		if (this.CustomSlot != null && !this.CustomSlot.contains("%")) { return this.CustomSlot; } 
		else if (this.CustomSlot != null) { return (0 + ""); }
		else if (this.InvSlot != null) { return this.InvSlot.toString(); }
		return null;
	}
	
   /**
    * Gets the Multiple Slots.
    * 
    * @return The Multiple Slots.
    */
	public List<String> getMultipleSlots() {
		return this.AllSlots;
	}
	
   /**
    * Gets the Disabled Worlds.
    * 
    * @return The Disabled Worlds.
    */
	public List<String> getDisabledWorlds() {
		return this.disabledWorlds;
	}
	
   /**
    * Gets the Enabled Worlds.
    * 
    * @return The Enabled Worlds.
    */
	public List<String> getEnabledWorlds() {
		return this.enabledWorlds;
	}
	
   /**
    * Gets the Enabled Regions.
    * 
    * @return The Enabled Regions.
    */
	public List<String> getEnabledRegions() {
		return this.enabledRegions;
	}
	
   /**
    * Gets the Stored Contents.
    * 
    * @return The Stored Contents.
    */
	public List<String> getContents() {
		return this.contents;
	}
	
   /**
    * Gets the Enchantments.
    * 
    * @return The Enchantments.
    */
	public Map<String, Integer> getEnchantments() {
		return this.enchants;
	}
	
   /**
    * Gets the stack size.
    * 
    * @return The stack size.
    */
	public Integer getCount() {
		return this.count;
	}
	
   /**
    * Gets the attribute list.
    * 
    * @return The attribute list.
    */
	public Map < String, Double > getAttributes() {
		return this.attributes;
	}
	
   /**
    * Gets the ItemFlags.
    * 
    * @return The ItemFlags.
    */
	public String getItemFlags() {
		return this.itemflags;
	}
	
   /**
    * Gets the Triggers.
    * 
    * @return The Triggers.
    */
	public String getTriggers() {
		return this.triggers;
	}
	
   /**
    * Gets the Permission.
    * 
    * @return The Permission.
    */
	public String getPermissionNode() {
		return permissionNode;
	}
	
   /**
    * Gets the Toggle Permission.
    * 
    * @return The Permission.
    */
	public String getToggleNode() {
		return toggleNode;
	}
	
   /**
    * Gets the Toggle Message.
    * 
    * @return The Toggle Message.
    */
	public String getToggleMessage() {
		return toggleMessage;
	}
	
   /**
    * Gets the ItemStacks Data Value.
    * 
    * @return The ItemStacks Data Value.
    */
	public Short getDataValue() {
		return this.dataValue;
	}
	
   /**
    * Gets the Material.
    * 
    * @return The Material.
    */
	public Material getMaterial() {
		return this.material;
	}
	
   /**
    * Gets the ItemStacks Durability.
    * 
    * @return The ItemStacks Durability.
    */
	public Short getDurability() {
		if (this.durability != null) {
			return this.durability;	
		}
		return 0;
	}
	
   /**
    * Gets the ItemStack Data.
    * 
    * @return The ItemStack Data.
    */
	public Integer getData() {
		if (this.data != null) {
			return this.data;	
		}
		return 0;
	}
	
   /**
    * Gets the ItemStack Model Data.
    * 
    * @return The ItemStack Model Data.
    */
	public Integer getModelData() {
		if (this.modelData != null) {
			return this.modelData;	
		}
		return 0;
	}
	
   /**
    * Gets the current mobsDrops.
    * 
    * @return The mobsDrop Map.
    */
	public Map<EntityType, Double> getMobsDrop() {
		return this.mobsDrop;
	}
	
   /**
    * Checks if mobs drop are enabled.
    * 
    * @return If mobs drop are enabled.
    */
	public boolean mobsDrop() {
		return (this.mobsDrop != null && !this.mobsDrop.isEmpty());
	}
	
   /**
    * Gets the current blocksDrop.
    * 
    * @return The blocksDrop Map.
    */
	public Map<Material, Double> getBlocksDrop() {
		return this.blocksDrop;
	}
	
   /**
    * Checks if blocks drop are enabled.
    * 
    * @return If blocks drop are enabled.
    */
	public boolean blocksDrop() {
		return (this.blocksDrop != null && !this.blocksDrop.isEmpty());
	}
	
   /**
    * Gets the Probability.
    * 
    * @return The Probability.
    */
	public Integer getProbability() {
		if (this.probability != null) {
			return this.probability;	
		}
		return 0;
	}
	
   /**
    * Gets the Commands Sound.
    * 
    * @return The Commands Sound.
    */
	public Sound getCommandSound() {
		return this.commandSound;	
	}
	
   /**
    * Gets the Commands Sound Volume.
    * 
    * @return The Commands Sound Volume.
    */
	public Double getCommandVolume() {
		return this.commandSoundVolume;	
	}
	
   /**
    * Gets the Commands Sound Pitch.
    * 
    * @return The Commands Sound Pitch.
    */
	public Double getCommandPitch() {
		return this.commandSoundPitch;	
	}
	
   /**
    * Gets the Commands Warmup Delay.
    * 
    * @return The Commands Warmup Delay.
    */
	public Integer getWarmDelay() {
		return this.warmDelay;
	}
	
   /**
    * Checks if the Player is Pending Warmup.
    * 
    * @param player - The Player to be checked.
    */
	private boolean getWarmPending(final Player player) {
        if (this.warmPending.contains(player)) { return true; }
        return false;
	}
	
   /**
    * Gets the ItemStack.
    * 
    * @param player - The Player to have their ItemStack generated.
    * @return The Player Specific ItemStack.
    */
	public ItemStack getItemStack(final Player player) {
		this.updateItem(player);
		return this.tempItem.clone();
	}
	
   /**
    * Gets the Temporary ItemStack.
    * 
    * @return The Temporary ItemStack.
    */
	public ItemStack getTempItem() {
		return this.tempItem;	
	}
	
   /**
    * Gets the Temporary ItemMeta.
    * 
    * @return The Temporary ItemMeta.
    */
	public ItemMeta getTempMeta() {
		return this.tempMeta;	
	}
	
   /**
    * Gets the Config Name.
    * 
    * @return The Config Name.
    */
	public String getConfigName() {
		return this.configName;	
	}
	
   /**
    * Gets the Banner Patterns.
    * 
    * @return The Banner Patterns.
    */
	public List <Pattern> getBannerPatterns() {
		return this.bannerPatterns;
	}
	
   /**
    * Gets the recipe ingredients.
    * 
    * @return The recipe ingredients.
    */
	public Map<Character, String> getIngredients() {
		return this.ingredients;
	}
	
   /**
    * Gets the recipe pattern.
    * 
    * @return The recipe pattern.
    */
	public List<Character> getRecipe() {
		return this.recipe;
	}
	
   /**
    * Gets the Node Location.
    * 
    * @return The Node Location.
    */
	public ConfigurationSection getNodeLocation() {
		return this.nodeLocation;	
	}
	
   /**
    * Gets the Limit Modes.
    * 
    * @return The Limit Modes.
    */
	public String getLimitModes() {
		if (this.limitModes != null) {
			return this.limitModes;
		}
		return "NONE";
	}
	
   /**
    * Gets the ItemCommands.
    * 
    * @return The ItemCommands.
    */
	public ItemCommand[] getCommands() {
		return this.commands;
	}
	
   /**
    * Gets the Toggle Commands.
    * 
    * @return The Toggle Commands.
    */
	public List<String> getToggleCommands() {
		return this.toggleCommands;
	}
	
   /**
    * Gets the Commands Cooldown.
    * 
    * @return The Commands Cooldown.
    */
	public Integer getCommandCooldown() {
		return this.cooldownSeconds;
	}
	
   /**
    * Gets the Commands Cost.
    * 
    * @return The Commands Cost.
    */
	public Integer getCommandCost() {
		return this.cost;
	}
	
   /**
    * Gets the Commands Receive.
    * 
    * @return The Commands Receive.
    */
	public Integer getCommandReceive() {
		return this.commandsReceive;
	}
	
   /**
    * Gets the Commands Item Cost.
    * 
    * @return The Commands Item Cost.
    */
	public String getItemCost() {
		return this.itemCost;
	}
	
   /**
    * Gets the Commands Particle.
    * 
    * @return The Commands Particle.
    */
	public String getCommandParticle() {
		return this.commandParticle;
	}
	
   /**
    * Gets the Commands Sequence.
    * 
    * @return The Commands Sequence.
    */
	public CommandSequence getCommandSequence() {
		return this.sequence;
	}
	
   /**
    * Gets the Book Author.
    * 
    * @return The Book Author.
    */
	public String getAuthor() {
		return this.author;
	}
	
   /**
    * Gets the Book Title.
    * 
    * @return The Book Title.
    */
	public String getTitle() {
		return this.title;
	}
	
   /**
    * Gets the Book Generation.
    * 
    * @return The Book Generation.
    */
	public org.bukkit.inventory.meta.BookMeta.Generation getGeneration() {
		return (Generation) this.generation;
	}
	
   /**
    * Gets the Book Pages.
    * 
    * @return The Book Pages.
    */
	public List <String> getPages() {
		return this.bookPages;
	}
	
   /**
    * Gets the Book List Pages.
    * 
    * @return The Book List Pages.
    */
	public List <List <String> > getListPages() {
		return this.listPages;
	}
	
   /**
    * Gets the Map ID.
    * 
    * @return The Map ID.
    */
	public int getMapID() {
		return this.mapId;
	}
	
   /**
    * Gets the MapView.
    * 
    * @return The MapView.
    */
	public MapView getMapView() {
		return this.mapView;
	}
	
   /**
    * Gets the Map Image.
    * 
    * @return The Map Image.
    */
	public String getMapImage() {
		return this.customMapImage;
	}
	
   /**
    * Gets the FireworkEffect.
    * 
    * @return The FireworkEffect.
    */
	public FireworkEffect getFirework() {
		return this.firework;
	}
	
   /**
    * Gets the Firework Type.
    * 
    * @return The Firework Type.
    */
	public Type getFireworkType() {
		return this.fireworkType;
	}
	
   /**
    * Gets the Firework Power.
    * 
    * @return The Firework Power.
    */
	public int getFireworkPower() {
		return this.power;
	}
	
   /**
    * Gets the Firework Colors.
    * 
    * @return The Firework Colors.
    */
	public List<DyeColor> getFireworkColor() {
		return this.fireworkColor;
	}
	
   /**
    * Gets the Firework Trail.
    * 
    * @return The Firework Trail.
    */
	public boolean getFireworkTrail() {
		return this.fireworkTrail;
	}
	
   /**
    * Gets the Firework Flicker.
    * 
    * @return The Firework Flicker.
    */
	public boolean getFireworkFlicker() {
		return this.fireworkFlicker;
	}
	
   /**
    * Gets the Firework Charge Color.
    * 
    * @return The Firework Charge Color.
    */
	public DyeColor getChargeColor() {
		return this.chargeColor;
	}
	
   /**
    * Gets the Skull Owner.
    * 
    * @return The Skull Owner.
    */
	public String getSkull() {
		return this.skullOwner;
	}
	
   /**
    * Gets the Skull Texture.
    * 
    * @return The Skull Texture.
    */
	public String getSkullTexture() {
		return this.skullTexture;
	}
	
   /**
    * Gets the PotionEffects.
    * 
    * @return The PotionEffects.
    */
	public List <PotionEffect> getPotionEffect() {
		return this.effect;
	}
	
   /**
    * Gets the Leather Color.
    * 
    * @return The Leather Color.
    */
	public String getLeatherColor() {
		return this.leatherColor;
	}
	
   /**
    * Gets the Leather HexColor.
    * 
    * @return The Leather HexColor.
    */
	public String getLeatherHex() {
		return this.leatherHex;
	}
	
   /**
    * Gets the NBTData.
    * 
    * @return The NBTData.
    */
	public String getNewNBTData() {
		return this.newNBTData;
	}
	
   /**
    * Gets the NBT Properties.
    * 
    * @return The NBT Properties.
    */
	public List<Object> getNBTProperties() {
		return this.nbtProperties;
	}
	
   /**
    * Gets the NBT Values.
    * 
    * @return The NBT Values.
    */
	public Map<String, String> getNBTValues() {
		return this.nbtProperty;
	}
	
   /**
    * Gets the NBTData (Secret).
    * 
    * @return The NBTData (Secret).
    */
	public String getLegacySecret() {
		if (!ItemHandler.dataTagsEnabled()) {
			return this.legacySecret;
		} else { return null; }
	}
	
   /**
    * Gets the Arbitrary.
    * 
    * @return The Arbitrary.
    */
	public String getArbitrary() {
		return this.Arbitrary;
	}
	
   /**
    * Gets the Item Value (Arbitrary ID).
    * 
    * @return The Item Value (Arbitrary ID).
    */
	public String getItemValue() {
		return this.itemValue;
	}
	
   /**
    * Gets the Interact Cooldown.
    * 
    * @return The Interact Cooldown.
    */
	public int getInteractCooldown() {
		return this.interactCooldown;
	}
	
   /**
    * Gets the Teleport Effect.
    * 
    * @return The Teleport Effect.
    */
	public String getTeleportEffect() {
		return this.teleportEffect;
	}
	
   /**
    * Gets the Teleport Sound.
    * 
    * @return The Teleport Sound.
    */
	public String getTeleportSound() {
		return this.teleportSound;
	}
	
   /**
    * Gets the Teleport Volume.
    * 
    * @return The Teleport Volume.
    */
	public Double getTeleportVolume() {
		return this.teleportSoundVolume;
	}
	
   /**
    * Gets the Teleport Pitch.
    * 
    * @return The Teleport Pitch.
    */
	public Double getTeleportPitch() {
		return this.teleportSoundPitch;
	}
	
   /**
    * Gets the Commands Cooldown Message.
    * 
    * @return The Commands Cooldown Message.
    */
	public String getCooldownMessage() {
		return this.cooldownMessage;
	}
	
   /**
    * Gets the Trigger Message.
    * 
    * @return The Trigger Message.
    */
	public String getTriggerMessage() {
		return this.triggerMessage;
	}
	
   /**
    * Gets the Trigger Conditions.
    * 
    * @return The Trigger Conditions.
    */
	public List<String> getTriggerConditions() {
		return this.triggerConditions;
	}
	
   /**
    * Gets the Disposable Message.
    * 
    * @return The Disposable Message.
    */
	public String getDisposableMessage() {
		return this.disposableMessage;
	}
	
   /**
    * Gets the Disposable Conditions.
    * 
    * @return The Disposable Conditions.
    */
	public List<String> getDisposableConditions() {
		return this.disposableConditions;
	}
	
   /**
    * Gets the Commands Message.
    * 
    * @return The Commands Message.
    */
	public Map<String, String> getCommandMessages() {
		return this.commandMessages;
	}
	
   /**
    * Gets the Commands Conditions.
    * 
    * @return The Commands Conditions.
    */
	public Map<String, List<String>> getCommandConditions() {
		return this.commandConditions;
	}
	
   /**
    * Gets the NBTData that should be set to be set to the custom item.
    * 
    * @param itemMap - The ItemMap to have its NBTData defined.
    * @return The NBTData format to be set to an item.
    */
	public String getNBTFormat() {
		return this.getItemValue() + this.getConfigName();
	}
	
   /**
    * Gets the Custom Consumable.
    * 
    * @return The Custom Consumable.
    */
	public boolean isCustomConsumable() {
		return this.customConsumable;
	}
	
   /**
    * Checks if the Player has Permission.
    * 
    * @param player - The Player that should have Permission.
    * @param world - The world to check permission.
    * @return If the Player has Permission.
    */
	public boolean hasPermission(final Player player, final World world) {
		String customPerm = PermissionsHandler.customPermissions(this.permissionNode, this.configName, world.getName());
		if (!this.isPermissionNeeded() && !player.isOp() || (!this.isOPPermissionNeeded() && player.isOp())) {
			return true;
		} else if (this.isOPPermissionNeeded() && player.isOp()) {
			if ((player.isPermissionSet(customPerm) && player.hasPermission(customPerm) && (!player.isPermissionSet("itemjoin." + world.getName() + ".*") 
			|| (player.isPermissionSet("itemjoin." + world.getName() + ".*") && player.hasPermission("itemjoin." + world.getName() + ".*"))) 
			|| ((player.isPermissionSet("itemjoin." + world.getName() + ".*") && player.hasPermission("itemjoin." + world.getName() + ".*")) || (player.isPermissionSet(customPerm) && player.hasPermission(customPerm))))) {
				return true;
			}
		} else if (((player.isPermissionSet("itemjoin." + world.getName() + ".*") && player.hasPermission("itemjoin." + world.getName() + ".*")) || (player.isPermissionSet(customPerm) && player.hasPermission(customPerm)))) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the item is a Crafting Item.
    * 
    * @return If it is enabled.
    */
	public boolean isCraftingItem() {
		return this.craftingItem;
	}
	
   /**
    * Checks if the item is a HeadDatabase Item.
    * 
    * @return If it is enabled.
    */
	public boolean isHeadDatabase() {
		return this.headDatabase;
	}
	
   /**
    * Checks if give on join is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnJoin() {
		return this.giveOnJoin;
	}
	
   /**
    * Checks if give on world switch is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnWorldSwitch() {
		return this.giveOnWorldSwitch;
	}
	
   /**
    * Checks if give on respawn is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnRespawn() {
		return this.giveOnRespawn;
	}
	
   /**
    * Checks if give on region enter is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnRegionEnter() {
		return this.giveOnRegionEnter;
	}
	
   /**
    * Checks if give on region leave is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnRegionLeave() {
		return this.giveOnRegionLeave;
	}
	
   /**
    * Checks if give on region enter and remove on region leave is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnRegionAccess() {
		return this.giveOnRegionAccess;
	}
	
   /**
    * Checks if give on region leave and remove on region enter is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveOnRegionEgress() {
		return this.giveOnRegionEgress;
	}
	
   /**
    * Checks if item giving is disabled.
    * 
    * @return If it is disabled.
    */
	public boolean isGiveOnDisabled() {
		return this.giveOnDisabled;
	}
	
   /**
    * Checks if give on first join is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isOnlyFirstJoin() {
		return this.onlyFirstJoin;
	}
	
   /**
    * Checks if give on first life is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isOnlyFirstLife() {
		return this.onlyFirstLife;
	}
	
   /**
    * Checks if give on first world is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isOnlyFirstWorld() {
		return this.onlyFirstWorld;
	}
	
   /**
    * Checks if ip limit is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isIpLimted() {
		return this.ipLimited;
	}
	
   /**
    * Checks if use on limit switch is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isUseOnLimitSwitch() {
		return this.useOnLimitSwitch;
	}
	
   /**
    * Checks if the GameMode is a limit mode.
    * 
    * @return If the GameMode is a limit mode.
    */
	public boolean isLimitMode(final GameMode newMode) {
		if (this.limitModes != null) {
			if (StringUtils.containsIgnoreCase(this.limitModes, newMode.name())) {
				return true;
			} else if (!StringUtils.containsIgnoreCase(this.limitModes, newMode.name())) {
				return false;
			}
		}
		return true;
	}
	
   /**
    * Checks if the region is an enabled region.
    * 
    * @return If the region is a enabled region.
    */
	public Boolean inRegion(final String region) {
		if (this.enabledRegions == null) { return false; }
			for (String compareRegion: this.enabledRegions) {
				if (compareRegion.equalsIgnoreCase(region) || compareRegion.equalsIgnoreCase("UNDEFINED")) {
					return true;
				}
			}
		return false;
	}
	
   /**
    * Checks if Permissions are Required.
    * 
    * @return If Permissions are Required.
    */
	public boolean isPermissionNeeded() {
		return this.permissionNeeded;
	}
	
   /**
    * Checks if OP Permissions are Required.
    * 
    * @return If OP Permissions are Required.
    */
	public boolean isOPPermissionNeeded() {
		return this.opPermissionNeeded;
	}
	
   /**
    * Checks if the Vanilla Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isVanilla() {
		return this.vanillaItem;
	}
	
   /**
    * Checks if the Vanilla Status Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isVanillaStatus() {
		return this.vanillaStatus;
	}
	
   /**
    * Checks if the Vanilla Control Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isVanillaControl() {
		return this.vanillaControl;
	}
	
   /**
    * Checks if the Give Next Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGiveNext() {
		return this.giveNext;
	}
	
   /**
    * Checks if the Move Next Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isMoveNext() {
		return this.moveNext;
	}
	
   /**
    * Checks if the Drop Full Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isDropFull() {
		return this.dropFull;
	}
	
   /**
    * Checks if the Unbreakable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isUnbreakable() {
		return this.unbreakable;
	}
	
   /**
    * Checks if the Count Lock Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isCountLock() {
		return this.countLock;
	}
	
   /**
    * Checks if the Teleport Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isTeleport() {
		return this.teleportArrow;
	}
	
   /**
    * Checks if the Cancel Events Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isCancelEvents() {
		return this.cancelEvents;
	}
	
   /**
    * Checks if the Item Store Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isItemStore() {
		return this.itemStore;
	}
	
   /**
    * Checks if the Item Modify Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isItemModify() {
		return this.itemModify;
	}
	
   /**
    * Checks if the Item Craftable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isItemCraftable() {
		return this.noCrafting;
	}
	
   /**
    * Checks if the Item Repairable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isItemRepairable() {
		return this.noRepairing;
	}
	
   /**
    * Checks if the Item Changable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isItemChangable() {
		return this.itemChangable;
	}
	
   /**
    * Checks if the Always Give Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isAlwaysGive() {
		return this.alwaysGive;
	}
	
   /**
    * Checks if the Auto Remove Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isAutoRemove() {
		return this.autoRemove;
	}
	
   /**
    * Checks if the Stackable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isStackable() {
		return this.stackable;
	}
	
   /**
    * Checks if the Selectable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isSelectable() {
		return this.selectable;
	}
	
   /**
    * Checks if the Animate Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isAnimated() {
		return this.animate;
	}
	
   /**
    * Checks if the Dynamic Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isDynamic() {
		return this.dynamic;
	}
	
   /**
    * Checks if the Glowing Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isGlowing() {
		return this.glowing;
	}
	
   /**
    * Checks if the Overwritable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isOverwritable() {
		return this.overwritable;
	}
	
   /**
    * Checks if the Placement Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isPlaceable() {
		return this.blockPlacement;
	}
	
   /**
    * Checks if the Attributes Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isAttributesInfo() {
		return this.hideAttributes;
	}
	
   /**
    * Checks if the Attributes Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isFlagsInfo() {
		return this.hideFlags;
	}
	
   /**
    * Checks if the Durability Bar Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isDurabilityBar() {
		return this.hideDurability;
	}
	
   /**
    * Checks if the Movement Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isMovement() {
		return this.blockMovement;
	}
	
   /**
    * Checks if the Equip Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isEquip() {
		return this.blockEquip;
	}
	
   /**
    * Checks if the Inventory Close Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isInventoryClose() {
		return this.closeInventory;
	}
	
   /**
    * Checks if the Disposable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isDisposable() {
		return this.disposable;
	}
	
   /**
    * Checks if the Self Droppable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isSelfDroppable() {
		return this.selfDroppable;
	}
	
   /**
    * Checks if the Death Droppable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isDeathDroppable() {
		return this.deathDroppable;
	}
	
   /**
    * Checks if the Death Keepable Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isDeathKeepable() {
		return this.deathKeepable;
	}
	
   /**
    * Checks if the CeativeBypass Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isCreativeBypass() {
		return this.CreativeBypass;
	}
	
   /**
    * Checks if the OPBypass Flag is enabled.
    * 
    * @return If it is enabled.
    */
	public boolean isOpBypass() {
		return this.AllowOpBypass;
	}
	
   /**
    * Checks if the ItemStack is subject to removal. 
    * Prevents Duplication.
    * 
    * @return If the ItemStack is pending removal.
    */
	private boolean isSubjectRemoval() {
		return this.subjectRemoval;
	}
	
   /**
    * Checks if the String World Name is an Disabled/Enabled World.
    * 
    * @param world - The name of the World being checked.
    * @param isDisabled - If the worlds being checked are Disabled.
    * @return If the World is an Disabled/Enabled World.
    */
	public boolean containsWorld(final String world, final boolean isDisabled) {
		for (String worldString: (isDisabled ? this.getDisabledWorlds() : this.getEnabledWorlds())) {
			if (worldString.equalsIgnoreCase(world) || worldString.equalsIgnoreCase("ALL") || worldString.equalsIgnoreCase("GLOBAL")) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Checks if the String Region Name is an Enabled Region.
    * 
    * @param region - The name of the Reegion being checked.
    * @return If the Region is an Enabled Region.
    */
	public boolean containsRegion(final String region) {
		for (String enabledRegion: this.getEnabledRegions()) {
			if (enabledRegion.equalsIgnoreCase(region) || enabledRegion.equalsIgnoreCase("UNDEFINED")) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Checks if the ItemFlag should be allowed.
    * 
    * @param player - The Player being Checked.
    * @param item - The ItemStack being checked.
    * @param findFlag - The ItemFlag being found.
    * @return If the ItemFlag is to be prevented.
    */
	public boolean isAllowedItem(final Player player, final ItemStack item, final String findFlag) {
		if (!Menu.isOpen(player) && this.isSimilar(item)) {
			if (this.AllowOpBypass && player.isOp() || this.CreativeBypass && player.getGameMode() == GameMode.CREATIVE 
					|| findFlag.equalsIgnoreCase("inventory-modify") && player.hasPermission("itemjoin.bypass.inventorymodify") 
					&& ItemJoin.getInstance().getConfig().getBoolean("Permissions.Movement-Bypass")) {
				return false;
			} 
			else if (findFlag.equals("cancel-events")) { return cancelEvents; } 
			else if (findFlag.equals("self-drops")) { return selfDroppable; } 
			else if (findFlag.equals("death-drops")) { return deathDroppable; } 
			else if (findFlag.equals("death-keep")) { return deathKeepable; } 
			else if (findFlag.equals("cancel-equip")) { return blockEquip; }
			else if (findFlag.equals("inventory-modify")) { return blockMovement; }
			else if (findFlag.equals("inventory-close")) { return closeInventory; }
			else if (findFlag.equals("item-store")) { return itemStore; } 
			else if (findFlag.equals("stackable")) { return stackable; } 
			else if (findFlag.equals("selectable")) { return selectable; } 
			else if (findFlag.equals("item-modifiable")) { return itemModify; } 
			else if (findFlag.equals("item-craftable")) { return noCrafting; } 
			else if (findFlag.equals("item-repairable")) { return noRepairing; } 
			else if (findFlag.equals("placement")) { return blockPlacement; } 
			else if (findFlag.equals("count-lock")) { return countLock; }
			else if (findFlag.equals("teleport")) { return teleportArrow; }
		}
		return false;
	}
	
   /**
    * Checks if the ItemStack is similar to the defined ItemMap.
    * 
    * @param item - The ItemStack being checked.
    * @return If the ItemStack is similar.
    */
	public boolean isReal(final ItemStack item) {
		if (item != null && item.getType() != Material.AIR
				&& (this.vanillaControl || this.vanillaStatus
				|| (ItemHandler.dataTagsEnabled() && ItemHandler.getNBTData(item) != null && ItemHandler.getNBTData(item).equalsIgnoreCase(this.newNBTData))
				|| (this.legacySecret != null && item.hasItemMeta() && (ServerUtils.hasSpecificUpdate("1_14") || (!ServerUtils.hasSpecificUpdate("1_14") && item.getItemMeta().hasDisplayName())) 
				&& StringUtils.colorDecode(item) != null && StringUtils.colorDecode(item).contains(this.legacySecret)))) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the ItemStack is similar to the defined ItemMap.
    * 
    * @param item - The ItemStack being checked.
    * @return If the ItemStack is similar.
    */
	public boolean isSimilar(final ItemStack item) {
		if ((item != null && item.getType() != Material.AIR && item.getType() == this.material) || (this.materialAnimated && item != null && item.getType() != Material.AIR && this.isMaterial(item))) {
			if (this.vanillaControl || this.vanillaStatus || (ItemHandler.dataTagsEnabled() && ItemHandler.getNBTData(item) != null && ItemHandler.getNBTData(item).equalsIgnoreCase(this.newNBTData))
				|| (this.legacySecret != null && item.hasItemMeta() && (ServerUtils.hasSpecificUpdate("1_14") || (!ServerUtils.hasSpecificUpdate("1_14") && item.getItemMeta().hasDisplayName())) 
				&& StringUtils.colorDecode(item) != null && StringUtils.colorDecode(item).contains(this.legacySecret))) {
				if (isEnchantSimilar(item) || !item.getItemMeta().hasEnchants() && enchants.isEmpty() || this.isItemChangable()) {
					if (this.material.toString().toUpperCase().contains("BOOK") 
							&& (this.isBookMeta(item) 
							&& ((BookMeta) item.getItemMeta()).getPages().equals(((BookMeta) tempItem.getItemMeta()).getPages()) || this.isDynamic())
							|| this.material.toString().toUpperCase().contains("BOOK") && !this.isBookMeta(item) || !this.material.toString().toUpperCase().contains("BOOK") || this.isItemChangable()) {
						if (!this.vanillaControl || this.vanillaControl && this.displayMeta(item)) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}
	
   /**
    * Checks if the Material is a Skull.
    * 
    * @return If the Material is a Skull.
    */
	public boolean isSkull() {
		if (this.material.toString().equalsIgnoreCase("PLAYER_HEAD") || this.material.toString().equalsIgnoreCase("SKULL_ITEM")) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the diplay meta is similar.
    * 
    * @param item - The ItemStack being checked.
    * @return If the display meta is similar.
    */
	private boolean displayMeta(final ItemStack item) {
		if (item.hasItemMeta() && item.getItemMeta().hasDisplayName() && this.tempMeta != null && this.tempMeta.hasDisplayName() && item.getItemMeta().hasLore() && this.tempMeta.hasLore()) {
			if (item.getItemMeta().getDisplayName().equalsIgnoreCase(this.tempMeta.getDisplayName()) && item.getItemMeta().getLore().toString().equalsIgnoreCase(this.tempMeta.getLore().toString())) {
				return true;
			}
		} else if (item.hasItemMeta() && item.getItemMeta().hasDisplayName() && this.tempMeta != null && this.tempMeta.hasDisplayName() && !item.getItemMeta().hasLore() && !this.tempMeta.hasLore()) {
			if (item.getItemMeta().getDisplayName().equalsIgnoreCase(this.tempMeta.getDisplayName())) {
				return true;
			}
		} else if (item.hasItemMeta() && !item.getItemMeta().hasDisplayName() && this.tempMeta != null && !this.tempMeta.hasDisplayName() && item.getItemMeta().hasLore() && this.tempMeta.hasLore()) {
			if (item.getItemMeta().getLore().toString().equalsIgnoreCase(this.tempMeta.getLore().toString())) {
				return true;
			}
		} else if (this.tempMeta == null) { return true; }
		return false;
	}
	
   /**
    * Checks if the ItemStack Enchantments are similar.
    * 
    * @param item - The ItemStack being checked.
    * @return If the ItemStack Enchantments are similar.
    */
	private boolean isEnchantSimilar(final ItemStack item) {
		if (item.getItemMeta().hasEnchants() && ((this.enchants != null && !this.enchants.isEmpty()) || this.glowing)) { 
			ItemStack checkItem = new ItemStack(item.getType());
			for (Entry<String, Integer> enchantments : this.enchants.entrySet()) {
				if (enchantments.getKey() == null && DependAPI.getDepends(false).tokenEnchantEnabled() && TokenEnchantAPI.getInstance().getEnchantment(enchantments.getKey()) != null) {
					TokenEnchantAPI.getInstance().enchant(null, checkItem, enchantments.getKey(), enchantments.getValue(), true, 0, true);
				} else { 
					checkItem.addUnsafeEnchantment(ItemHandler.getEnchantByName(enchantments.getKey()), enchantments.getValue()); }
			}
			return (this.glowing ? true : item.getItemMeta().getEnchants().equals(checkItem.getItemMeta().getEnchants()));
		}
		return false;
	}
	
   /**
    * Checks if the Book Meta is similar.
    * 
    * @param item - The ItemStack being checked.
    * @return If the Book Meta is similar.
    */
	private boolean isBookMeta(final ItemStack item) {
		try {
			return ((BookMeta) item.getItemMeta()).hasPages();
		} catch (Exception e) { return false; }
	}
	
   /**
    * Checks if the stack size is similar.
    * 
    * @param item - The ItemStack being checked.
    * @return If the stack size is similar.
    */
	public boolean isCountSimilar(final ItemStack item) {
		if (item.getAmount() == count || ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-RestrictCount") == false || this.isItemChangable()) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the Material is a Dynamic Material.
    * 
    * @param item - The ItemStack being checked.
    * @return If the Material is a Dynamic Material.
    */
	private boolean isMaterial(final ItemStack item) {
		for (String material : this.dynamicMaterials) {
			material = ItemHandler.cutDelay(material);
			String dataValue = null;
			if (material.contains(":")) { String[] parts = material.split(":"); dataValue = parts[1]; }
			if (item.getType() == ItemHandler.getMaterial(material, dataValue)) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Checks the Players inventory for the ItemMap.
    * 
    * @param player - The Player being checked.
    * @return If the Player already has the ItemMap.
    */
	public boolean hasItem(final Player player, boolean ignoreCount) {
		for (ItemStack inPlayerInventory: player.getInventory().getContents()) {
			if (this.isSimilar(inPlayerInventory) && (ignoreCount || this.isCountSimilar(inPlayerInventory))) {
				return true;
			}
		}
		for (ItemStack equipInventory: player.getEquipment().getArmorContents()) {
			if (this.isSimilar(equipInventory) && (ignoreCount || this.isCountSimilar(equipInventory))) {
				return true;
			}
		}
		if (ServerUtils.hasSpecificUpdate("1_9") 
				&& this.isSimilar(player.getInventory().getItemInOffHand())
				&& (ignoreCount || this.isCountSimilar(player.getInventory().getItemInOffHand()))) {
			return true;
		}
		if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
			for (ItemStack craftInventory: player.getOpenInventory().getTopInventory()) {
				if (this.isSimilar(craftInventory) && (ignoreCount || this.isCountSimilar(craftInventory))) {
					return true;
				}
			}
		}
		return (player.getItemOnCursor() != null && player.getItemOnCursor().getType() != Material.AIR && this.isSimilar(player.getItemOnCursor()) && (ignoreCount || this.isCountSimilar(player.getItemOnCursor())));
	}
	
   /**
    * Gets the ItemStack that is specific to the Player.
    * 
    * @param player - The Player to have their ItemStack generated.
    * @return The Player specific ItemStack.
    */
	public ItemStack getItem(final Player player) {
		return updateItem(player).getTempItem();
	}
//  ================================================================================================================================================================================= //

//  ================================================================ //
//                      ~ Player Item Updater ~                      //
//  Method(s) update the ItemMap item for player specific variables. //
//  ================================================================ //
   /**
    * Updates the ItemStack to be specific to the Player.
    * 
    * @param player - The Player to have their ItemStack generated.
    * @return The Player specific ItemStack.
    */
	public ItemMap updateItem(final Player player) {
		if (this.tempItem != null) {
			this.setSkullDatabase();
			this.setUnbreaking();
			this.setEnchantments(player);
			this.setMapImage();
			this.tempItem = this.setJSONBookPages(player, this.tempItem, this.bookPages);
			this.setNBTData();
			this.tempMeta = this.tempItem.getItemMeta();
		}
		if (tempMeta != null) {
			this.setCustomName(player);
			this.setCustomLore(player);
			this.setSkull(player);
			this.setDurability();
			this.setData();
			this.setModelData();
			this.setPotionEffects();
			this.setBanners();
			this.setFireworks();
			this.setFireChargeColor();
			this.setDye();
			this.setBookInfo(player);
			LegacyAPI.setBookPages(player, this.tempMeta, this.bookPages, this);
			this.setAttributes();
			this.setAttributeFlags();
			this.setFlags();
			this.realGlow();
			this.setContents(player);
			this.tempItem.setItemMeta(this.tempMeta);
			LegacyAPI.setGlowing(this.tempItem, this);
			LegacyAPI.setAttributes(this.tempItem, this);
		}
		return this;
	}
	
   /**
    * Sets the item contents for the storage box.
    * 
    */
	private void setContents(final Player player) {
		if (this.contents != null && !this.contents.isEmpty() && ServerUtils.hasSpecificUpdate("1_11")) {
			ShulkerBox box = (ShulkerBox) ((BlockStateMeta)this.tempMeta).getBlockState();
			box.getInventory().clear();
			for (String node : this.contents) {
				boolean isNull = true;
				for (ItemMap item : ItemUtilities.getUtilities().getItems()) {
					if (item != null && item.getConfigName().equalsIgnoreCase(node)) {
						isNull = false;
						if (StringUtils.isInt(item.getSlot()) && Integer.parseInt(item.getSlot()) <= 26) {
							box.getInventory().setItem(Integer.parseInt(item.getSlot()), item.getItemStack(player));
						} else if (item.getSlot().equalsIgnoreCase("ARBITRARY")) {
							box.getInventory().addItem(item.getItemStack(player));
						} else if (StringUtils.isInt(item.getSlot()) && Integer.parseInt(item.getSlot()) > 26) {
							ServerUtils.logWarn("{ItemMap} The item " + node + " cannot have the slot " + item.getSlot() + " as the slot cannot be higher than 26 to be set as contents for the item " + this.getConfigName() + ", the item will not be set.");
						} else if (!StringUtils.isInt(item.getSlot())) {
							ServerUtils.logWarn("{ItemMap} The item " + node + " cannot have the slot " + item.getSlot() + " as the item " + this.getConfigName() + " does not support it, the item will not be set.");
						}
					}
				}
				if (isNull) { ServerUtils.logWarn("{ItemMap} The item " + node + " does not exist and will not be set as contents for " + this.getConfigName() + "."); }
			}
			((BlockStateMeta)this.tempMeta).setBlockState(box);
			box.update();
		}
	}
	
   /**
    * Sets the item to glow.
    * 
    */
	private void realGlow() {
		if (this.glowing) { 
			if (ServerUtils.hasSpecificUpdate("1_13")) {
				Glow glow = new Glow();
				this.tempMeta.addEnchant(glow, 1, true);
			} else if (!ServerUtils.hasSpecificUpdate("1_13") && ServerUtils.hasSpecificUpdate("1_11")) {
				this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_ENCHANTS);
				this.tempMeta.addEnchant(Enchantment.LURE, 0, true);
			} 
		}
	}
	
   /**
    * Sets the Skull Database Textures.
    * 
    */
	private void setSkullDatabase() {
		if (this.headDatabase && this.skullTexture != null) {
			HeadDatabaseAPI api = new HeadDatabaseAPI();
			ItemStack sk = api.getItemHead(this.skullTexture);
			this.tempItem = (sk != null ? sk : this.tempItem.clone());
		}
	}
	
   /**
    * Sets the ItemStack Enchantments.
    * 
    * @param player - The Player to have their TokenEnchant instance fetched.
    */
	private void setEnchantments(final Player player) {
		if (this.enchants != null && !this.enchants.isEmpty()) {
			for (Entry<String, Integer> enchantments : this.enchants.entrySet()) {
				if (enchantments.getKey() == null && DependAPI.getDepends(false).tokenEnchantEnabled() && TokenEnchantAPI.getInstance().getEnchantment(enchantments.getKey()) != null) {
					TokenEnchantAPI.getInstance().enchant(player, this.tempItem, enchantments.getKey(), enchantments.getValue(), true, 0, true);
				} else { this.tempItem.addUnsafeEnchantment(ItemHandler.getEnchantByName(enchantments.getKey()), enchantments.getValue()); }
			}
		}
	}
	
   /**
    * Sets the ItemStack as Unbreakable.
    * 
    */
	private void setUnbreaking() {
		if (this.isUnbreakable() || this.hideDurability) {
			try {
				Class<?> craftItemStack = ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack");
				Object nms = craftItemStack.getMethod("asNMSCopy", ItemStack.class).invoke(null, this.tempItem);
				Class<?> itemClass = ReflectionUtils.getMinecraftClass("ItemStack");
				Object tag = itemClass.getMethod(MinecraftMethod.getTag.getMethod(itemClass)).invoke(nms);
				if (tag == null) { tag = ReflectionUtils.getMinecraftClass("NBTTagCompound").getConstructor().newInstance(); }
				tag.getClass().getMethod(MinecraftMethod.setInt.getMethod(tag, String.class, int.class), String.class, int.class).invoke(tag, "Unbreakable", 1);
				nms.getClass().getMethod(MinecraftMethod.setTag.getMethod(nms, tag.getClass()), tag.getClass()).invoke(nms, tag);
				this.tempItem = (ItemStack) craftItemStack.getMethod("asCraftMirror", nms.getClass()).invoke(null, nms);
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		}
	}
	
   /**
    * Sets the armor value to the items attributes.
    * 
    */
	private void setAttributes() {
		if (ServerUtils.hasSpecificUpdate("1_13") && this.attributes != null && !this.attributes.isEmpty()) {
			try {
				for (String attrib: this.attributes.keySet()) {
					Attribute attribute = Attribute.valueOf(attrib.toUpperCase());
					double value = this.attributes.get(attrib);
					EquipmentSlot slot = null;
					if (ItemHandler.getDesignatedSlot(this.material).equalsIgnoreCase("noslot")) {
						slot = EquipmentSlot.HAND;
					} else {
						slot = EquipmentSlot.valueOf(ItemHandler.getDesignatedSlot(this.material).toUpperCase());
					}
					AttributeModifier modifier = new AttributeModifier(UUID.nameUUIDFromBytes((this.configName + attrib).getBytes()), attrib.toLowerCase().replace("_", "."), value, AttributeModifier.Operation.ADD_NUMBER, slot);
					if (this.tempMeta.getAttributeModifiers() == null || !this.tempMeta.getAttributeModifiers().containsValue(modifier)) {
						this.tempMeta.addAttributeModifier(attribute, modifier);
					}
				}
			} catch (Exception e) {
				ServerUtils.sendDebugTrace(e);
			}
		}
	}
	
   /**
    * Sets the Map Image to be displayed.
    * 
    */
	private void setMapImage() {
		if (this.customMapImage != null || this.mapId != -1) {
			if (ServerUtils.hasSpecificUpdate("1_13")) {
				MapMeta mapmeta = (MapMeta) this.tempItem.getItemMeta();
				try { mapmeta.setMapView(this.mapView); }
				catch (NoSuchMethodError e) { mapmeta = LegacyAPI.setMapID(mapmeta, this.mapId); }
				this.tempItem.setItemMeta(mapmeta);
			} else {
				LegacyAPI.setDurability(this.tempItem, this.mapId);
			}
		}
	}
	
   /**
    * Sets the JSON Book Pages to the ItemStack.
    * 
    * @param player - The Player being used for placeholders.
    * @param item - The ItemStack to be updated.
    * @param pages - The book pages to be set.
    * @return The updated ItemStack.
    */
	public ItemStack setJSONBookPages(final Player player, final ItemStack item, final List<String> pages) {
		if (item.getType().toString().equalsIgnoreCase("WRITTEN_BOOK") && pages != null && !pages.isEmpty() && pages.size() != 0 && ServerUtils.hasSpecificUpdate("1_8")) {
			List<String> copyPages = new ArrayList<String>();
			for (String page: pages) { copyPages.add(page); }
			copyPages.set(0, ItemHandler.cutDelay(copyPages.get(0)));
			Object localePages = null;
			try { localePages = ReflectionUtils.getMinecraftClass("NBTTagList").getConstructor().newInstance(); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			if (ServerUtils.hasSpecificUpdate("1_15")) { return this.set1_15JSONPages(player, item, localePages, copyPages); } 
			else if (ServerUtils.hasSpecificUpdate("1_14")) { return this.set1_14JSONPages(player, item, localePages, copyPages); }
			else { return this.set1_13JSONPages(player, item, localePages, copyPages); }
		}
		return item;
	}
	
   /**
    * Sets the JSON Book Pages to the ItemStack.
    * @warn Method ONLY USED for Server Version 1.13
    * 
    * @param player - The Player being used for placeholders.
    * @param item - The ItemStack to be updated.
    * @param localePages - The NBTTagList of Pages.
    * @param pages - The book pages to be set.
    * @return The updated ItemStack.
    */
	private ItemStack set1_13JSONPages(final Player player, final ItemStack item, final Object localePages, final List<String> pages) {
		for (String textComponent: pages) {
			try { 
				textComponent = StringUtils.translateLayout(textComponent, player);
				Object TagString = ReflectionUtils.getMinecraftClass("NBTTagString").getConstructor(String.class).newInstance(textComponent);
				Class<?> baseClass = ReflectionUtils.getMinecraftClass("NBTBase");
				localePages.getClass().getMethod(MinecraftMethod.add.getMethod(localePages, baseClass), baseClass).invoke(localePages, TagString);
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); } 
		}
		try { return this.invokePages(item, localePages); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return item;
	}
	
   /**
    * Sets the JSON Book Pages to the ItemStack.
    * @warn Method ONLY USED for Server Version 1.14
    * 
    * @param player - The Player being used for placeholders.
    * @param item - The ItemStack to be updated.
    * @param localePages - The NBTTagList of Pages.
    * @param pages - The book pages to be set.
    * @return The updated ItemStack.
    */
	private ItemStack set1_14JSONPages(final Player player, final ItemStack item, final Object localePages, final List<String> pages) {
		for (int i = pages.size() - 1; i >= 0; i--) {
			String textComponent = pages.get(i);
			try { 
				textComponent = StringUtils.translateLayout(textComponent, player);
				Object TagString = ReflectionUtils.getMinecraftClass("NBTTagString").getConstructor(String.class).newInstance(textComponent);
				Class<?> baseClass = ReflectionUtils.getMinecraftClass("NBTBase");
				localePages.getClass().getMethod(MinecraftMethod.add.getMethod(localePages, int.class, baseClass), int.class, baseClass).invoke(localePages, 0, TagString);
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); } 
		}
		try { return this.invokePages(item, localePages); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return item;
	}
	
   /**
    * Sets the JSON Book Pages to the ItemStack.
    * @warn Method ONLY USED for Server Version 1.15
    * 
    * @param player - The Player being used for placeholders.
    * @param item - The ItemStack to be updated.
    * @param localePages - The NBTTagList of Pages.
    * @param pages - The book pages to be set.
    * @return The updated ItemStack.
    */
	private ItemStack set1_15JSONPages(final Player player, final ItemStack item, final Object localePages, final List<String> pages) {
		for (int i = pages.size() - 1; i >= 0; i--) {
			String textComponent = pages.get(i);
			try { 
				textComponent = StringUtils.translateLayout(textComponent, player);
				Class<?> stringClass = ReflectionUtils.getMinecraftClass("NBTTagString");
				Class<?> baseClass = ReflectionUtils.getMinecraftClass("NBTBase");
				Object TagString = stringClass.getMethod(MinecraftMethod.getPage.getMethod(stringClass), String.class).invoke(null, textComponent);
				localePages.getClass().getMethod(MinecraftMethod.add.getMethod(localePages, int.class, baseClass), int.class, baseClass).invoke(localePages, 0, TagString);
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); } 
		}
		try { return this.invokePages(item, localePages); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return item;
	}
	
   /**
    * Sets the JSON Book Pages to the ItemStack.
    * 
    * @param item - The ItemStack to be updated.
    * @param pages - The book pages to be set.
    * @throws Exception An exception.
    * @return The updated ItemStack.
    */
	private ItemStack invokePages(final ItemStack item, final Object pages) throws Exception {
		Class<?> craftItemStack = ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack");
		Class<?> itemClass = ReflectionUtils.getMinecraftClass("ItemStack");
		Class<?> baseClass = ReflectionUtils.getMinecraftClass("NBTBase");
		Object nms = craftItemStack.getMethod("asNMSCopy", ItemStack.class).invoke(null, item);
		Object tag = itemClass.getMethod(MinecraftMethod.getTag.getMethod(itemClass)).invoke(nms);
		if (tag == null) { tag = ReflectionUtils.getMinecraftClass("NBTTagCompound").getConstructor().newInstance(); }
		tag.getClass().getMethod(MinecraftMethod.set.getMethod(tag, String.class, baseClass), String.class, baseClass).invoke(tag, "pages", pages); 
		nms.getClass().getMethod(MinecraftMethod.setTag.getMethod(nms, tag.getClass()), tag.getClass()).invoke(nms, tag);
		return ((ItemStack)craftItemStack.getMethod("asCraftMirror", nms.getClass()).invoke(null, nms));
	}
	
   /**
    * Sets the NBTData, making the ItemStack plugin specific.
    * 
    */
	private void setNBTData() {
		if (ItemHandler.dataTagsEnabled() && !this.isVanilla() && !this.isVanillaControl() && !this.isVanillaStatus()) {
			try {
				Class<?> itemClass = ReflectionUtils.getMinecraftClass("ItemStack");
				Object nms = ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack").getMethod("asNMSCopy", ItemStack.class).invoke(null, this.tempItem);
				Object cacheTag = itemClass.getMethod(MinecraftMethod.getTag.getMethod(itemClass)).invoke(nms);
				if (cacheTag != null) {
					cacheTag.getClass().getMethod(MinecraftMethod.setString.getMethod(cacheTag, String.class, String.class), String.class, String.class).invoke(cacheTag, "ItemJoin Name", this.getConfigName());
					cacheTag.getClass().getMethod(MinecraftMethod.setString.getMethod(cacheTag, String.class, String.class), String.class, String.class).invoke(cacheTag, "ItemJoin Slot", this.getItemValue());
					if (this.nbtProperty != null && !this.nbtProperty.isEmpty()) {
						for (String tag: this.nbtProperty.keySet()) {
							cacheTag.getClass().getMethod(MinecraftMethod.setString.getMethod(cacheTag, String.class, String.class), String.class, String.class).invoke(cacheTag, tag, this.nbtProperty.get(tag));
						}
					}
				} else { 
					nms.getClass().getMethod(MinecraftMethod.setTag.getMethod(nms, this.newNBTTag.getClass()), this.newNBTTag.getClass()).invoke(nms, this.newNBTTag);
					if (this.nbtProperties != null && !this.nbtProperties.isEmpty()) {
						for (Object tag: this.nbtProperties) {
							nms.getClass().getMethod(MinecraftMethod.setTag.getMethod(nms, tag.getClass()), tag.getClass()).invoke(nms, tag);
						}
					}
				}
				this.tempItem = (ItemStack) ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack").getMethod("asCraftMirror", nms.getClass()).invoke(null, nms);
			} catch (Exception e) {
				ServerUtils.logSevere("{ItemMap} An error has occured when setting NBTData to an item.");
				ServerUtils.sendDebugTrace(e);
			}
		} else if (!ItemHandler.dataTagsEnabled()) {
			this.tempItem = StringUtils.colorEncode(this.tempItem, this.legacySecret);
		}
	}
	
   /**
    * Sets the Custom Display Name.
    * 
    * @param player - The Player to be used for placeholders.
    */
	private void setCustomName(final Player player) {
		if (this.customName != null && !this.customName.equalsIgnoreCase(ItemHandler.getMaterialName(this.tempItem))) {
			if (this.legacySecret != null && !ServerUtils.hasSpecificUpdate("1_14")) {
				final String itemData = this.tempMeta.getDisplayName();
				this.tempMeta.setDisplayName(StringUtils.translateLayout(ItemHandler.cutDelay(this.customName), player) + "§r" + itemData);
			} else {
				this.tempMeta.setDisplayName(StringUtils.translateLayout(ItemHandler.cutDelay(this.customName), player));
			}
		}
	}
	
   /**
    * Sets the Custom Display Lore.
    * 
    * @param player - The Player to be used for placeholders.
    */
	private void setCustomLore(final Player player) {
		if (this.customLore != null && !this.customLore.isEmpty()) {
			List < String > loreList = this.customLore;
			List < String > loreFormatList = new ArrayList < String > ();
			for (int k = 0; k < loreList.size(); k++) {
				String formatLore = ItemHandler.cutDelay(loreList.get(k));
				formatLore = StringUtils.translateLayout(formatLore, player);
				loreFormatList.add(formatLore);
			}
			this.tempMeta.setLore(loreFormatList);
		}
	}
	
   /**
    * Sets the ItemStack Durability.
    * 
    */
	private void setDurability() {
		if (this.durability != null && (this.data == null || this.data == 0)) {
			if (ServerUtils.hasSpecificUpdate("1_13")) {
				((org.bukkit.inventory.meta.Damageable) this.tempMeta).setDamage(this.durability);
			} else {
				LegacyAPI.setDurability(this.tempItem, this.durability);
			}
		}
	}
	
   /**
    * Sets the ItemStack Data.
    * 
    */
	private void setData() {
		if (this.data != null) {
			if (ServerUtils.hasSpecificUpdate("1_13")) {
				((org.bukkit.inventory.meta.Damageable) this.tempMeta).setDamage(this.data);
			} else {
				LegacyAPI.setDurability(this.tempItem, Short.parseShort(this.data + ""));
			}
		}
	}
	
   /**
    * Sets the ItemStack Model Data.
    * 
    */
	private void setModelData() {
		if (this.modelData != null && this.modelData != 0) {
			if (ServerUtils.hasSpecificUpdate("1_14")) {
				this.tempMeta.setCustomModelData(this.modelData);
			} else { ServerUtils.logWarn("{ItemMap} The item " + this.getConfigName() + " is using Custom Model Data which is not supported until Minecraft 1.14+."); }
		}
	}
	
   /**
    * Sets the Skull Owner.
    * 
    * @param player - The Player to be used for placeholders.
    */
	private void setSkull(final Player player) {
		if (this.skullOwner != null) {
			this.tempMeta = ItemHandler.setSkullOwner(this.tempMeta, StringUtils.translateLayout(this.skullOwner, player));
		} else if (this.skullTexture != null && !this.headDatabase) {
			try {
				if (ServerUtils.hasSpecificUpdate("1_8")) {
					GameProfile gameProfile = new GameProfile(UUID.randomUUID(), null);
					gameProfile.getProperties().put("textures", new Property("textures", new String(((this.skullOwner != null && DependAPI.getDepends(false).skinsRestorerEnabled()) ? DependAPI.getDepends(false).getSkinValue(StringUtils.translateLayout(this.skullOwner, player)) : StringUtils.toTextureUUID(player, this.configName, this.skullTexture)))));
					Field declaredField = this.tempMeta.getClass().getDeclaredField("profile");
					declaredField.setAccessible(true);
					declaredField.set(this.tempMeta, gameProfile);
				}
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		}
	}
	
   /**
    * Sets the ItemStack PotionEffects
    * 
    */
	private void setPotionEffects() {
		if (this.effect != null && !this.effect.isEmpty() && !this.customConsumable) {
			for (PotionEffect potion: this.effect) {
				((PotionMeta) this.tempMeta).addCustomEffect(potion, true);
			}
		}
	}
	
   /**
    * Sets the ItemStack Banner Patterns
    * 
    */
	private void setBanners() {
		if (this.bannerPatterns != null && !this.bannerPatterns.isEmpty()) {
			((BannerMeta) this.tempMeta).setPatterns(this.bannerPatterns);
		}
	}
	
   /**
    * Sets the itemStack FireworkMeta.
    * 
    */
	private void setFireworks() {
		if (this.firework != null) {
			((FireworkMeta) this.tempMeta).clearEffects();
			((FireworkMeta) this.tempMeta).addEffect(this.firework);
		}
		
		if (this.power != null && this.power != 0) {
			((FireworkMeta) this.tempMeta).setPower(this.power);
		}
	}
	
   /**
    * Sets the Firework Charge Color.
    * 
    */
	private void setFireChargeColor() {
		if (this.chargeColor != null) {
			((FireworkEffectMeta) this.tempMeta).setEffect(FireworkEffect.builder().withColor(this.chargeColor.getColor()).build());
		}
	}
	
   /**
    * Sets the ItemStack DyeColor.
    * 
    */
	private void setDye() {
		if (this.leatherColor != null) {
			((LeatherArmorMeta) this.tempMeta).setColor(DyeColor.valueOf(this.leatherColor).getFireworkColor());
		} else if (this.leatherHex != null) {
			((LeatherArmorMeta) this.tempMeta).setColor(StringUtils.getColorFromHexColor(this.leatherHex));
		}
	}
	
   /**
    * Sets the ItemStack Book Information.
    * 
    * @param player - The Player to be used for placeholders.
    */
	private void setBookInfo(final Player player) {
		if (this.author != null) {
			this.author = StringUtils.translateLayout(this.author, player);
			((BookMeta) this.tempMeta).setAuthor(this.author);
		}
		
		if (this.title != null) {
			this.title = StringUtils.translateLayout(this.title, player);
			((BookMeta) this.tempMeta).setTitle(this.title);
		}
		
		if (this.generation != null && ServerUtils.hasSpecificUpdate("1_10")) {
			((BookMeta) this.tempMeta).setGeneration((Generation) this.generation);
		}
	}
	
   /**
    * Sets the Attributes to the Temporary ItemMeta.
    * 
    */
	private void setAttributeFlags() {
		if (ServerUtils.hasSpecificUpdate("1_8") && this.hideAttributes) {
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_ATTRIBUTES);
		}
	}
	
   /**
    * Sets the Flags to the Temporary ItemMeta.
    * 
    */
	private void setFlags() {
		if (ServerUtils.hasSpecificUpdate("1_8") && this.hideFlags) {
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_ATTRIBUTES);
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_DESTROYS);
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_ENCHANTS);
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_PLACED_ON);
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_POTION_EFFECTS);
			this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_UNBREAKABLE);
			if (ServerUtils.hasSpecificUpdate("1_17")) {
				this.tempMeta.addItemFlags(org.bukkit.inventory.ItemFlag.HIDE_DYE);
			}
		}
	}
//  =========================================================================================================================================================== //	
	
   /**
    * Checks if the World is an Enabled World.
    * 
    * @param world - The world to be checked.
    * @return If the World is an Enabled World.
    */
	public boolean inWorld(final World world) {
		if (this.enabledWorlds == null && this.disabledWorlds == null) { return true; }
			for (String enabledWorld : this.enabledWorlds) {
				if (enabledWorld.equalsIgnoreCase(world.getName()) 
						|| enabledWorld.equalsIgnoreCase("ALL") 
						|| enabledWorld.equalsIgnoreCase("GLOBAL")
						|| (enabledWorld.contains("*") && world.getName().toUpperCase().startsWith(enabledWorld.split("\\*")[0].toUpperCase()))) {
					return !this.isDisabled(world);
				}
			}
		return false;
	}
	
   /**
    * Checks if the World is an Disabled World.
    * 
    * @param world - The world to be checked.
    * @return If the World is an Disabled World.
    */
	public boolean isDisabled(final World world) {
		boolean isDisabled = false;
		for (String disabledWorld : this.disabledWorlds) {
			if (disabledWorld.equalsIgnoreCase(world.getName()) 
					|| disabledWorld.equalsIgnoreCase("ALL") 
					|| disabledWorld.equalsIgnoreCase("GLOBAL") ||
					(disabledWorld.contains("*") && world.getName().toUpperCase().startsWith(disabledWorld.split("\\*")[0].toUpperCase()))) {
				isDisabled = true;
			}
		}
		return isDisabled;
	}
	
   /**
    * Gets the condition message for the ItemMap.
    * 
    * @param conditions - The condition list to be fetched.
    * @return The fetched condition message.
    */
	private List < String > getConditions(final String conditions) {
		if (conditions.equalsIgnoreCase("disposable-conditions")) {
			return this.disposableConditions;
		} else if (conditions.equalsIgnoreCase("trigger-conditions")) {
			return this.triggerConditions;
		} else {
			return this.commandConditions.get(conditions.replace("-conditions", ""));
		}
	}
	
   /**
    * Gets the condition message for the ItemMap.
    * 
    * @param conditions - The condition list to be fetched.
    * @return The fetched condition message.
    */
	private String getConditionMessage(final String conditions) {
		if (conditions.replace("conditions", "fail-message").equalsIgnoreCase("disposable-fail-message")) {
			return this.disposableMessage;
		} else if (conditions.replace("conditions", "fail-message").equalsIgnoreCase("trigger-fail-message")) {
			return this.triggerMessage;
		} else {
			return this.commandMessages.get(conditions.replace("-conditions", ""));
		}
	}
	
   /**
    * Checks if the condition is met for the ItemMap.
    * 
    * @param player - The Player being referenced.
    * @param conditions - The condition list to be fetched.
    * @return If the condition was successfully met.
    */
	public boolean conditionMet(final Player player, final String conditions) {
		if (this.getConditions(conditions) != null && !this.getConditions(conditions).isEmpty()) {
			for (String condition : this.getConditions(conditions)) {
				String[] parts = (condition != null ? condition.split(":") : null);
				if (parts != null && parts.length == 3) {
					String value1 = (parts[0] != null && !StringUtils.isInt(parts[0]) ? StringUtils.translateLayout(parts[0], player) : parts[0]);
					String operand = parts[1];
					String value2 = (parts[2] != null && !StringUtils.isInt(parts[2]) ? StringUtils.translateLayout(parts[2], player) : parts[2]);
					final boolean conditionMet = StringUtils.conditionMet(value1, operand, value2);
					if (!conditionMet && this.getConditionMessage(conditions) != null && !this.getConditionMessage(conditions).isEmpty()) {
						player.sendMessage(StringUtils.translateLayout(this.getConditionMessage(conditions), player));
						ServerUtils.logDebug("{ItemMap} " + player.getName() + " has not met any of the " + conditions + "(s), for the Item: " + this.getConfigName() + "."); 
					}
					return conditionMet;
				} else if (!(parts != null && parts.length == 3)) {
					ServerUtils.logSevere("{ItemMap} The item " + this.getConfigName() + " has a " + conditions + " defined incorrectly!");
					ServerUtils.logWarn("{ItemMap} The condition " + condition + " is not the proper format CONDITION:OPERAND:VALUE, the item may not function properly.");
				}
			}
		} else { return true; }
		return false;
	}
	
   /**
    * Removes the ItemMap from the Player.
    * 
    * @param player - The Player to have the item removed.
    * @param amount - The stack size of the item.
    */
	public void removeFrom(final Player player, int...amount) {
		if (amount.length == 0) { amount = new int[]{0}; } 
		PlayerInventory inv = player.getInventory();
		Inventory craftView = player.getOpenInventory().getTopInventory();
		ItemStack[] contents = inv.getContents();
		ItemStack[] craftingContents = player.getOpenInventory().getTopInventory().getContents();
		this.updateItem(player);
		if (amount[0] == 0) {
			if (this.isAnimated() && this.getAnimationHandler().get(player) != null
					|| this.isDynamic() && this.getAnimationHandler().get(player) != null) {
				this.localeAnimations.get(player).closeAnimation(player);
				this.localeAnimations.remove(player);
			}
			
			for (int k = 0; k < contents.length; k++) {
				if (this.isSimilar(contents[k])) { inv.setItem(k, new ItemStack(Material.AIR)); }
			}
			if (this.isSimilar(inv.getHelmet())) { inv.setHelmet(new ItemStack(Material.AIR)); }
			if (this.isSimilar(inv.getChestplate())) { inv.setChestplate(new ItemStack(Material.AIR)); }
			if (this.isSimilar(inv.getLeggings())) { inv.setLeggings(new ItemStack(Material.AIR)); }
			if (this.isSimilar(inv.getBoots())) { inv.setBoots(new ItemStack(Material.AIR)); }
			if (ServerUtils.hasSpecificUpdate("1_9") && this.isSimilar(PlayerHandler.getOffHandItem(player))) { PlayerHandler.setOffHandItem(player, new ItemStack(Material.AIR)); }
			
			if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				for (int k = 0; k < craftingContents.length; k++) {
					if (this.isSimilar(craftingContents[k])) { craftView.setItem(k, new ItemStack(Material.AIR)); }
				}
			}
		} else {
			for (int k = 0; k < contents.length; k++) {
				if (this.isSimilar(contents[k])) { inv.setItem(k, ItemHandler.modifyItem(inv.getItem(k), false, amount[0])); return; }
			}
			if (this.isSimilar(inv.getHelmet())) { inv.setHelmet(ItemHandler.modifyItem(inv.getHelmet(), false, amount[0])); }
			else if (this.isSimilar(inv.getChestplate())) { inv.setChestplate(ItemHandler.modifyItem(inv.getChestplate(), false, amount[0])); }
			else if (this.isSimilar(inv.getLeggings())) { inv.setLeggings(ItemHandler.modifyItem(inv.getLeggings(), false, amount[0])); }
			else if (this.isSimilar(inv.getBoots())) { inv.setBoots(ItemHandler.modifyItem(inv.getBoots(), false, amount[0])); }
			else if (ServerUtils.hasSpecificUpdate("1_9") && this.isSimilar(PlayerHandler.getOffHandItem(player))) { PlayerHandler.setOffHandItem(player, ItemHandler.modifyItem(PlayerHandler.getOffHandItem(player), false, amount[0])); }
			else if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				for (int k = 0; k < craftingContents.length; k++) {
					if (this.isSimilar(craftingContents[k])) { craftView.setItem(k, ItemHandler.modifyItem(player.getOpenInventory().getItem(k), false, amount[0])); return; }
				}
			}
		}
	}
	
   /**
    * Gives the Player the ItemMap.
    * 
    * @param player - The Player to be given the item.
    * @param amount - The stack size of the item.
    */
	public void giveTo(final Player player, int...amount) {
		if (amount.length == 0) { amount = new int[]{0}; }
		if (this.CustomSlot != null && !this.CustomSlot.contains("%")) { ItemUtilities.getUtilities().setCustomSlots(player, this, amount[0]); } 
		else { ItemUtilities.getUtilities().setInvSlots(player, this, amount[0]); }
		this.setAnimations(player);
		if (this.getMultipleSlots() != null && !this.getMultipleSlots().isEmpty()) {
			if (this.getSlot().equalsIgnoreCase(this.getMultipleSlots().get(0))) {
				this.executeCommands(player, null, this.tempItem, "ON_RECEIVE", "RECEIVED", this.getSlot());
			}
		} else { this.executeCommands(player, null, this.tempItem, "ON_RECEIVE", "RECEIVED", this.getSlot()); }
	}
	
   /**
    * Gives the Player the ItemMap.
    * 
    * @param player - The Player to be given the item.
    * @param slot - The slot to be placed into.
    */
	public void swapItem(final Player player, final String slot) {
		ItemStack itemStack = this.getItem(player);
		if ((!slot.startsWith("CH") && slot.startsWith("C")) || StringUtils.isInt(slot)) {
			if (StringUtils.containsIgnoreCase(slot, "CRAFTING")) { 
				if (StringUtils.getSlotConversion(slot) == 0) {
					SchedulerUtils.runLater(1L, () -> {
				    	if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				    		player.getOpenInventory().getTopInventory().setItem(StringUtils.getSlotConversion(slot), itemStack);
				    		PlayerHandler.updateInventory(player, 1L);
				    	}
					});
				} else {
				    player.getOpenInventory().getTopInventory().setItem(StringUtils.getSlotConversion(slot), itemStack);
				}
			} 
			else { 
				player.getInventory().setItem(Integer.parseInt(slot), itemStack);
			}
		} else {
			if (PlayerHandler.getMainHandItem(player) == null || PlayerHandler.getMainHandItem(player).getType() == Material.AIR) {
				PlayerHandler.setMainHandItem(player, itemStack);
			} else {
				player.getInventory().addItem(itemStack);
			}
		}
		this.setAnimations(player);
		this.executeCommands(player, null, this.tempItem, "ON_RECEIVE", "RECEIVED", slot);
	}
	
   /**
    * Sets the Animations of the Player.
    * 
    * @param player - The Player having their animations set.
    */
	public void setAnimations(final Player player) {
		if (this.isAnimated() && this.getAnimationHandler().get(player) == null
				|| isDynamic() && this.getAnimationHandler().get(player) == null) {
			ItemAnimation Animator = new ItemAnimation(this);
			Animator.openAnimation(player);
			this.localeAnimations.put(player, Animator);
		}
	}
	
   /**
    * Attempts to Execute the ItemCommands.
    * 
    * @param player - The Player that executed the commands.
    * @param altPlayer - that is associated with the commands.
    * @param itemCopy - The ItemStack having their commands executed.
    * @param action - The Action that executed the commands.
    * @param slot - The Slot of the ItemStack.
    * @return If the commands successfully executed.
    */
    public void executeCommands(final Player player, final Player altPlayer, final ItemStack itemCopy, final String action, final String clickType, final String slot) {
    	if (this.commands != null && this.commands.length > 0 && !Menu.isOpen(player) && !this.getWarmPending(player) && this.isExecutable(player, action, clickType) && !this.onCooldown(player) && this.isPlayerChargeable(player, this.itemCost != null && !this.itemCost.isEmpty())) {
    		this.warmCycle(player, altPlayer, this, this.getWarmDelay(), player.getLocation(), itemCopy, action, clickType, slot);
    	}
    }
	
   /**
    * Starts the Warmup for the Player pending command execution.
    * 
    * @param player - The Player that executed the commands.
    * @param altPlayer - that is associated with the commands.
    * @param itemMap - The ItemMap having their commands executed.
    * @param warmCount - The duration of the Warmup.
    * @param location - The Location of the Warmup.
    * @param itemCopy - The ItemStack having their commands executed.
    * @param action - The Action that executed the commands.
    * @param slot - The Slot of the ItemStack.
    */
	private void warmCycle(final Player player, final Player altPlayer, final ItemMap itemMap, final int warmCount, final Location location, final ItemStack itemCopy, final String action, final String clickType, final String slot) {
		if (warmCount != 0) {
			if (itemMap.warmDelay == warmCount) { 
				String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[13] = warmCount + ""; placeHolders[0] = player.getWorld().getName(); placeHolders[3] = StringUtils.translateLayout(itemMap.getCustomName(), player); 
				LanguageAPI.getLang(false).sendLangMessage("general.warmingUp", player, placeHolders); 
				itemMap.addWarmPending(player); 
			}
			SchedulerUtils.runLater(20L, () -> {
				if (itemMap.warmLocation(player, location, action)) {
					String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[13] = warmCount + ""; placeHolders[0] = player.getWorld().getName(); placeHolders[3] = StringUtils.translateLayout(itemMap.getCustomName(), player); 
					LanguageAPI.getLang(false).sendLangMessage("general.warmingTime", player, placeHolders);
					itemMap.warmCycle(player, altPlayer, itemMap, (warmCount - 1), location, itemCopy, action, clickType, slot);	
				} else { 
					itemMap.delWarmPending(player); 
					String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[13] = warmCount + ""; placeHolders[0] = player.getWorld().getName(); placeHolders[3] = StringUtils.translateLayout(itemMap.getCustomName(), player); 
					LanguageAPI.getLang(false).sendLangMessage("general.warmingHalted", player, placeHolders);
				}
			});
		} else {
			long delay = 0;
			if (itemMap.warmDelay != 0) { delay = 20L; }
			SchedulerUtils.runLater(delay, () -> {
				if ((!player.isDead() || action.equalsIgnoreCase("ON_DEATH")) && player.isOnline()) {
					if (this.isExecuted(player, altPlayer, action, clickType, slot)) { 
						if (itemMap.itemCost == null || itemMap.itemCost.isEmpty()) { itemMap.withdrawBalance(player); } 
						else { itemMap.withdrawItemCost(player); }
					    itemMap.playSound(player);
					    itemMap.playParticle(player);
					    itemMap.removeDisposable(player, itemMap, itemCopy, false);
						itemMap.addPlayerOnCooldown(player);
					}
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[13] = warmCount + ""; placeHolders[0] = player.getWorld().getName(); placeHolders[3] = StringUtils.translateLayout(itemMap.getCustomName(), player); 
					LanguageAPI.getLang(false).sendLangMessage("general.warmingHalted", player, placeHolders);
				}
				if (itemMap.warmDelay != 0) { itemMap.delWarmPending(player); }
			});
		}
	}
	
   /**
    * Checks if the Player is still at the original Warmup Location.
    * 
    * @param player - The Player Warming Up.
    * @param Location - The Location of the Warmup.
    * @return If the Player is still inside the Warmup Location.
    */
	private boolean warmLocation(final Player player, final Location location, final String action) {
	    if (!player.getLocation().getWorld().equals(location.getWorld()) || player.getLocation().distance(location) >= 1 || (!action.equalsIgnoreCase("ON_DEATH") && player.isDead())) {
	    	return false;
	    }
	    return true;
	}
	
   /**
    * Checks if the ItemCommands are executable.
    * 
    * @param player - The Player that executed the command.
    * @param action - The Action that executed the command.
    * @return If the ItemCommands are executable.
    */
    private boolean isExecutable(final Player player, final String action, final String clickType) {
    	boolean playerSuccess = false;
    	ItemCommand[] itemCommands = this.commands;
    	for (int i = 0; i < itemCommands.length; i++) {
    		if (!playerSuccess) { playerSuccess = itemCommands[i].canExecute(player, action, clickType); }
			else { break; }
		}
    	return playerSuccess;
    }
	
   /**
    * Randomly Selected an ItemCommand Entry for a Single Command.
    * 
    * @param itemCommands - The ItemCommands to have an entry randomly selected.
    * @param player - The Player having their commands randomly selected.
    * @param altPlayer - that is associated with the commands.
    * @param action - The Action that executed the commands.
    * @param slot - The Slot of the ItemStack.
    * @return If it was successful.
    */
    private boolean getRandomMap(final ArrayList < ItemCommand > randomCommands, final ItemCommand[] itemCommands, final Player player, final Player altPlayer, final String action, final String clickType, final String slot) {
    	ItemCommand dedicatedMap = (ItemCommand) StringUtils.randomEntry(randomCommands);
    	if (dedicatedMap != null && dedicatedMap != null && player != null && action != null && clickType != null && slot != null && itemCommands != null && randomCommands != null
        && !dedicatedMap.execute(player, altPlayer, action, clickType, slot, this)) { 
    		return this.getRandomMap(randomCommands, itemCommands, player, altPlayer, action, clickType, slot);
    	}
    	return true;
    }
	
   /**
    * Randomly Selected an ItemCommand Entry for All Commands.
    * 
    * @param itemCommands - The ItemCommands to have an entry randomly selected.
    * @param player - The Player having their commands randomly selected.
    * @param altPlayer - that is associated with the commands.
    * @param action - The Action that executed the commands.
    * @param slot - The Slot of the ItemStack.
    * @return If it was successful.
    */
    private boolean getRandomAll(final ArrayList < ItemCommand > randomCommands, final ItemCommand[] itemCommands, final Player player, final Player altPlayer, final String action, final String clickType, final String slot) {
    	ItemCommand dedicatedMap = (ItemCommand) StringUtils.randomEntry(randomCommands);
    	if (dedicatedMap != null && dedicatedMap != null && player != null && action != null && slot != null && itemCommands != null && randomCommands != null 
        && !dedicatedMap.execute(player, altPlayer, action, clickType, slot, this)) { 
    		randomCommands.remove(dedicatedMap);
    		return this.getRandomAll(randomCommands, itemCommands, player, altPlayer, action, clickType, slot);
    	}
    	if (dedicatedMap != null && randomCommands != null) { randomCommands.remove(dedicatedMap); }
    	if (dedicatedMap != null && dedicatedMap != null && player != null && action != null && slot != null && itemCommands != null && randomCommands != null && 
    	   !randomCommands.isEmpty()) {
    		this.getRandomAll(randomCommands, itemCommands, player, altPlayer, action, clickType, slot);
    	}
    	return true;
    }
	
   /**
    * Randomly Selected an ItemCommand Entry.
    * 
    * @param itemCommands - The ItemCommands to have an entry randomly selected.
    * @return The Randomly selected ItemCommand.
    */
    private String getRandomList(final ItemCommand[] itemCommands) {
    	if (this.sequence == CommandSequence.RANDOM_LIST) {
    		ArrayList < String > listIdent = new ArrayList < String > ();
    		for (int i = 0; i < itemCommands.length; i++) {
    			if (!listIdent.contains("+" + itemCommands[i].getSection() + "+")) {
    				listIdent.add("+" + itemCommands[i].getSection() + "+");
    			}
    		}
    		return (String) StringUtils.randomEntry(listIdent);
    	}
    	return null;
    }
	
   /**
    * Executes the ItemCommands.
    * 
    * @param player - The Player executing the commands.
    * @param altPlayer - that is associated with the commands.
    * @param action - The Action executing the commands.
    * @param slot - The slot of the ItemStack.
    * @param itemCopy - The ItemStack having their commands executed.
    * @return If the Command(s) were successfully executed.
    */
    private boolean isExecuted(final Player player, final Player altPlayer, final String action, final String clickType, final String slot) {
    	boolean playerSuccess = false;
    	ItemCommand[] itemCommands = this.commands;
    	String chosenIdent = this.getRandomList(itemCommands);
    	ArrayList < ItemCommand > randomCommands = new ArrayList < ItemCommand > ();
    	if (!this.subjectRemoval) {
    		for (int i = 0; i < itemCommands.length; i++) { 
        		if (this.sequence == CommandSequence.RANDOM || this.sequence == CommandSequence.RANDOM_SINGLE) { randomCommands.add(itemCommands[i]); }
        		else if (this.sequence == CommandSequence.RANDOM_LIST) {
        			if (itemCommands[i].getSection() != null && itemCommands[i].getSection().equalsIgnoreCase(chosenIdent.replace("+", ""))) {
	        			if (!playerSuccess) { playerSuccess = itemCommands[i].execute(player, altPlayer, action, clickType, slot, this); } 
	        			else { itemCommands[i].execute(player, altPlayer, action, clickType, slot, this); } 
	        		}
        		}
				else { 
					synchronized(ItemCommand.class) {
						if (!playerSuccess) { playerSuccess = itemCommands[i].execute(player, altPlayer, action, clickType, slot, this); }
						else { itemCommands[i].execute(player, altPlayer, action, clickType, slot, this); }
					}
				}
			}
    		if (this.sequence == CommandSequence.RANDOM) { playerSuccess = this.getRandomAll(randomCommands, itemCommands, player, altPlayer, action, clickType, slot); }
    		else if (this.sequence == CommandSequence.RANDOM_SINGLE) { playerSuccess = this.getRandomMap(randomCommands, itemCommands, player, altPlayer, action, clickType, slot); }
    	}
    	return playerSuccess;
    }
	
   /**
    * Checks if the Player has the proper balance/cost so they can execute the command.
    * 
    * @param player - The Player being charged.
    * @param materialCost - If the cost being charged is an Item.
    * @return If the Player has the required economy balance to execute the command.
    */
    private boolean isPlayerChargeable(final Player player, final boolean materialCost) {
		if (DependAPI.getDepends(false).getVault().vaultEnabled() && !materialCost) {
			double balance = 0.0; try { balance = DependAPI.getDepends(false).getVault().getBalance(player); } catch (NullPointerException e) { }
			if (balance >= this.cost || this.cost < 0) {
				return true;
			} else if (!(balance >= this.cost)) {
				String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[6] = this.cost.toString(); placeHolders[5] = balance + "";
				LanguageAPI.getLang(false).sendLangMessage("general.econFailed", player, placeHolders);
				return false;
			}
		} else if (materialCost) {
			Material mat = ItemHandler.getMaterial(this.itemCost, null);
			int foundAmount = 0;
			for (ItemStack playerInventory: player.getInventory().getContents()) {
				if (playerInventory != null && playerInventory.getType() == mat) {
					if (playerInventory.getAmount() >= this.cost) {
						return true;
					} else { 
						foundAmount += playerInventory.getAmount();
						if (foundAmount >= this.cost) {
							return true;
						}
					}
				}
			}
			for (ItemStack equipInventory: player.getEquipment().getArmorContents()) {
				if (equipInventory != null && equipInventory.getType() == mat) {
					if (equipInventory.getAmount() >= this.cost) {
						return true;
					} else { 
						foundAmount += equipInventory.getAmount();
						if (foundAmount >= this.cost) {
							return true;
						}
					}
				}
			}
			if (ServerUtils.hasSpecificUpdate("1_9") && player.getInventory().getItemInOffHand() != null && player.getInventory().getItemInOffHand().getType() == mat) {
				if (player.getInventory().getItemInOffHand().getAmount() >= this.cost) {
					return true;
				} else { 
					foundAmount += player.getInventory().getItemInOffHand().getAmount();
					if (foundAmount >= this.cost) {
						return true;
					}
				}
			}
			if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				for (ItemStack craftInventory: player.getOpenInventory().getTopInventory()) {
					if (craftInventory != null && craftInventory.getType() == mat && craftInventory.getAmount() >= this.cost) {
						if (craftInventory.getAmount() >= this.cost) {
							return true;
						} else { 
							foundAmount += craftInventory.getAmount();
							if (foundAmount >= this.cost) {
								return true;
							}
						}
					}
				}
			}
			String formatCost = "";
			for (String str : this.itemCost.toLowerCase().split("_")) { formatCost += str.substring(0, 1).toUpperCase() + str.substring(1) + " "; }
			formatCost = formatCost.substring(0, formatCost.length() - 1);
			String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[4] = formatCost; placeHolders[6] = this.cost == 0 ? "1" : this.cost.toString(); placeHolders[5] = foundAmount + "";
			LanguageAPI.getLang(false).sendLangMessage("general.itemFailed", player, placeHolders);
			return false;
		}
		return true;
	}
	
    /**
    * Withdraws the Commands Item Cost from the Players Inventory.
    * 
    * @param player - The Player to have their Item Cost changed.
    */
    private void withdrawItemCost(final Player player) {
		Material mat = ItemHandler.getMaterial(this.itemCost, null);
		Integer removeAmount = this.cost; if (this.cost == 0) { removeAmount = 1; }
		for (int i = 0; i < player.getInventory().getSize(); i++) {
			if (player.getInventory().getItem(i) != null && player.getInventory().getItem(i).getType() == mat) {
				if (player.getInventory().getItem(i).getAmount() < removeAmount) {
					removeAmount -= player.getInventory().getItem(i).getAmount();
					player.getInventory().setItem(i, ItemHandler.modifyItem(player.getInventory().getItem(i), false, player.getInventory().getItem(i).getAmount()));
				} else { player.getInventory().setItem(i, ItemHandler.modifyItem(player.getInventory().getItem(i), false, removeAmount)); break; } 
			}
		}
		if (ServerUtils.hasSpecificUpdate("1_9") && player.getInventory().getItemInOffHand() != null && player.getInventory().getItemInOffHand().getType() == mat) {
			if (player.getInventory().getItemInOffHand().getAmount() < removeAmount) {
				removeAmount -= player.getInventory().getItemInOffHand().getAmount();
				PlayerHandler.setOffHandItem(player, ItemHandler.modifyItem(player.getInventory().getItemInOffHand(), false, player.getInventory().getItemInOffHand().getAmount()));
			} else { PlayerHandler.setOffHandItem(player, ItemHandler.modifyItem(player.getInventory().getItemInOffHand(), false, removeAmount));} 
			PlayerHandler.setOffHandItem(player, ItemHandler.modifyItem(player.getInventory().getItemInOffHand(), false, removeAmount));
		}
		if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
			for (int i = 0; i < player.getOpenInventory().getTopInventory().getSize(); i++) {
				if (player.getOpenInventory().getTopInventory().getItem(i) != null && player.getOpenInventory().getTopInventory().getItem(i).getType() == mat) {
					if (player.getOpenInventory().getTopInventory().getItem(i).getAmount() < removeAmount) {
						removeAmount -= player.getOpenInventory().getTopInventory().getItem(i).getAmount();
						player.getOpenInventory().getTopInventory().setItem(i, ItemHandler.modifyItem(player.getOpenInventory().getTopInventory().getItem(i), false, player.getOpenInventory().getTopInventory().getItem(i).getAmount()));
					} else { player.getOpenInventory().getTopInventory().setItem(i, ItemHandler.modifyItem(player.getOpenInventory().getTopInventory().getItem(i), false, removeAmount)); break; } 
				}
			}
		}
		String formatCost = "";
		for (String str : this.itemCost.toLowerCase().split("_")) { formatCost += str.substring(0, 1).toUpperCase() + str.substring(1) + " "; }
		formatCost = formatCost.substring(0, formatCost.length() - 1);
		String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[4] = formatCost; placeHolders[6] = this.cost.toString();
		LanguageAPI.getLang(false).sendLangMessage("general.itemSuccess", player, placeHolders);
    }
	
   /**
    * Withdraws the Commands Cost from the Vault Balance for the Player.
    * 
    * @param player - The Player to have their economy balance changed.
    */
    private void withdrawBalance(final Player player) {
		if (DependAPI.getDepends(false).getVault().vaultEnabled()) {
			double balance = 0.0;
			try { balance = DependAPI.getDepends(false).getVault().getBalance(player); } catch (NullPointerException e) { }
			int parseCost = this.cost;
			if (balance >= parseCost) {
				if (parseCost > 0) {
					try { DependAPI.getDepends(false).getVault().withdrawBalance(player, parseCost); } catch (NullPointerException e) { ServerUtils.sendDebugTrace(e); }
					String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[6] = this.cost.toString();
					LanguageAPI.getLang(false).sendLangMessage("general.econSuccess", player, placeHolders);
				}
			}
		}
	}
	
   /**
    * Plays the Commands Sound for the Player.
    * 
    * @param player - The Player to have the Sound heard.
    */
	private void playSound(final Player player) {
		if (this.commandSound != null) {
			try {
				player.playSound(player.getLocation(), this.commandSound, (float) ((double)this.commandSoundVolume), (float) ((double)this.commandSoundPitch));
			} catch (Exception e) {
				ServerUtils.logSevere("{ItemMap} There was an issue executing the commands-sound you defined.");
				ServerUtils.logWarn("{ItemMap} " + this.commandSound + " is not a sound in " + ReflectionUtils.getServerVersion() + ".");
				ServerUtils.sendDebugTrace(e);
			}
		}
	}
	
   /**
    * Plays the Commands Particle for the Player.
    * 
    * @param player - The Player to have the Particle visible.
    */
	private void playParticle(final Player player) {
		if (this.commandParticle != null) {
			EffectAPI.spawnParticle(player, this.commandParticle);
		}
	}
	
   /**
    * Disposes of the specified ItemStack, removing x1 from the Players Inventory.
    * 
    * @param player - The Player disposing of the ItemStack.
    * @param itemCopy - The ItemStack to be disposed.
    * @param allItems - If the item should not have its amount changed.
    */
	public void removeDisposable(final Player player, final ItemMap itemMap, final ItemStack itemCopy, final boolean allItems) {
		if (this.disposable && this.conditionMet(player, "disposable-conditions") || allItems) {
			if (!allItems) { this.setSubjectRemoval(true); }
			SchedulerUtils.runLater(1L, () -> {
				if (PlayerHandler.isCreativeMode(player)) { player.closeInventory(); }
				if (itemMap.isSimilar(player.getItemOnCursor())) {
					player.setItemOnCursor(ItemHandler.modifyItem(player.getItemOnCursor(), allItems, 1));
					if (!allItems) { this.setSubjectRemoval(false); }
				} else {
					int itemSlot = player.getInventory().getHeldItemSlot();
					if (itemMap.isSimilar(player.getInventory().getItem(itemSlot))) { player.getInventory().setItem(itemSlot, ItemHandler.modifyItem(player.getInventory().getItem(itemSlot), allItems, 1)); if (!allItems) { this.setSubjectRemoval(false); }}
					else { 
						for (int i = 0; i < player.getInventory().getSize(); i++) {
							if (itemMap.isSimilar(player.getInventory().getItem(i))) {
								player.getInventory().setItem(i, ItemHandler.modifyItem(player.getInventory().getItem(i), allItems, 1));
								if (!allItems) { this.setSubjectRemoval(false); }
								break;
							}
						}
					}
					if (this.isSubjectRemoval() && PlayerHandler.isCreativeMode(player)) {
						player.getInventory().addItem(ItemHandler.modifyItem(itemCopy, allItems, 1));
						player.setItemOnCursor(new ItemStack(Material.AIR));
						if (!allItems) { this.setSubjectRemoval(false); }
					} else if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
						for (int i = 0; i < player.getOpenInventory().getTopInventory().getSize(); i++) {
							if (itemMap.isSimilar(player.getOpenInventory().getTopInventory().getItem(i))) {
								player.getOpenInventory().getTopInventory().setItem(i, ItemHandler.modifyItem(player.getOpenInventory().getTopInventory().getItem(i), allItems, 1));
								if (!allItems) { this.setSubjectRemoval(false); }
								break;
							}
						}
					}
				}
			});
		}
	}
	
   /**
    * Checks if the Player is on Interact Cooldown.
    * 
    * @param player - The Player to be checked. 
    * @return If the Player is on Interact Cooldown.
    */
	public boolean onInteractCooldown(final Player player) {
		long playersCooldownList = 0L;
		if (this.playersOnInteractCooldown.containsKey(PlayerHandler.getPlayerID(player) + ".items." + this.configName)) {
			playersCooldownList = this.playersOnInteractCooldown.get(PlayerHandler.getPlayerID(player) + ".items." + this.configName);
		}
		if (System.currentTimeMillis() - playersCooldownList >= this.interactCooldown * 1000) {
			this.playersOnInteractCooldown.put(PlayerHandler.getPlayerID(player) + ".items." + this.configName, System.currentTimeMillis());
			return false;
		} else {
			if (this.onSpamCooldown(player)) {
				this.storedSpammedPlayers.put(PlayerHandler.getPlayerID(player) + ".items." + this.configName, System.currentTimeMillis());
				if (this.cooldownMessage != null && !this.cooldownMessage.isEmpty()) {
					int timeLeft = (int)(this.interactCooldown - ((System.currentTimeMillis() - playersCooldownList) / 1000));
					player.sendMessage(StringUtils.translateLayout(this.cooldownMessage.replace("%timeleft%", String.valueOf(timeLeft)).replace("%item%", this.customName), player));
				}
			}
			return true;
		}
	}
	
   /**
    * Checks if the Player is on Cooldown.
    * (Prevents rapid fire commands).
    * 
    * @param player - The Player to be checked. 
    * @return If the Player is on Cooldown.
    */
	private boolean onSpamCooldown(final Player player) {
		boolean interactSpam = ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Spamming");
		if (interactSpam != true) {
			long playersCooldownList = 0L;
			if (this.storedSpammedPlayers.containsKey(PlayerHandler.getPlayerID(player) + ".items." + this.configName)) {
				playersCooldownList = this.storedSpammedPlayers.get(PlayerHandler.getPlayerID(player) + ".items." + this.configName);
			}
			if (System.currentTimeMillis() - playersCooldownList >= this.spamtime * 1000) { } 
			else { return false; }
		}
		return true;
	}
	
   /**
    * Checks if the Player is on Cooldown.
    * 
    * @param player - The Player to be checked. 
    * @return If the Player is on Cooldown.
    */
	private boolean onCooldown(final Player player) {
		long playersCooldownList = 0L;
		if (this.playersOnCooldown.containsKey(PlayerHandler.getPlayerID(player))) {
			playersCooldownList = this.playersOnCooldown.get(PlayerHandler.getPlayerID(player));
		}
		if (this.cooldownSeconds != 0) {
			if (System.currentTimeMillis() - playersCooldownList >= this.cooldownSeconds * 1000) { return false; } 
			else if (this.onCooldownTick(player)) {
				String cooldownmsg = this.cooldownMessage != null ? (this.cooldownMessage.replace("%timeleft%", String.valueOf((this.cooldownSeconds - ((System.currentTimeMillis() - playersCooldownList) / 1000)))).replace("%item%", this.customName).replace("%itemraw%", ItemHandler.getMaterialName(this.tempItem))) : null;
				if (cooldownmsg != null && !this.cooldownMessage.isEmpty()) { 
					cooldownmsg = StringUtils.translateLayout(cooldownmsg, player);
					player.sendMessage(cooldownmsg);
				}
				this.addPlayerOnCooldownTick(player);
			}
		} else if (this.onCooldownTick(player)) {
			this.addPlayerOnCooldownTick(player);
			return false;
		}
		return true;
	}
	
   /**
    * Checks if the Player is on Cooldown.
    * 
    * @param player - The Player to be checked. 
    * @return If the Player is on Cooldown.
    */
	private boolean onCooldownTick(final Player player) {
		if (!ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Spamming")) {
			long playersCooldownList = 0L;
			if (this.playersOnCooldownTick.containsKey(PlayerHandler.getPlayerID(player))) {
				playersCooldownList = this.playersOnCooldownTick.get(PlayerHandler.getPlayerID(player));
			}
			
			if (!(System.currentTimeMillis() - playersCooldownList >= 1000)) { return false; }
		}
		return true;
	}
	
   /**
    * Puts the Player on Cooldown.
    * (Prevents rapid fire commands).
    * 
    * @param player - The Player to be put on Cooldown.
    */
	private void addPlayerOnCooldownTick(final Player player) {
		this.playersOnCooldownTick.put(PlayerHandler.getPlayerID(player), System.currentTimeMillis());
	}
	
   /**
    * Puts the Player on Cooldown.
    * 
    * @param player - The Player to be put on Cooldown.
    */
	private void addPlayerOnCooldown(final Player player) {
		this.playersOnCooldown.put(PlayerHandler.getPlayerID(player), System.currentTimeMillis());
	}
	
   /**
    * Gets the Players on Cooldown.
    * 
    * @return The Map of Players on Cooldown.
    */
    public Map<String, Long> getPlayersOnCooldown() {
    	return this.playersOnCooldown;
    }
	
   /**
    * Adds an ItemCommand to a Map.
    * 
    * @param map - The Map to have an ItemCommand addded.
    * @param command - The ItemCommand to be added to the Map.
    * @return The changed Map instance.
    */
	public Map<String, List<String>> addMapCommand(final Map<String, List<String>> map, final ItemCommand command) {
		String commandSection = (command.getSection() != null ? command.getSection() : "DEFAULT");
		if (map.get(commandSection) != null) { 
			List <String> s1 = map.get(commandSection); s1.add(command.getRawCommand());
			map.put(commandSection, s1);  
		} 
		else {
			List <String> s1 = new ArrayList<String>(); s1.add(command.getRawCommand());
			map.put(commandSection, s1);  
		}
		return map;
	}
	
   /**
    * Saves the ItemCommands to the items.yml.
    * 
    * @param itemData - The File having the data saved.
    * @param map - The Map of entries to save.
    * @param section - The item section being saved.
    */
	public void setMapCommand(final FileConfiguration itemData, final Map<String, List<String>> map, final String section) {
		Iterator<Entry<String, List<String>>> iterate = map.entrySet().iterator(); 
		while (iterate.hasNext()) { 
			Entry<String, List<String>> mapElement = (Entry<String, List<String>>)iterate.next(); 
			String mapKey = mapElement.getKey(); 
			if (mapKey.equalsIgnoreCase("DEFAULT") && map.size() <= 1) { mapKey = ""; } else { mapKey = "." + mapKey; }
			itemData.set("items." + this.configName + "." + section + mapKey, mapElement.getValue()); 
		}
	}
	
   /**
	* Gets the Shape of the Recipe of the Custom Item.
	* 
	* @return The trimmed recipe.
	*/
	public String[] trimRecipe(final List<String> list) {
		List < Character > recipe = new ArrayList < Character > ();
		List < String > recipeList = list;
		String[] recipeShape = { "XXX", "XXX", "XXX" };
		String[] shape = { "", "", "" };
		for (int i = 0; i < recipeList.size(); i++) {
			int charSize = 0;
			for (String character: recipeList.get(i).split("(?<!^)")) {
				StringBuilder sb = new StringBuilder(recipeShape[i]);
				sb.setCharAt(charSize, character.charAt(0));
				recipeShape[i] = sb.toString();
				charSize++;
			}
			for (String character: recipeShape[i].split("(?<!^)")) { 
				recipe.add(character.charAt(0));
			}
			shape[i] = recipeList.get(i).replace("X", " ");
		}
		this.setRecipe(recipe);
		if ((shape[2].length() == 3 && shape[2].charAt(0) == ' ' && shape[2].charAt(1) == ' ' && shape[2].charAt(2) == ' ') || shape[2].isEmpty()) {
			if (shape[0].length() == 3 && shape[0].charAt(2) == ' ' && shape[1].length() == 3 && shape[1].charAt(2) == ' ') {
				shape = new String[] { shape[0].substring(0, shape[0].length() - 1), shape[1].substring(0, shape[1].length() - 1) };
			} else if ((shape[0].length() == 3 && shape[0].charAt(0) == ' ' && shape[0].charAt(1) == ' ' && shape[0].charAt(2) == ' ') || shape[0].isEmpty()) {
				shape = new String[] { shape[1] };
			} else if ((shape[1].length() == 3 && shape[1].charAt(0) == ' ' && shape[1].charAt(1) == ' ' && shape[1].charAt(2) == ' ') || shape[1].isEmpty()) {
				shape = new String[] { shape[0] };
			} else {
				shape = new String[] { shape[0], shape[1] };
			}
		} else if (shape[0].length() < 3 && shape[1].length() < 3 && shape[2].length() == 3 && shape[2].charAt(0) == ' ' && shape[2].charAt(1) == ' ' && shape[2].charAt(2) == ' ') {
			shape = new String[] { shape[0], shape[1] };
		} else if (shape[0].length() == 3 && shape[1].length() == 3 && shape[2].length() == 3 && shape[0].charAt(2) == ' ' && shape[1].charAt(2) == ' ' && shape[2].charAt(2) == ' ') {
			shape = new String[] { shape[0].substring(0, shape[0].length() - 1), shape[1].substring(0, shape[1].length() - 1), shape[2].substring(0, shape[2].length() - 1) };
		}
		return shape;
	}
	
   /**
    * Removes this ItemMap instance from the items.yml.
    * 
    */
	public void removeFromConfig() {
		File itemFile =  new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
		FileConfiguration itemData = YamlConfiguration.loadConfiguration(itemFile);
		if (ConfigHandler.getConfig().getFile("items.yml").getString("items." + this.configName) != null) { itemData.set("items." + this.configName, null); } 
		try { itemData.save(itemFile); ConfigHandler.getConfig().getSource("items.yml"); ConfigHandler.getConfig().getFile("items.yml").options().copyDefaults(false); } 
		catch (Exception e) { ItemJoin.getInstance().getServer().getLogger().severe("Could not remove the custom item " + this.configName + " from the items.yml data file!"); ServerUtils.sendDebugTrace(e); }	
	}
	
   /**
    * Saves the ItemMap to the items.yml.
    * 
    */
	public void saveToConfig() {
		File itemFile =  new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
		FileConfiguration itemData = YamlConfiguration.loadConfiguration(itemFile);
		this.renderItemStack();
		if (ConfigHandler.getConfig().getFile("items.yml").getString("items." + this.configName) != null) { itemData.set("items." + this.configName, null); } 
		if (!(this.dynamicMaterials != null && !this.dynamicMaterials.isEmpty())) { itemData.set("items." + this.configName + ".id", this.material.toString().toUpperCase() + (this.dataValue != null && this.dataValue != 0 ? ":" + this.dataValue : "")); }
		else if (this.dynamicMaterials != null && !this.dynamicMaterials.isEmpty()) { 
			for (int i = 0; i < this.dynamicMaterials.size(); i++) {
				itemData.set("items." + this.configName + ".id." + (i + 1), this.dynamicMaterials.get(i)); 	
			}
		}
		if (this.AllSlots != null && !this.AllSlots.isEmpty()) { 
			String saveSlots = "";
			for (String slot : this.AllSlots) { saveSlots += slot + ", "; }
			if (!saveSlots.substring(0, saveSlots.length() - 2).equalsIgnoreCase("ARBITRARY")) {
				itemData.set("items." + this.configName + ".slot", saveSlots.substring(0, saveSlots.length() - 2)); 
			}
		}
		else if (this.CustomSlot == null) { itemData.set("items." + this.configName + ".slot", this.InvSlot); }
		else { 
			if (!this.CustomSlot.equalsIgnoreCase("ARBITRARY")) {
				itemData.set("items." + this.configName + ".slot", this.CustomSlot); 
			}
		}
		if (this.count > 1) { itemData.set("items." + this.configName + ".count", this.count); }
		if (this.durability != null && this.durability > 0) { itemData.set("items." + this.configName + ".durability", this.durability); }
		if (this.data != null && this.data > 0) { itemData.set("items." + this.configName + ".data", this.data); }
		if (this.modelData != null && this.modelData > 0) { itemData.set("items." + this.configName + ".model-data", this.modelData); }
		if (this.author != null && !this.author.isEmpty()) { itemData.set("items." + this.configName + ".author", this.author.replace("§", "&")); }
		if (this.customName != null && !this.customName.isEmpty() && (this.dynamicNames == null || this.dynamicNames.isEmpty())) { 
			String setName = null;
			if (this.legacySecret != null && !ServerUtils.hasSpecificUpdate("1_14")) {
				final ItemMeta itemMeta = this.tempItem.getItemMeta();
				itemMeta.setDisplayName("");
				this.tempItem.setItemMeta(itemMeta);
				StringUtils.colorEncode(this.tempItem, this.legacySecret);
				final String itemInfo = this.tempItem.getItemMeta().getDisplayName();
				setName = this.customName.replace(itemInfo, "").replace("§", "&");
			} else {
				setName = this.customName.replace("§", "&");
			}
			if (setName.startsWith("&f") && (!ItemHandler.dataTagsEnabled() || !ServerUtils.hasSpecificUpdate("1_8"))) { setName = setName.substring(2, setName.length()); }
				if (!ItemHandler.getMaterialName(this.tempItem).equalsIgnoreCase(setName)) { 
					itemData.set("items." + this.configName + ".name", setName); 
				}
			}
		else if (this.dynamicNames != null && !this.dynamicNames.isEmpty()) { 
			for (int i = 0; i < this.dynamicNames.size(); i++) {
				itemData.set("items." + this.configName + ".name." + (i + 1), this.dynamicNames.get(i).replace("§", "&")); 	
			}
		}
		if (this.customLore != null && !this.customLore.isEmpty() && (this.dynamicLores == null || this.dynamicLores.isEmpty())) { itemData.set("items." + this.configName + ".lore", this.customLore); }
		else if (this.dynamicLores != null && !this.dynamicLores.isEmpty()) { 
			for (int i = 0; i < this.dynamicLores.size(); i++) {
				List <String> lores = this.dynamicLores.get(i);
				for (int k = 0; k < lores.size(); k++) {
					lores.get(k).replace("§", "&");
				}
				itemData.set("items." + this.configName + ".lore." + (i + 1), lores); 	
			}
		}
		if (this.listPages != null && !this.listPages.isEmpty()) { 
			for (int i = 0; i < this.listPages.size(); i++) {
				List <String> pages = this.listPages.get(i);
				for (int k = 0; k < pages.size(); k++) {
					pages.get(k).replace("§", "&");
				}
				itemData.set("items." + this.configName + ".pages." + (i + 1), pages); 	
			}
		}
		if (this.probability != null && this.probability != -1 && this.probability != 0) { itemData.set("items." + this.configName + ".probability", this.probability); }
		if (this.commands != null && this.commands.length > 0) {
			Map<String, List<String>> interactAll = new HashMap<String, List<String>>();
			Map<String, List<String>> interactLeft = new HashMap<String, List<String>>();
			Map<String, List<String>> interactRight = new HashMap<String, List<String>>();
			Map<String, List<String>> interactAir = new HashMap<String, List<String>>();
			Map<String, List<String>> interactBlock = new HashMap<String, List<String>>();
			Map<String, List<String>> interactLeftAir = new HashMap<String, List<String>>();
			Map<String, List<String>> interactLeftBlock = new HashMap<String, List<String>>();
			Map<String, List<String>> interactRightAir = new HashMap<String, List<String>>();
			Map<String, List<String>> interactRightBlock = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryAll = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryMiddle = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryCreative = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryLeft = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryShiftLeft = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryRight = new HashMap<String, List<String>>();
			Map<String, List<String>> inventoryShiftRight = new HashMap<String, List<String>>();
			Map<String, List<String>> inventorySwapCursor = new HashMap<String, List<String>>();
			Map<String, List<String>> onEquip = new HashMap<String, List<String>>();
			Map<String, List<String>> unEquip = new HashMap<String, List<String>>();
			Map<String, List<String>> onHold = new HashMap<String, List<String>>();
			Map<String, List<String>> onDeath = new HashMap<String, List<String>>();
			Map<String, List<String>> onDamage = new HashMap<String, List<String>>();
			Map<String, List<String>> onHit = new HashMap<String, List<String>>();
			Map<String, List<String>> onFire = new HashMap<String, List<String>>();
			Map<String, List<String>> onConsume = new HashMap<String, List<String>>();
			Map<String, List<String>> onReceive = new HashMap<String, List<String>>();
			Map<String, List<String>> physical = new HashMap<String, List<String>>();
			for(ItemCommand command : this.commands) {
				if (command.matchAction(ItemCommand.Action.INTERACT_ALL)) { interactAll = this.addMapCommand(interactAll, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_AIR)) { interactAir = this.addMapCommand(interactAir, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_BLOCK)) { interactBlock = this.addMapCommand(interactBlock, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_RIGHT_ALL)) { interactRight = this.addMapCommand(interactRight, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_RIGHT_AIR)) { interactRightAir = this.addMapCommand(interactRightAir, command);}
				else if (command.matchAction(ItemCommand.Action.INTERACT_RIGHT_BLOCK)) { interactRightBlock = this.addMapCommand(interactRightBlock, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_LEFT_ALL)) { interactLeft = this.addMapCommand(interactLeft, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_LEFT_AIR)) { interactLeftAir = this.addMapCommand(interactLeftAir, command); }
				else if (command.matchAction(ItemCommand.Action.INTERACT_LEFT_BLOCK)) { interactLeftBlock = this.addMapCommand(interactLeftBlock, command); }
				
				else if (command.matchAction(ItemCommand.Action.INVENTORY_ALL)) { inventoryAll = this.addMapCommand(inventoryAll, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_MIDDLE)) { inventoryMiddle = this.addMapCommand(inventoryMiddle, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_CREATIVE)) { inventoryCreative = this.addMapCommand(inventoryCreative, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_LEFT)) { inventoryLeft = this.addMapCommand(inventoryLeft, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_SHIFT_LEFT)) { inventoryShiftLeft = this.addMapCommand(inventoryShiftLeft, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_RIGHT)) { inventoryRight = this.addMapCommand(inventoryRight, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_SHIFT_RIGHT)) { inventoryShiftRight = this.addMapCommand(inventoryShiftRight, command); }
				else if (command.matchAction(ItemCommand.Action.INVENTORY_SWAP_CURSOR)) { inventorySwapCursor = this.addMapCommand(inventorySwapCursor, command); }
				
				else if (command.matchAction(ItemCommand.Action.ON_EQUIP)) { onEquip = this.addMapCommand(onEquip, command); }
				else if (command.matchAction(ItemCommand.Action.UN_EQUIP)) { unEquip = this.addMapCommand(unEquip, command); }
				else if (command.matchAction(ItemCommand.Action.ON_HOLD)) { onHold = this.addMapCommand(onHold, command); }
				else if (command.matchAction(ItemCommand.Action.ON_DEATH)) { onDeath = this.addMapCommand(onDeath, command); }
				else if (command.matchAction(ItemCommand.Action.ON_DAMAGE)) { onDamage = this.addMapCommand(onDamage, command); }
				else if (command.matchAction(ItemCommand.Action.ON_HIT)) { onHit = this.addMapCommand(onHit, command); }
				else if (command.matchAction(ItemCommand.Action.ON_FIRE)) { onFire = this.addMapCommand(onFire, command); }
				else if (command.matchAction(ItemCommand.Action.ON_CONSUME)) { onConsume = this.addMapCommand(onConsume, command); }
				else if (command.matchAction(ItemCommand.Action.ON_RECEIVE)) { onReceive = this.addMapCommand(onReceive, command); }
				else if (command.matchAction(ItemCommand.Action.PHYSICAL)) { physical = this.addMapCommand(physical, command); }
			}
			if (!interactAll.isEmpty()) { this.setMapCommand(itemData, interactAll, "interact"); }
			if (!interactAir.isEmpty()) { this.setMapCommand(itemData, interactAir, "interact-air"); }
			if (!interactBlock.isEmpty()) { this.setMapCommand(itemData, interactBlock, "interact-block"); }
			if (!interactRight.isEmpty()) { this.setMapCommand(itemData, interactRight, "interact-right"); }
			if (!interactRightAir.isEmpty()) { this.setMapCommand(itemData, interactRightAir, "interact-air-right"); }
			if (!interactRightBlock.isEmpty()) { this.setMapCommand(itemData, interactRightBlock, "interact-block-right"); }
			if (!interactLeft.isEmpty()) { this.setMapCommand(itemData, interactLeft, "interact-left"); }
			if (!interactLeftAir.isEmpty()) { this.setMapCommand(itemData, interactLeftAir, "interact-air-left"); }
			if (!interactLeftBlock.isEmpty()) { this.setMapCommand(itemData, interactLeftBlock, "interact-block-left"); }
			
			if (!inventoryAll.isEmpty()) { this.setMapCommand(itemData, inventoryAll, "inventory"); }
			if (!inventoryMiddle.isEmpty()) { this.setMapCommand(itemData, inventoryMiddle, "inventory-middle"); }
			if (!inventoryCreative.isEmpty()) { this.setMapCommand(itemData, inventoryCreative, "inventory-creative"); }
			if (!inventoryLeft.isEmpty()) { this.setMapCommand(itemData, inventoryLeft, "inventory-left"); }
			if (!inventoryShiftLeft.isEmpty()) { this.setMapCommand(itemData, inventoryShiftLeft, "inventory-shift-left"); }
			if (!inventoryRight.isEmpty()) { this.setMapCommand(itemData, inventoryRight, "inventory-right"); }
			if (!inventoryShiftRight.isEmpty()) { this.setMapCommand(itemData, inventoryShiftRight, "inventory-shift-right"); }
			if (!inventorySwapCursor.isEmpty()) { this.setMapCommand(itemData, inventorySwapCursor, "inventory-swap-cursor"); }
			
			if (!onEquip.isEmpty()) { this.setMapCommand(itemData, onEquip, "on-equip"); }
			if (!unEquip.isEmpty()) { this.setMapCommand(itemData, unEquip, "un-equip"); }
			if (!onHold.isEmpty()) { this.setMapCommand(itemData, onHold, "on-hold"); }
			if (!onDeath.isEmpty()) { this.setMapCommand(itemData, onDeath, "on-death"); }
			if (!onDamage.isEmpty()) { this.setMapCommand(itemData, onDamage, "on-damage"); }
			if (!onHit.isEmpty()) { this.setMapCommand(itemData, onHit, "on-hit"); }
			if (!onFire.isEmpty()) { this.setMapCommand(itemData, onFire, "on-fire"); }
			if (!onConsume.isEmpty()) { this.setMapCommand(itemData, onConsume, "on-consume"); }
			if (!onReceive.isEmpty()) { this.setMapCommand(itemData, onReceive, "on-receive"); }
			if (!physical.isEmpty()) { this.setMapCommand(itemData, physical, "physical"); }
		}
		if (this.toggleCommands != null && !this.getToggleCommands().isEmpty()) { itemData.set("items." + this.configName + ".toggle", this.toggleCommands); }
		if (this.commandSound != null) { itemData.set("items." + this.configName + ".commands-sound", this.commandSound.name() + ((this.commandSoundVolume != 1.0 && this.commandSoundPitch != 1.0) ? ":" + this.commandSoundVolume + ":" + this.commandSoundPitch : "")); }
		if (this.commandParticle != null && !this.commandParticle.isEmpty()) { itemData.set("items." + this.configName + ".commands-particle", this.commandParticle); }
		if (this.sequence != null && this.sequence != CommandSequence.SEQUENTIAL) { itemData.set("items." + this.configName + ".commands-sequence", this.sequence.name()); }
		if (this.itemCost != null && !this.itemCost.isEmpty()) { itemData.set("items." + this.configName + ".commands-item", this.itemCost); }
		if (this.cost != null && this.cost != 0) { itemData.set("items." + this.configName + ".commands-cost", this.cost); }
		if (this.commandsReceive != null && this.commandsReceive != 0) { itemData.set("items." + this.configName + ".commands-receive", this.commandsReceive); }
		if (this.warmDelay != null && this.warmDelay != 0) { itemData.set("items." + this.configName + ".commands-warmup", this.warmDelay); }
		if (this.cooldownSeconds != null && this.cooldownSeconds != 0) { itemData.set("items." + this.configName + ".commands-cooldown", this.cooldownSeconds); }
		if (this.cooldownMessage != null && !this.cooldownMessage.isEmpty()) { itemData.set("items." + this.configName + ".cooldown-message", this.cooldownMessage); }
		if (this.toggleMessage != null && !this.toggleMessage.isEmpty()) { itemData.set("items." + this.configName + ".toggle-message", this.toggleMessage); }
		if (this.enchants != null && !this.enchants.isEmpty()) { 
			String enchantList = "";
			for (Entry<String, Integer> enchantments : this.enchants.entrySet()) { enchantList += enchantments.getKey() + ":" + enchantments.getValue() + ", "; }
			itemData.set("items." + this.configName + ".enchantment", enchantList.substring(0, enchantList.length() - 2)); 
		}
		if (this.fireworkType != null) { itemData.set("items." + this.configName + ".firework.type", this.fireworkType.name()); }
		if (this.power != null && this.power != 0) { itemData.set("items." + this.configName + ".firework.power", this.power); }
		if (this.fireworkFlicker) { itemData.set("items." + this.configName + ".firework.flicker", this.fireworkFlicker); }
		if (this.fireworkTrail) { itemData.set("items." + this.configName + ".firework.trail", this.fireworkTrail); }
		if (this.fireworkColor != null && !this.fireworkColor.isEmpty()) { 
			String colorList = "";
			for (DyeColor color : this.fireworkColor) { colorList += color.name() + ", "; }
			itemData.set("items." + this.configName + ".firework.colors", colorList.substring(0, colorList.length() - 2)); 
		}
		if (this.interactCooldown != null && this.interactCooldown != 0) { itemData.set("items." + this.configName + ".use-cooldown", this.interactCooldown); }
		if (this.teleportEffect != null && !this.teleportEffect.isEmpty()) { itemData.set("items." + this.configName + ".teleport-effect", this.teleportEffect); }
		if (this.teleportSound != null && !this.teleportSound.isEmpty()) { itemData.set("items." + this.configName + ".teleport-sound", this.teleportSound + ((this.teleportSoundVolume != 1.0 && this.teleportSoundPitch != 1.0) ? ":" + this.teleportSoundVolume + ":" + this.teleportSoundPitch : "")); }
		if (this.itemflags != null && !this.itemflags.isEmpty()) { itemData.set("items." + this.configName + ".itemflags", this.itemflags); }
		if (this.triggers != null && !this.triggers.isEmpty()) { itemData.set("items." + this.configName + ".triggers", this.triggers); }
		if (this.limitModes != null && !this.limitModes.isEmpty()) { itemData.set("items." + this.configName + ".limit-modes", this.limitModes); }
		if (this.toggleNode != null && !this.toggleNode.isEmpty()) { itemData.set("items." + this.configName + ".toggle-permission", this.toggleNode); }
		if (this.permissionNode != null && !this.permissionNode.isEmpty()) { itemData.set("items." + this.configName + ".permission-node", this.permissionNode); }
		if (this.leatherColor != null && !this.leatherColor.isEmpty()) { itemData.set("items." + this.configName + ".leather-color", this.leatherColor); }
		else if (this.leatherHex != null && !this.leatherHex.isEmpty()) { itemData.set("items." + this.configName + ".leather-color", this.leatherHex); }
		if (this.customMapImage != null && !this.customMapImage.isEmpty()) { itemData.set("items." + this.configName + ".custom-map-image", this.customMapImage); }
		if (this.mapId != -1) { itemData.set("items." + this.configName + ".map-id", this.mapId); }
		if (this.skullTexture != null && !this.skullTexture.isEmpty() && (this.dynamicTextures == null || this.dynamicTextures.isEmpty())) { itemData.set("items." + this.configName + ".skull-texture", this.skullTexture); }
		else if (this.dynamicTextures != null && !this.dynamicTextures.isEmpty()) { 
			for (int i = 0; i < this.dynamicTextures.size(); i++) {
				itemData.set("items." + this.configName + ".skull-texture." + (i + 1), this.dynamicTextures.get(i)); 	
			}
		}
		if (this.skullOwner != null && !this.skullOwner.isEmpty()&& (this.dynamicOwners == null || this.dynamicOwners.isEmpty())) { itemData.set("items." + this.configName + ".skull-owner", this.skullOwner); }
		else if (this.dynamicOwners != null && !this.dynamicOwners.isEmpty()) { 
			for (int i = 0; i < this.dynamicOwners.size(); i++) {
				itemData.set("items." + this.configName + ".skull-owner." + (i + 1), this.dynamicOwners.get(i)); 	
			}
		}
		if (this.chargeColor != null) { itemData.set("items." + this.configName + ".charge-color", this.chargeColor.name()); }
		if (this.bannerPatterns != null && !this.bannerPatterns.isEmpty()) { 
			String bannerList = "";
			for (Pattern pattern : this.bannerPatterns) { bannerList += pattern.getColor().name() + pattern.getPattern().name() + ", "; }
			itemData.set("items." + this.configName + ".banner-meta", bannerList.substring(0, bannerList.length() - 2)); 
		}
		if (this.recipe != null && !this.recipe.isEmpty() && this.ingredients != null && !this.ingredients.isEmpty()) {
			List<String> ingredientList = new ArrayList<String>();
			List<String> recipeTempList = new ArrayList<String>();
			List<String> recipeList = new ArrayList<String>();
			for (Character ingredient: this.ingredients.keySet()) { 
				ingredientList.add(ingredient + ":" + this.ingredients.get(ingredient).toString());
			}
			String recipeLine = "";
			for (Character recipeCharacter: this.recipe) {
				recipeLine += recipeCharacter;
				if (StringUtils.countCharacters(recipeLine) == 3) {
					recipeTempList.add(recipeLine);
					recipeLine = "";
				}
			}
			if (!recipeLine.isEmpty()) { 
				while (StringUtils.countCharacters(recipeTempList.get(0)) != StringUtils.countCharacters(recipeLine)) { recipeLine += "X"; }
				recipeTempList.add(recipeLine);  
			}
			for (String str: this.trimRecipe(recipeTempList)) { recipeList.add(str.replace(" ", "X")); }
			itemData.set("items." + this.configName + ".recipe", recipeList);
			itemData.set("items." + this.configName + ".ingredients", ingredientList);
		}
		if (this.mobsDrop()) {
			List<String> mobsList = new ArrayList<String>();
			for (EntityType mobs: this.mobsDrop.keySet()) { 
				mobsList.add(mobs.name() + ":" + this.mobsDrop.get(mobs).toString());
			}
			itemData.set("items." + this.configName + ".mobs-drop", mobsList);
		}
		if (this.blocksDrop()) {
			List<String> blocksList = new ArrayList<String>();
			for (Material blocks: this.blocksDrop.keySet()) { 
				blocksList.add(blocks.name() + ":" + this.blocksDrop.get(blocks).toString());
			}
			itemData.set("items." + this.configName + ".blocks-drop", blocksList);
		}
		if (this.effect != null && !this.effect.isEmpty()) { 
			String effectList = "";
			for (PotionEffect effects : this.effect) { effectList += effects.getType().getName() + ":" + effects.getAmplifier() + ":" + effects.getDuration() + ", "; }
			itemData.set("items." + this.configName + ".potion-effects", effectList.substring(0, effectList.length() - 2)); 
		}
		if (this.attributes != null && !this.attributes.isEmpty()) { 
			String attributeList = "";
			for (String attribute : this.attributes.keySet()) { attributeList += "{" + attribute + ":" + this.attributes.get(attribute) + "}, "; }
			itemData.set("items." + this.configName + ".attributes", attributeList.substring(0, attributeList.length() - 2)); 
		}
		if (this.contents != null && !this.contents.isEmpty()) { 
			itemData.set("items." + this.configName + ".contents", this.contents); 
		}
		if (this.nbtProperty != null && !this.nbtProperty.isEmpty()) { 
			String propertyList = "";
			for (String property : this.nbtProperty.keySet()) { propertyList += property + ":" + this.nbtProperty.get(property) + ", "; }
			itemData.set("items." + this.configName + ".properties", propertyList.substring(0, propertyList.length() - 2)); 
		}
		if (this.disposableConditions != null && !this.disposableConditions.isEmpty()) { 
			if (disposableConditions.size() == 1) {
				itemData.set("items." + this.configName + ".disposable-conditions", this.disposableConditions.get(0)); 
			} else if (triggerConditions.size() > 0) {
				itemData.set("items." + this.configName + ".disposable-conditions", this.disposableConditions); 
			}
		}
		if (this.disposableMessage != null && !this.disposableMessage.isEmpty()) { 
			itemData.set("items." + this.configName + ".disposable-fail-message", this.disposableMessage); 
		}
		if (this.triggerConditions != null && !this.triggerConditions.isEmpty()) { 
			if (triggerConditions.size() == 1) {
				itemData.set("items." + this.configName + ".trigger-conditions", this.triggerConditions.get(0)); 
			} else if (triggerConditions.size() > 0) {
				itemData.set("items." + this.configName + ".trigger-conditions", this.triggerConditions); 
			}
		}
		if (this.triggerMessage != null && !this.triggerMessage.isEmpty()) { 
			itemData.set("items." + this.configName + ".trigger-fail-message", this.triggerMessage); 
		}
		if (this.commandConditions != null && !this.commandConditions.isEmpty()) { 
			for (String property : this.commandConditions.keySet()) {
				if (this.commandConditions.get(property).size() == 1) {
					itemData.set("items." + this.configName + property + "-conditions", this.commandConditions.get(property).get(0)); 
				} else if (this.commandConditions.get(property).size() > 0) {
					itemData.set("items." + this.configName + property + "-conditions", this.commandConditions.get(property)); 
				}
			}
		}
		if (this.commandMessages != null && !this.commandMessages.isEmpty()) { 
			for (String property : this.commandMessages.keySet()) {
				itemData.set("items." + this.configName + property + "-fail-message", this.commandMessages.get(property)); 
			}
		}
		if (this.enabledRegions != null && !this.enabledRegions.isEmpty()) { 
			String regionList = "";
			for (String region : this.enabledRegions) { regionList += region + ", "; }
			itemData.set("items." + this.configName + ".enabled-regions", regionList.substring(0, regionList.length() - 2)); 
		}
		if (this.enabledWorlds != null && !this.enabledWorlds.isEmpty()) { 
			String worldList = "";
			for (String world : this.enabledWorlds) { worldList += world + ", "; }
			if (!worldList.startsWith("ALL") && !worldList.startsWith("GLOBAL")) {
				itemData.set("items." + this.configName + ".enabled-worlds", worldList.substring(0, worldList.length() - 2)); 
			}
		}
		if (this.disabledWorlds != null && !this.disabledWorlds.isEmpty()) { 
			String worldList = "";
			for (String world : this.disabledWorlds) { worldList += world + ", "; }
			if (!worldList.startsWith("ALL") && !worldList.startsWith("GLOBAL")) {
				itemData.set("items." + this.configName + ".disabled-worlds", worldList.substring(0, worldList.length() - 2)); 
			}
		}
		try { itemData.save(itemFile); ConfigHandler.getConfig().getSource("items.yml"); ConfigHandler.getConfig().getFile("items.yml").options().copyDefaults(false); } 
		catch (Exception e) { ItemJoin.getInstance().getServer().getLogger().severe("Could not save the new custom item " + this.configName + " to the items.yml data file!"); ServerUtils.sendDebugTrace(e); }	
	}
	
   /**
    * Creates a Clone of the Current ItemMap instance.
    * 
    * @return The newly Cloned ItemMap instance.
    */
	public ItemMap clone() {
        try {
            Object clone = this.getClass().getDeclaredConstructor().newInstance();
	            for (Field field : this.getClass().getDeclaredFields()) {
	                field.setAccessible(true);
	                field.set(clone, field.get(this));
	            }
            return (ItemMap)clone;
        } catch(Exception e) { ServerUtils.sendDebugTrace(e); return this; }
    }
} public class ItemUtilities {
  	private List < ItemMap > items = new ArrayList < ItemMap >();
  	private List < ItemMap > craftingItems = new ArrayList < ItemMap >();
  	private List < ItemMap > protectItems = new ArrayList < ItemMap >();
	private HashMap <Integer, Integer> failCount = new HashMap <Integer, Integer> ();
	
	private static ItemUtilities utilities;

   /**
    * Checks if the specified itemflag and ItemStack is allowed.
    * 
    * @param player - The Player that is being allowed.
    * @param item - The ItemStack to check if it is allowed to perform the itemflag.
    * @param itemflag - The itemflag to be checked if it is allowed.
    */
	public boolean isAllowed(final Player player, final ItemStack item, final String itemflag) {
		if (player == null || item == null) { return true; }
		ItemMap itemMap = this.getItemMap(item, null, player.getWorld());
		if (itemMap != null && itemMap.isAllowedItem(player, item, itemflag)) {
			return false;
		}
		return true;
	}
	
   /**
    * Finds the matching ItemMap from the list of provided ItemMaps,
    * that has the exact same ItemStack and world or config node name defined.
    * 
    * @param itemStack - The ItemStack to have its ItemMap located.
    * @param configName - The config node name of the ItemMap.
    * @param world - The world of the ItemMap.
    */
	public ItemMap getItemMap(final ItemStack itemStack, final String configName, final World world) {
		for (ItemMap itemMap : this.getItems()) {
			if (world != null && configName == null && itemMap.inWorld(world) && itemMap.isSimilar(itemStack)) {
				return itemMap;
			} else if (configName != null && itemMap.getConfigName().equalsIgnoreCase(configName)) {
				return itemMap;
			}
		}
		return null;
	}
	
   /**
    * Finds the matching ItemMap from the list of provided ItemMaps,
    * that has the exact same slot defined.
    * 
    * @param slot - The slot that the ItemMap should have defined.
    * @param items - The list of ItemMap to be checked.
    * @return The ItemMap matching the specified slot.
    */
	public ItemMap getItemMap(final String slot, final List < ItemMap > items) {
		ItemMap itemMap = null;
		for (final ItemMap item: items) {
			if (item.getUISlot().equalsIgnoreCase(slot)) {
				itemMap = item;
				break;
			}
		}
		return itemMap;
	}
	
   /**
    * Closes the ItemAnimations for ALL Online Players.
    * 
    */
	public void closeAnimations() {
		PlayerHandler.forOnlinePlayers(player -> { this.closeAnimations(player); });
	}
	
   /**
    * Deletes the Toggle Commands registered for the server.
    * 
    */
	public void delToggleCommands() {
		for (ItemMap item : this.getItems()) {
			item.delToggleCommands();
		}
	}
	
   /**
    * Closes the ItemAnimations for the specified Player.
    * 
    * @param player - The Player that is having their item animations closed.
    */
	public void closeAnimations(final Player player) {
		for (ItemMap item : this.getItems()) {
			if (item.isAnimated() && item.getAnimationHandler().get(player) != null
					|| item.isDynamic() && item.getAnimationHandler().get(player) != null) {
				item.getAnimationHandler().get(player).closeAnimation(player);
				item.removeFromAnimationHandler(player);
			}
		}
	}
	
   /**
    * Updates the ItemMap List to fill the Player placeholders for ALL Online Players.
    * 
    */
	public void updateItems() {
		PlayerHandler.forOnlinePlayers(player -> { this.updateItems(player, true); });
	}
	
   /**
    * Updates the ItemMap List to fill the Player placeholders.
    * 
    * @param player - The Player that is having their items updated.
    * @param refresh - If the ItemAnimation should be restarted.
    */
	private void updateItems(final Player player, final boolean refresh) {
		for (ItemMap item: this.getItems()) {
			item.updateItem(player);
			if (refresh) {
				item.setAnimations(player);
			}
		}
	}
	
   /**
    * Checks if the Player is waiting Authentication from a plugin such as AuthMe. 
    * Then sets the item after Authentication is complete.
    * 
    * @param player - The Player that is being authenticated.
    * @param world - The World that the player is from.
    * @param type - The TriggerType that is being performed.
    * @param newMode - The GameMode of the Player.
    * @param region - The region the Player is in.
    */
	public void setAuthenticating(final Player player, final World world, TriggerType type, final GameMode newMode, final String region) {
		if (DependAPI.getDepends(false).authMeEnabled()) {
			new BukkitRunnable() {
				@Override
				public void run() {
					try { 
						final fr.xephi.authme.api.v3.AuthMeApi authMe = fr.xephi.authme.api.v3.AuthMeApi.getInstance();
						if (fr.xephi.authme.api.v3.AuthMeApi.getInstance().isAuthenticated(player) 
						|| (authMe.getPlugin().getConfig().getString("settings.registration.force") != null 
					    && !authMe.getPlugin().getConfig().getBoolean("settings.registration.force"))) {
							setItems(player, world, type, newMode, region);
							this.cancel();
						} else if (!player.isOnline()) {
							this.cancel();
						}
					} catch (NoClassDefFoundError e) {
						ServerUtils.logSevere("{ItemMap} You are using an outdated version of AuthMe, custom items will not be given after login.");
						this.cancel();
					}
				}
			}.runTaskTimer(ItemJoin.getInstance(), 0, 20);
		} else { 
			this.setItems(player, world, type, newMode, region);
		}
	}
	
   /**
    * Sets the items to be given.
    * 
    * @param player - The Player that is having their items set.
    * @param world - The World that the player is from.
    * @param type - The TriggerType that is being performed.
    * @param newMode - The GameMode of the Player.
    * @param region - The region the Player is in.
    */
	public void setItems(final Player player, final World world, final TriggerType type, final GameMode newMode, final String region) {
		this.safeSet(player, world, type, region);
		if (this.getItemDelay() != 0 && type != TriggerType.LIMIT_SWITCH && type != TriggerType.REGION_ENTER && type != TriggerType.REGION_LEAVE) { 
			SchedulerUtils.runLater(this.getItemDelay(), () -> {
				ItemHandler.restoreCraftItems(player, type); {
					this.handleItems(player, world, type, newMode, region);
				}
			});
		} else {
			ItemHandler.restoreCraftItems(player, type); {
				this.handleItems(player, world, type, newMode, region);
			}
		}
	}
	
   /**
    * Handles the item give and removal provided the trigger type.
    * 
    * @param player - The Player that is having their items handled.
    * @param type - The TriggerType that is being performed.
    * @param newMode - The GameMode of the Player.
    * @param region - The region the Player is in.
    */
	private void handleItems(final Player player, World world, final TriggerType type, final GameMode gameMode, final String region) {
		final ItemMap randomMap = ChanceAPI.getChances().getRandom(player);
		final int session = StringUtils.getRandom(1, 100000);
		if (type.equals(TriggerType.WORLD_SWITCH)) { world = player.getWorld(); }
		for (ItemMap item : this.getItems()) { 
			item.setAnimations(player);
			if (((((type.equals(TriggerType.JOIN) && item.isGiveOnJoin()) 
			  || (type.equals(TriggerType.RESPAWN) && (item.isGiveOnRespawn() || item.isDeathKeepable()))
			  || (type.equals(TriggerType.WORLD_SWITCH) && item.isGiveOnWorldSwitch())
			  || (type.equals(TriggerType.LIMIT_SWITCH) && item.isUseOnLimitSwitch())) && item.inWorld(world))
		      || ((((type.equals(TriggerType.REGION_ENTER) && (item.isGiveOnRegionEnter() || item.isGiveOnRegionAccess())) 
			  || (type.equals(TriggerType.REGION_LEAVE) && (item.isGiveOnRegionLeave() || item.isGiveOnRegionEgress()))) && item.inRegion(region))))
			   && item.isLimitMode(gameMode) && ChanceAPI.getChances().isProbability(item, randomMap) && item.conditionMet(player, "trigger-conditions")
			   && PlayerHandler.isEnabled(player, item.getConfigName()) && item.hasPermission(player, world) 
			   && this.isObtainable(player, item, session, type)) {
				item.giveTo(player); 
			} else if (((type.equals(TriggerType.LIMIT_SWITCH) && item.isUseOnLimitSwitch() && !item.isLimitMode(gameMode))
					|| (((type.equals(TriggerType.REGION_LEAVE) && item.isGiveOnRegionAccess()) || (type.equals(TriggerType.REGION_ENTER) && item.isGiveOnRegionEgress())) && item.inRegion(region)))
					&& item.hasItem(player, false)) {
				item.removeFrom(player);
			} else if (item.isAutoRemove() && (!item.inWorld(world) || !item.isLimitMode(gameMode)) && item.hasItem(player, true)) {
				item.removeFrom(player);
			}
		}
		this.sendFailCount(player, session);
		PlayerHandler.updateInventory(player, 15L);
	}
	
   /**
    * Safely checks and sets the items for their corresponding TriggerType.
    * 
    * @param player - The Player that is having their items set.
    * @param type - The TriggerType that is being performed.
    */
	private void safeSet(final Player player, final World world, final TriggerType type, final String region) {
		if (StringUtils.splitIgnoreCase(ConfigHandler.getConfig().getHotbarTriggers(), type.name, ",")) { PlayerHandler.setHotbarSlot(player, ConfigHandler.getConfig().getHotbarSlot()); }
		if (type.equals(TriggerType.REGION_LEAVE)) { DependAPI.getDepends(false).getGuard().pasteReturnItems(player, region); }
		if (type.equals(TriggerType.WORLD_SWITCH)) { this.pasteReturnItems(type, player, world.getName()); }
		if (type.equals(TriggerType.REGION_ENTER)) { this.clearEvent(type, player, "", region); }
		if (type.equals(TriggerType.QUIT)) { this.clearEvent(type, player, world.getName(), ""); }
		if (this.getClearDelay() != 0) {
			SchedulerUtils.runLater(this.getClearDelay(), () -> {
				if (type.equals(TriggerType.JOIN) || type.equals(TriggerType.WORLD_SWITCH)) {
					this.clearEvent(type, player, player.getWorld().getName(), "");
				}
				this.triggerCommands(player, type);
			});
		} else {
			if (type.equals(TriggerType.JOIN) || type.equals(TriggerType.WORLD_SWITCH) || type.equals(TriggerType.QUIT)) {
				this.clearEvent(type, player, player.getWorld().getName(), "");
			}
			this.triggerCommands(player, type);
		}
	}
	
   /**
    * Sets the Players items to be cleared upon performing the specified event.
    * 
    * @param type - The trigger type.
    * @param player - The Player performing the event.
    * @param world - The world the Player is in.
    * @param event - The event/trigger being performed.
    * @param region - The region the Player is in (if any).
    */
	private void clearEvent(final TriggerType type, final Player player, final String world, final String region) {
		String clearEvent = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items." + type.name);
		if (clearEvent != null && ((region != null && !region.isEmpty() && StringUtils.containsLocation(region, clearEvent.replace(" ", ""))) || StringUtils.containsLocation(world, clearEvent.replace(" ", "")))) {
			if ((StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options"), "PROTECT_OP") && player.isOp())
				|| (StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options"), "PROTECT_CREATIVE") && PlayerHandler.isCreativeMode(player))) {
			} else {
				String clearType = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type");
				if (clearType != null && (clearType.equalsIgnoreCase("ALL") || clearType.equalsIgnoreCase("GLOBAL"))) {
					this.clearItems(type, player, region, type.name, true);
				} else if (clearType != null && clearType.equalsIgnoreCase("ITEMJOIN")) {
					this.clearItems(type, player, region, type.name, false);
				} else if (clearType != null) {
					ServerUtils.logSevere("{ItemMap} " + clearType + " for Clear-Items in the config.yml is not a valid option.");
				}
			}
		}
	}
	
   /**
    * Clears the items from the Player Inventory.
    * 
    * @param type - The trigger type.
    * @param player - The Player performing the event.
    * @param event - The event/trigger being performed.
    * @param region - The region the Player is in (if any).
    * @param clearAll - If ALL items are expected to be cleared from the Player Inventory.
    */
	private void clearItems(final TriggerType type, final Player player, final String event, final String region, final boolean clearAll) {
		this.protectItems = this.getProtectItems();
		PlayerInventory inventory = player.getInventory();
		Inventory craftView = player.getOpenInventory().getTopInventory();
		DependAPI.getDepends(false).getGuard().saveReturnItems(player, event, region, craftView, inventory, true);
		this.saveReturnItems(type, player, player.getWorld().getName(), craftView, inventory, true);
		for (int i = 0; i < (!this.protectItems.isEmpty() ? this.protectItems.size() : 1); i++) {
			if (this.canClear(inventory.getHelmet(), "Helmet", i, clearAll)) {
				inventory.setHelmet(new ItemStack(Material.AIR));
			} if (this.canClear(inventory.getChestplate(), "Chestplate", i, clearAll)) {
				inventory.setChestplate(new ItemStack(Material.AIR));
			} if (this.canClear(inventory.getLeggings(), "Leggings", i, clearAll)) {
				inventory.setLeggings(new ItemStack(Material.AIR));
			} if (this.canClear(inventory.getBoots(), "Boots", i, clearAll)) {
				inventory.setBoots(new ItemStack(Material.AIR));
			} if (ServerUtils.hasSpecificUpdate("1_9") && this.canClear(inventory.getItemInOffHand(), "OffHand", i, clearAll)) {
				PlayerHandler.setOffHandItem(player, new ItemStack(Material.AIR));
			} if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				for (int k = 0; k < player.getOpenInventory().getTopInventory().getContents().length; k++) {
					if (this.canClear(player.getOpenInventory().getTopInventory().getItem(k), "CRAFTING[" + k + "]", i, clearAll)) {
						craftView.setItem(k, new ItemStack(Material.AIR));
					}
				}
			}
			for (int f = 0; f < inventory.getSize(); f++) {
				if (this.canClear(inventory.getItem(f), Integer.toString(f), i, clearAll)) {
					inventory.setItem(f, new ItemStack(Material.AIR));
				}
			}
		}
	}
	
   /**
    * Checks if the ItemStack is allowed to be cleared.
    * 
    * @param item - The ItemStack being checked.
    * @param slot - The slot the ItemStack is in.
    * @param i - The position in the cycle for protected items.
    * @param clearAll - If ALL items are expected to be cleared from the Player Inventory.
    * @return If the ItemStack is allowed.
    */
	public boolean canClear(final ItemStack item, final String slot, final int i, final boolean clearAll) {
		return item != null && !this.isBlacklisted(slot, item) && !this.isProtected(i, item) && (clearAll ? true : ItemHandler.containsNBTData(item));
	}
	
   /**
    * Checks if the ItemStack is blacklisted from being cleared.
    * 
    * @param item - The ItemStack being checked.
    * @param slot - The slot the ItemStack is in.
    * @return If the ItemStack is blacklisted.
    */
	private boolean isBlacklisted(String slot, ItemStack item) {
		String[] blacklist = null;
		String list = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Blacklist");
		if (list != null && list.contains("{") && list.contains("}")) { blacklist = list.split(","); }
		try {
			if (blacklist != null) {
				for (String value: blacklist) {
					String valType = (StringUtils.containsIgnoreCase(value, "{id") ? "id" : (StringUtils.containsIgnoreCase(value, "{slot") ? "slot" : (StringUtils.containsIgnoreCase(value, "{name") ? "name" : "")));
					String inputResult = org.apache.commons.lang.StringUtils.substringBetween(value, "{" + valType + ":", "}");
					if (valType.equalsIgnoreCase("id") && item.getType() == ItemHandler.getMaterial(inputResult.trim(), null)) {
						return true;
					} else if (valType.equalsIgnoreCase("slot") && slot.trim().equalsIgnoreCase(inputResult.trim())) {
						return true;
					} else if (valType.equalsIgnoreCase("name") && item.hasItemMeta() && item.getItemMeta().hasDisplayName()
						&& ChatColor.stripColor(item.getItemMeta().getDisplayName()).trim().equalsIgnoreCase(inputResult.trim())) {
						return true;
					}
				}
			}
		} catch (Exception e) {
			ServerUtils.logSevere("{ItemMap} It looks like the Blacklist section is missing quotations or apostrohes.");
			ServerUtils.logSevere("{ItemMap} Include quotations or apostrophes at the beginning and the end or this error will persist.");
			ServerUtils.logSevere("{ItemMap} The blacklist should look like '{id:DIAMOND}, {slot:0}' or \"{id:DIAMOND}, {slot:0}\".");
		}
		return false;
	}
	
   /**
    * Checks if the ItemMap is obtainable by the Player.
    * 
    * @param player - The Player that is trying to obtain the ItemMap.
    * @param itemMap - The ItemMap being checked.
    * @param session - The current set items session.
    * @param gamemode - The current GameMode of the Player.
    * @return If the ItemMap is Obtainable.
    */
	public boolean isObtainable(final Player player, final ItemMap itemMap, final int session, final TriggerType type) {
		if (!itemMap.hasItem(player, false) || itemMap.isAlwaysGive()) {
			DataObject firstJoin = (itemMap.isOnlyFirstLife() && type.equals(TriggerType.RESPAWN) || itemMap.isOnlyFirstJoin() ? SQL.getData().getData(new DataObject(Table.FIRST_JOIN, PlayerHandler.getPlayerID(player), "", itemMap.getConfigName())) : null);
			DataObject firstWorld = itemMap.isOnlyFirstWorld() ? SQL.getData().getData(new DataObject(Table.FIRST_WORLD, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName())) : null;
			DataObject ipLimit = itemMap.isIpLimted() ? SQL.getData().getData(new DataObject(Table.IP_LIMITS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName(), player.getAddress().getHostString())) : null;
			if ((firstJoin == null || (itemMap.isOnlyFirstLife() && type.equals(TriggerType.RESPAWN))) && firstWorld == null 
					&& (ipLimit == null || (ipLimit != null && ipLimit.getPlayerId().equalsIgnoreCase(PlayerHandler.getPlayerID(player)))) && this.canOverwrite(player, itemMap)) {
				return true;
			} else if (firstJoin == null && firstWorld == null && ipLimit == null) {
				if (session != 0 && this.failCount.get(session) != null) {
					this.failCount.put(session, this.failCount.get(session) + 1);
				} else if (session != 0) { this.failCount.put(session, 1); }
				ServerUtils.logDebug("{ItemMap} " + player.getName() + " has failed to receive item: " + itemMap.getConfigName() + ".");
				return false;
			} else { 
				if (firstJoin != null) { 
					ServerUtils.logDebug("{ItemMap} " + player.getName() + " has already received first-join " + itemMap.getConfigName() + ", they can no longer recieve this."); 
					return false;
				} else if (firstWorld != null) { 
					ServerUtils.logDebug("{ItemMap} " + player.getName() + " has already received first-world " + itemMap.getConfigName() + ", they can no longer recieve this in " + player.getWorld().getName() + "."); 
					return false;
				} else if (ipLimit != null && !ipLimit.getPlayerId().equalsIgnoreCase(PlayerHandler.getPlayerID(player))) { 
					ServerUtils.logDebug("{ItemMap} " + player.getName() + " has already received ip-limited " + itemMap.getConfigName() + ", they will only recieve this on their dedicated ip.");
					return false;
				}
			}
		}
		ServerUtils.logDebug("{ItemMap} " + player.getName() + " already has item: " + itemMap.getConfigName() + ".");
		return false;
	}
	
   /**
    * Checks if the ItemMap can overwrite itself.
    * 
    * @param player - The Player that is trying to overwrite the ItemMap.
    * @param itemMap - The ItemMap being checked.
    * @return If the ItemMap is Overwritable.
    */
	public boolean canOverwrite(final Player player, final ItemMap itemMap) {
		try {
			if ((itemMap.isCraftingItem() && StringUtils.getSlotConversion(itemMap.getSlot()) == 0) || this.isOverwritable(player, itemMap) || (itemMap.isDropFull() || ((itemMap.isGiveNext() || itemMap.isMoveNext()) && player.getInventory().firstEmpty() != -1))) { return true; }
		} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return false;
	}
	
   /**
    * Gets if the ItemMap can overwrite itself.
    * 
    * @param player - The Player that is trying to overwrite the ItemMap.
    * @param itemMap - The ItemMap being checked.
    * @return If the ItemMap is Overwritable.
    */
	private boolean isOverwritable(final Player player, final ItemMap itemMap) {
		try {
			String overWrite = ConfigHandler.getConfig().getFile("items.yml").getString("items-Overwrite");
			if (itemMap.isOverwritable() || (((overWrite == null || (overWrite != null && StringUtils.containsLocation(player.getWorld().getName(), overWrite.replace(" ", ""))))) 
					|| (ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Overwrite")))) {
				return true; 
			} else if (CustomSlot.ARBITRARY.isSlot(itemMap.getSlot()) && player.getInventory().firstEmpty() == -1) {
				return false;
			} else if (CustomSlot.HELMET.isSlot(itemMap.getSlot()) && player.getInventory().getHelmet() != null) {
				return false;
			} else if (CustomSlot.CHESTPLATE.isSlot(itemMap.getSlot()) && player.getInventory().getChestplate() != null) {
				return false;
			} else if (CustomSlot.LEGGINGS.isSlot(itemMap.getSlot()) && player.getInventory().getLeggings() != null) {
				return false;
			} else if (CustomSlot.BOOTS.isSlot(itemMap.getSlot()) && player.getInventory().getBoots() != null) {
				return false;
			} else if (ServerUtils.hasSpecificUpdate("1_9") && CustomSlot.OFFHAND.isSlot(itemMap.getSlot())) {
				if (player.getInventory().getItemInOffHand().getType() != Material.AIR) {
					return false;
				}
			} else if (StringUtils.isInt(itemMap.getSlot()) && player.getInventory().getItem(Integer.parseInt(itemMap.getSlot())) != null) {
				return false;
			}
		} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		return true;
	}
	
   /**
    * Sends the number of items that the Player failed to Obtain.
    * 
    * @param player - The Player that has failed to be given some items.
    * @param session - The current set items session.
    */
	public void sendFailCount(final Player player, final int session) {
		SchedulerUtils.run(() -> {
			if (this.failCount.get(session) != null && this.failCount.get(session) != 0) {
				String overWrite = ConfigHandler.getConfig().getFile("items.yml").getString("items-Overwrite");
				if ((overWrite != null && StringUtils.containsLocation(player.getWorld().getName(), overWrite.replace(" ", "")))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[7] = this.failCount.get(session).toString();
					LanguageAPI.getLang(false).sendLangMessage("general.failedInventory", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[7] = this.failCount.get(session).toString();
					LanguageAPI.getLang(false).sendLangMessage("general.failedOverwrite", player, placeHolders);
				}
				this.failCount.remove(session);
			}
		});
	}
	
   /**
    * Saves the current items in the Player Inventory to be returned later.
    * 
    * @param type - The trigger executed.
    * @param player - The Player that had their items saved.
    * @param world - The world to be checked.
    * @param type - The clear type that is being executed.
    * @param craftView - The players current CraftView.
    * @param inventory - The players current Inventory.
    * @param clearAll - If ALL items are being cleared.
    */
	public void saveReturnItems(final TriggerType type, final Player player, final String world, final Inventory craftView, final PlayerInventory inventory, final boolean clearAll) {
		boolean doReturn = StringUtils.splitIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options").replace(" ", ""), "RETURN_SWITCH", ",");
		List < ItemMap > protectItems = ItemUtilities.getUtilities().getProtectItems();
		if (type == TriggerType.WORLD_SWITCH && doReturn) {
			Inventory saveInventory = Bukkit.createInventory(null, 54);
			for (int i = 0; i <= 47; i++) {
				for (int k = 0; k < (!protectItems.isEmpty() ? protectItems.size() : 1); k++) {
					if (i <= 41 && inventory.getSize() >= i && ItemUtilities.getUtilities().canClear(inventory.getItem(i), String.valueOf(i), k, clearAll)) {
						saveInventory.setItem(i, inventory.getItem(i).clone());
					} else if (i >= 42 && ItemUtilities.getUtilities().canClear(craftView.getItem(i - 42), "CRAFTING[" + (i - 42) + "]", k, clearAll) && PlayerHandler.isCraftingInv(player.getOpenInventory())) {
						saveInventory.setItem(i, craftView.getItem(i - 42).clone());
					}
				}
			}
			SQL.getData().saveData(new DataObject(Table.RETURN_SWITCH_ITEMS, PlayerHandler.getPlayerID(player), world, ItemHandler.serializeInventory(saveInventory)));
		}
	}
	
   /**
    * Returns the previously removed Region Items to the Player.
    * 
    * @param type - The trigger executed.
    * @param player - The Player that had their items returned.
    * @param world - The world to be checked.
    */
	public void pasteReturnItems(final TriggerType type, final Player player, final String world) {
		if (type == TriggerType.WORLD_SWITCH && StringUtils.splitIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options").replace(" ", ""), "RETURN_SWITCH", ",")) {
			DataObject dataObject = SQL.getData().getData(new DataObject(Table.RETURN_SWITCH_ITEMS, PlayerHandler.getPlayerID(player), world, ""));
			Inventory inventory = (dataObject != null ? ItemHandler.deserializeInventory(dataObject.getInventory64().replace(world + ".", "")) : null);
			for (int i = 47; i >= 0; i--) {
				if (inventory != null && inventory.getItem(i) != null && inventory.getItem(i).getType() != Material.AIR) {
					if (i <= 41) {
						player.getInventory().setItem(i, inventory.getItem(i).clone());
					} else if (i >= 42 && PlayerHandler.isCraftingInv(player.getOpenInventory())) {
						player.getOpenInventory().getTopInventory().setItem(i - 42, inventory.getItem(i).clone());
						PlayerHandler.updateInventory(player, 1L);
					}
				}
				SQL.getData().removeData(new DataObject(Table.RETURN_SWITCH_ITEMS, PlayerHandler.getPlayerID(player), world, ""));
			}
		}
	}
	
   /**
    * Sets the ItemMap to the Player Inventory Slots.
    * 
    * @param player - The Player to have the ItemMap set to their Inventory slot(s).
    * @param itemMap - The ItemMap to be given to the Player.
    * @param size - The expected stack size of the item.
    */
	public void setInvSlots(final Player player, final ItemMap itemMap, final int size) {
		SchedulerUtils.run(() -> {
			boolean isGiven = false;
			ItemStack existingItem = ItemHandler.getItem(player, itemMap);
			ItemStack item = itemMap.getItem(player).clone();
			this.shiftItem(player, itemMap);
			int nextSlot = this.nextItem(player, itemMap);
			boolean overWrite = itemMap.isOverwritable() || ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Overwrite");
			if (size > 1) { item.setAmount(size); }
			if ((size > 1 || itemMap.isAlwaysGive()) && !overWrite && existingItem != null) {
				isGiven = true;
				player.getInventory().addItem(item);
			} else if (nextSlot != 0) {
				isGiven = true;
				player.getInventory().setItem(nextSlot, item);
			} else if (player.getInventory().firstEmpty() != -1 || overWrite) {
				if (itemMap.getSlot().contains("%")) {
					String slot = StringUtils.translateLayout(itemMap.getSlot(), player);
					if (StringUtils.isInt(slot)) {
						isGiven = true;
						player.getInventory().setItem(Integer.parseInt(slot), item);
					}
				} else {
					isGiven = true;
					player.getInventory().setItem(Integer.parseInt(itemMap.getSlot()), item);
				}
			} else if (itemMap.isDropFull()) { 
				isGiven = true;
				player.getWorld().dropItem(player.getLocation(), item);
			}
			if (isGiven) {
				ServerUtils.logDebug("{ItemMap} " + player.getName() + " has been given the item " + itemMap.getConfigName() + " in the world [" + player.getWorld().getName() + "].");
				DataObject ipLimit = SQL.getData().getData(new DataObject(Table.IP_LIMITS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName(), player.getAddress().getHostString()));
				if ((itemMap.isOnlyFirstJoin() || itemMap.isOnlyFirstLife())) { SQL.getData().saveData(new DataObject(Table.FIRST_JOIN, PlayerHandler.getPlayerID(player), "", itemMap.getConfigName())); }
				if (itemMap.isOnlyFirstWorld()) { SQL.getData().saveData(new DataObject(Table.FIRST_WORLD, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName())); }
				if (itemMap.isIpLimted() && ipLimit == null) { SQL.getData().saveData(new DataObject(Table.IP_LIMITS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName(), player.getAddress().getHostString())); }
			}
		});
	}
	
   /**
    * Sets the ItemMap to the Player Inventory Custom Slots.
    * 
    * @param player - The Player to have the ItemMap set to their Inventory slot(s).
    * @param itemMap - The ItemMap to be given to the Player.
    * @param size - The expected stack size of the item.
    */
	public void setCustomSlots(final Player player, final ItemMap itemMap, final int size) {
		SchedulerUtils.run(() -> {
			boolean isGiven = false;
			int craftSlot = StringUtils.getSlotConversion(itemMap.getSlot());
			ItemStack existingItem = ItemHandler.getItem(player, itemMap);
			ItemStack item = itemMap.getItem(player).clone();
			this.shiftItem(player, itemMap);
			int nextSlot = this.nextItem(player, itemMap);
			boolean overWrite = itemMap.isOverwritable() || ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Overwrite");
			if (size > 1) { item.setAmount(size); }
			if ((size > 1 || itemMap.isAlwaysGive()) && !overWrite && existingItem != null) {
				isGiven = true;
				player.getInventory().addItem(item);
			} else if (nextSlot != 0) {
				isGiven = true;
				player.getInventory().setItem(nextSlot, item);
			} else if (CustomSlot.ARBITRARY.isSlot(itemMap.getSlot()) && player.getInventory().firstEmpty() != -1) {
				isGiven = true;
				player.getInventory().addItem(item);
			} else if (CustomSlot.HELMET.isSlot(itemMap.getSlot()) && (existingItem == null || overWrite)) {
				isGiven = true;
				player.getEquipment().setHelmet(item);
			} else if (CustomSlot.CHESTPLATE.isSlot(itemMap.getSlot()) && (existingItem == null || overWrite)) {
				isGiven = true;
				player.getEquipment().setChestplate(item);
			} else if (CustomSlot.LEGGINGS.isSlot(itemMap.getSlot()) && (existingItem == null || overWrite)) {
				isGiven = true;
				player.getEquipment().setLeggings(item);
			} else if (CustomSlot.BOOTS.isSlot(itemMap.getSlot()) && (existingItem == null || overWrite)) {
				isGiven = true;
				player.getEquipment().setBoots(item);
			} else if (ServerUtils.hasSpecificUpdate("1_9") && CustomSlot.OFFHAND.isSlot(itemMap.getSlot()) && (existingItem == null || overWrite)) {
				isGiven = true;
				PlayerHandler.setOffHandItem(player, item);
			} else if (craftSlot != -1 && (existingItem == null || overWrite || craftSlot == 0)) {
				isGiven = true;
				SchedulerUtils.runLater(6L, () -> {
					this.setCraftingSlots(player, item, craftSlot, 240);
				});
			} else if (itemMap.isDropFull()) {
				isGiven = true;
				player.getWorld().dropItem(player.getLocation(), item);
			}
			if (isGiven) {
				ServerUtils.logDebug("{ItemMap} " + player.getName() + " has been given the item " + itemMap.getConfigName() + " in the world [" + player.getWorld().getName() + "].");
				DataObject ipLimit = SQL.getData().getData(new DataObject(Table.IP_LIMITS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName(), player.getAddress().getHostString()));
				if ((itemMap.isOnlyFirstJoin() || itemMap.isOnlyFirstLife())) { SQL.getData().saveData(new DataObject(Table.FIRST_JOIN, PlayerHandler.getPlayerID(player), "", itemMap.getConfigName())); }
				if (itemMap.isOnlyFirstWorld()) { SQL.getData().saveData(new DataObject(Table.FIRST_WORLD, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName())); }
				if (itemMap.isIpLimted() && ipLimit == null) { SQL.getData().saveData(new DataObject(Table.IP_LIMITS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), itemMap.getConfigName(), player.getAddress().getHostString())); }
			}
		});
	}
	
   /**
    * Sets the ItemStack to the Player Inventory Crafting Slots.
    * 
    * @param player - The Player to have the ItemStack set to their Crafting slot(s).
    * @param itemStack - The ItemStack to be given to the Player.
    * @param craftSlot - The designated slot for the Crafting Item.
    * @param attempts - The number of attempts to give the Crafting Slot item before failing.
    */
	private void setCraftingSlots(final Player player, final ItemStack itemStack, final int craftSlot, int attempts) {
		if (attempts != 0) {
			if (craftSlot == 0) {
				SchedulerUtils.runLater(2L, () -> {
					if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
						player.getOpenInventory().getTopInventory().setItem(craftSlot, itemStack);
						PlayerHandler.updateInventory(player, 1L);
					} else { 
						SchedulerUtils.runLater(20L, () -> this.setCraftingSlots(player, itemStack, craftSlot, (attempts - 1))); 
					}
				});
			} else if (PlayerHandler.isCraftingInv(player.getOpenInventory())) {
				if (player.getOpenInventory().getTopInventory().getItem(0) != null && !player.getOpenInventory().getTopInventory().getItem(0).getType().equals(Material.AIR)) {
					ItemHandler.returnCraftingItem(player, 0, player.getOpenInventory().getTopInventory().getItem(0).clone(), 0L);
				}
				player.getOpenInventory().getTopInventory().setItem(craftSlot, itemStack);
			} else { 		
				SchedulerUtils.runLater(20L, () -> this.setCraftingSlots(player, itemStack, craftSlot, (attempts - 1)));
			}
		}
	}
	
   /**
    * Moves any pre-exiting items in the players defined ItemMap slot to the next available slot.
    * 
    * @param player - The Player to have the ItemMap set to their Inventory slot(s).
    * @param itemMap - The ItemMap to be given to the Player.
    */
	public void shiftItem(final Player player, final ItemMap itemMap) {
		int i = 0; int k = 0;
		if (StringUtils.isInt(itemMap.getSlot())) { i = Integer.parseInt(itemMap.getSlot()); k = i; }
		else if (itemMap.getSlot().contains("%")) {
			String slot = StringUtils.translateLayout(itemMap.getSlot(), player);
			if (StringUtils.isInt(slot)) {
				i = Integer.parseInt(slot); k = i;
			}
		} 
		ItemStack existingItem = ItemHandler.getItem(player, itemMap);
		if (itemMap.isMoveNext() && existingItem != null && player.getInventory().firstEmpty() != -1) {
			for (i = 0; i <= 35; i++) {
				if (player.getInventory().getItem(i) == null || player.getInventory().getItem(i).getType() == Material.AIR) {
					player.getInventory().setItem(i, existingItem);
					existingItem.setAmount(0);
					existingItem.setType(Material.AIR);
					existingItem.setData(new ItemStack(Material.AIR).getData());
					return;
				} else if (i == 35) {
					for (k = 0; k >= 0; k--) {
						if (player.getInventory().getItem(k) == null || player.getInventory().getItem(k).getType() == Material.AIR) {
							player.getInventory().setItem(k, existingItem);
							existingItem.setAmount(0);
							existingItem.setType(Material.AIR);
							existingItem.setData(new ItemStack(Material.AIR).getData());
							return;
						}
					}
				}
			}
		}
	}
	
   /**
    * Gets the next available inventory slot from the defined ItemMap slot,
    * only if the give-next itemflag is defined.
    * 
    * @param player - The Player to have the ItemMap set to their Inventory slot(s).
    * @param itemMap - The ItemMap to be given to the Player.
    * @return The next available inventory slot.
    */
	public int nextItem(final Player player, final ItemMap itemMap) {
		int i = 0; int k = 0;
		if (StringUtils.isInt(itemMap.getSlot())) { i = Integer.parseInt(itemMap.getSlot()); k = i; }
		else if (itemMap.getSlot().contains("%")) {
			String slot = StringUtils.translateLayout(itemMap.getSlot(), player);
			if (StringUtils.isInt(slot)) {
				i = Integer.parseInt(slot); k = i;
			}
		} 
		ItemStack existingItem = ItemHandler.getItem(player, itemMap);
		if (itemMap.isGiveNext() && existingItem != null && player.getInventory().firstEmpty() != -1) {
			for (i = 0; i <= 35; i++) {
				if (player.getInventory().getItem(i) == null || player.getInventory().getItem(i).getType() == Material.AIR) {
					return i;
				} else if (i == 35) {
					for (k = 0; k >= 0; k--) {
						if (player.getInventory().getItem(k) == null || player.getInventory().getItem(k).getType() == Material.AIR) {
							return k;
						}
					}
				}
			}
		}
		return 0;
	}
	
   /**
    * Executes the Global Commands defined in the config.
    * 
    * @param player - The Player having the commands executed.
    */
	public void triggerCommands(final Player player, TriggerType trigger) {
		if ((ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds") != null && ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands") != null) 
				&& (!ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds").equalsIgnoreCase("DISABLED") || !ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds").equalsIgnoreCase("FALSE"))
				&& ((StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers"), TriggerType.JOIN.name) && trigger.equals(TriggerType.JOIN))
				|| (StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers"), TriggerType.FIRST_JOIN.name) && trigger.equals(TriggerType.FIRST_JOIN))
				|| (StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers"), TriggerType.WORLD_SWITCH.name) && trigger.equals(TriggerType.WORLD_SWITCH))
				|| (StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers"), TriggerType.RESPAWN.name) && trigger.equals(TriggerType.RESPAWN)))) {
			String commandsWorlds = ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds").replace(", ", ",");
			if (commandsWorlds == null) { commandsWorlds = "DISABLED"; }
			String[] compareWorlds = commandsWorlds.split(",");
			for (String compareWorld: compareWorlds) {
				if (compareWorld.equalsIgnoreCase(player.getWorld().getName()) || compareWorld.equalsIgnoreCase("ALL") || compareWorld.equalsIgnoreCase("GLOBAL")) {
					ArrayList < String > commandMap = new ArrayList < String >();
					for (String cmd : ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands")) { commandMap.add(cmd); }
					List<String> commandList = this.getRandomMap(commandMap, player);
					for (String commands: commandList) {
						String formatCommand = StringUtils.translateLayout(commands, player).replace("first-join: ", "").replace("first-join:", "");
						DataObject dataObject = SQL.getData().getData(new DataObject(Table.FIRST_COMMANDS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), formatCommand));
						if (!(dataObject != null && (StringUtils.containsIgnoreCase(commands, "first-join:") || StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers"), TriggerType.FIRST_JOIN.name)))) {
							Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), formatCommand);
							if (StringUtils.containsIgnoreCase(commands, "first-join:") || StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers"), TriggerType.FIRST_JOIN.name)) {
								SQL.getData().saveData(new DataObject(Table.FIRST_COMMANDS, PlayerHandler.getPlayerID(player), player.getWorld().getName(), formatCommand));
							}
						}
					}
					break;
				}
			}
		}
	}
	
   /**
    * Randomly Selected a Command Entry for a Single Command.
    * 
    * @param commands - The commands to have an entry randomly selected.
    * @param player - The Player having their commands randomly selected.
    * @return The newly generated ArrayList.
    */
    private List < String > getRandomMap(final ArrayList < String > commands, final Player player) {
    	final String commandSequence = ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.commands-sequence");
    	if (commandSequence != null && commandSequence.replace(" ", "").equalsIgnoreCase("RANDOM_SINGLE")) {
	    	String dedicatedMap = (String) StringUtils.randomEntry(commands);
	    	if (dedicatedMap != null && dedicatedMap != null && player != null) {
	    		List<String> returnList = new ArrayList<String>();
	    		returnList.add(dedicatedMap);
	    		return returnList;
	    	}
    	}
    	return ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands");
    }
	
   /**
    * Gets the ItemDelay.
    * 
    * @return The items-Delay that is to be expected before the items are given.
    */
	private long getItemDelay() {
		if ((this.getClearDelay() / 20) >= (ConfigHandler.getConfig().getFile("items.yml").getInt("items-Delay") / 2) && this.getClearDelay() != -1) { return this.getClearDelay() + 1; }
		return ConfigHandler.getConfig().getFile("items.yml").getInt("items-Delay") * 10L;
	}
	
   /**
    * Gets the Delay before clearing the items.
    * 
    * @return The clear-Delay before the items are cleared.
    */
	public long getClearDelay() {
		if (!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Join"), "DISABLED") 
				&& !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Join"), "FALSE")
				|| !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Quit"), "DISABLED")
				&& !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Quit"), "FALSE")
				|| !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.World-Switch"), "DISABLED")
				&& !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.World-Switch"), "FALSE")
				|| !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Region-Enter"), "DISABLED")
				&& !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Region-Enter"), "FALSE")) {
				return ConfigHandler.getConfig().getFile("config.yml").getInt("Clear-Items.Delay-Tick");
		}
		return -1;
	}
	
   /**
    * Checks the ItemStack to see if it is a protected item.
    * 
    * @param i - The position in the protectItems List when cycling.
    * @param item - The ItemStack being checked.
    * @return If the ItemStack is a protected ItemMap.
    */
	public boolean isProtected(final int i, final ItemStack item) {
			return !this.protectItems.isEmpty() && this.protectItems.get(i).isSimilar(item) && i == (this.protectItems.size() - 1);
	}
	
   /**
    * Gets the list of ItemMaps that should be protected from clearing.
    * 
    * @return The list of protected ItemMaps.
    */
	public List<ItemMap> getProtectItems() {
		List<ItemMap> protectItems = new ArrayList<ItemMap>();
		if (StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options"), "PROTECT")) {
			for (ItemMap item: this.getItems()) {
				if (item.isOnlyFirstJoin() || item.isOnlyFirstLife() || item.isOnlyFirstWorld()) {
					protectItems.add(item);
				}
			}
		}
		return protectItems;
	}
	
   /**
    * Clears any crafting recipes for the custom items.
    * 
    */
  	public void clearRecipes() {
  		List < Recipe > backupRecipes = new ArrayList < Recipe > ();
  		Iterator < Recipe > recipes = Bukkit.getServer().recipeIterator();
  		while (recipes.hasNext()) {
  			Recipe recipe = recipes.next();
  			ItemStack result = recipe.getResult();
  			boolean backupItem = true;
  			for (ItemMap itemMap: this.getItems()) {
  				if (itemMap.isSimilar(result) && !itemMap.getIngredients().isEmpty()) {
  					backupItem = false;
  				}
  			}
  			if (backupItem) { backupRecipes.add(recipe); }
  		}
  		Bukkit.getServer().clearRecipes();
  		for (Recipe recipe: backupRecipes) { try { Bukkit.getServer().addRecipe(recipe); } catch (IllegalStateException e) { } }
  	}
	
   /**
    * Creates a duplicate items HashMap.
    * 
    * @return The duplicated items HashMap.
    */
	public List < ItemMap > copyItems() {
		List < ItemMap > itemsCopy = new ArrayList < ItemMap > ();
		for (ItemMap itemMap : this.items) { 
			itemsCopy.add(itemMap.clone());
		}
		return itemsCopy;
	}
	
   /**
    * Adds a new item to the items List.
    * 
    * @param itemMap - The ItemMap to be added to the items List.
    */
	public void addItem(final ItemMap itemMap) {
		this.items.add(itemMap);
	}
	
   /**
    * Adds a new item to the crafting items List.
    * 
    * @param itemMap - The crafting ItemMap to be added to the items List.
    */
	public void addCraftingItem(final ItemMap itemMap) {
		if (itemMap.isCraftingItem()) { 
			this.craftingItems.add(itemMap); 
		}
	}
	
   /**
    * Gets the current ItemMap List.
    * 
    * @return The current ItemMap list.
    */
	public List < ItemMap > getItems() {
		return this.items;
	}
	
   /**
    * Gets the current crafting ItemMap List.
    * 
    * @return The current crafting ItemMap list.
    */
	public List < ItemMap > getCraftingItems() {
		return this.craftingItems;
	}

   /**
    * Clears the existing ItemMaps for the items List.
    * 
    */
	public void clearItems() {
		this.clearRecipes();
		this.items = new ArrayList < ItemMap >();
		this.craftingItems = new ArrayList < ItemMap >();
	}
	
   /**
    * Trigger types.
    * 
    */
	public enum CustomSlot {
		HELMET("Helmet"),
		CHESTPLATE("Chestplate"),
		LEGGINGS("Leggings"),
		BOOTS("Boots"),
		OFFHAND("Offhand"),
		CRAFTING("Crafting"),
		ARBITRARY("Arbitrary");
		private final String name;
		public boolean isSlot(String slot) { return this.name.equalsIgnoreCase(slot); }
		private CustomSlot(String name) { this.name = name; }
	}	
	
   /**
    * Trigger types.
    * 
    */
	public enum TriggerType {
		FIRST_JOIN("First-Join"),
		JOIN("Join"),
		QUIT("Quit"),
		RESPAWN("Respawn"),
		WORLD_SWITCH("World-Switch"),
		LIMIT_SWITCH("Limit-Modes"),
		REGION_ENTER("Region-Enter"),
		REGION_LEAVE("Region-Leave"),
		DEFAULT("DEFAULT");
		private final String name;
		private TriggerType(String name) { this.name = name; }
	}	
	
   /**
    * Gets the instance of the ItemUtilities.
    * 
    * @return The ItemUtilities instance.
    */
    public static ItemUtilities getUtilities() { 
        if (utilities == null) { utilities = new ItemUtilities(); }
        return utilities; 
    } 
} public class SchedulerUtils {
	
	private static List < Runnable > SINGLE_QUEUE = new ArrayList < Runnable > ();
	private static Boolean SINGLE_ACTIVE = false;

   /**
    * Runs the task on the main thread
    * @param runnable - The task to be performed.
    */
    public static void run(final Runnable runnable){
    	if (ItemJoin.getInstance().isEnabled()) {
    		Bukkit.getScheduler().runTask(ItemJoin.getInstance(), runnable);
    	}
    }
	
   /**
    * Runs the task on the main thread.
    * @param runnable - The task to be performed.
    * @param delay - The ticks to wait before performing the task.
    */
    public static void runLater(final long delay, final Runnable runnable) {
    	if (ItemJoin.getInstance().isEnabled()) {
    		Bukkit.getScheduler().runTaskLater(ItemJoin.getInstance(), runnable, delay);
    	}
    }
    
   /**
    * Runs the task repeating on the main thread.
    * @param runnable - The task to be performed.
    * @param delay - The ticks to wait before performing the task.
    * @param interval - The interval in which to run the task.
    * @return The repeating task identifier.
    */
    public static int runAsyncAtInterval(final long delay, final long interval, final Runnable runnable) {
    	if (ItemJoin.getInstance().isEnabled()) {
    		return Bukkit.getScheduler().runTaskTimerAsynchronously(ItemJoin.getInstance(), runnable, interval, delay).getTaskId();
    	}
    	return 0;
    }
    
   /**
    * Runs the task on another thread.
    * @param runnable - The task to be performed.
    */
    public static void runAsync(final Runnable runnable) {
    	if (ItemJoin.getInstance().isEnabled()) {
    		Bukkit.getScheduler().runTaskAsynchronously(ItemJoin.getInstance(), runnable);
    	}
    }

   /**
    * Runs the task on another thread.
    * @param runnable - The task to be performed.
    * @param delay - The ticks to wait before performing the task.
    */
    public static void runAsyncLater(final long delay, final Runnable runnable) {
    	if (ItemJoin.getInstance().isEnabled()) {
    		Bukkit.getScheduler().runTaskLaterAsynchronously(ItemJoin.getInstance(), runnable, delay);
    	}
    }
    
   /**
    * Runs the task timer on the another thread.
    * @param runnable - The task to be performed.
    * @param delay - The ticks to wait before performing the task.
    * @param interval - The interval in which to run the task.
    */
    public static void runAsyncTimer(final long delay, final long interval, final Runnable runnable) {
    	if (ItemJoin.getInstance().isEnabled()) {
    		Bukkit.getScheduler().runTaskTimerAsynchronously(ItemJoin.getInstance(), runnable, interval, delay);
    	}
    }
    
   /**
    * Runs the task on another thread without duplication.
    * @param runnable - The task to be performed.
    */
    public static void runSingleAsync(final Runnable runnable) {
    	SINGLE_QUEUE.add(runnable);
    	if (SINGLE_ACTIVE == false) { 
    		SINGLE_ACTIVE = true; {
    			cycleAsync();
    		}
    	}
    }
    
   /**
    * Runs the task on another thread without duplication.
    * 
    */
    public static void cycleAsync() {
    	if (ItemJoin.getInstance().isEnabled()) {
    		if (!SINGLE_QUEUE.isEmpty()) {
    			final Runnable runnable = SINGLE_QUEUE.get(0);
    			new BukkitRunnable() {
    				@Override
    				public void run() {
    					runnable.run(); {
    						SINGLE_QUEUE.remove(runnable); {
    							cycleAsync();
    						}
    					}
    				}
    			}.runTaskAsynchronously(ItemJoin.getInstance());
    		} else {
    			SINGLE_ACTIVE = false;
    		}
    	}
    }
} public class ServerUtils {
	
	private static String packageName = ItemJoin.getInstance().getServer().getClass().getPackage().getName();
	private static String serverVersion = packageName.substring(packageName.lastIndexOf('.') + 1).replace("_", "").replace("R0", "").replace("R1", "").replace("R2", "").replace("R3", "").replace("R4", "").replace("R5", "").replaceAll("[a-z]", "");
	private static String serverPreciseVersion = packageName.substring(packageName.lastIndexOf('.') + 1).replace("_", "").replace("R", "").replaceAll("[a-z]", "");
	private static List < String > errorStatements = new ArrayList < String > ();
	
   /**
    * Checks if the server is running the specified version.
    * 
    * @param versionString - The version to compare against the server version, example: '1_13'.
    * @return If the server version is greater than or equal to the specified version.
    */
	public static boolean hasSpecificUpdate(final String versionString) {
		if (Integer.parseInt(serverVersion) >= Integer.parseInt(versionString.replace("_", ""))) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if the server is running the specified version.
    * 
    * @param versionString - The version to compare against the server version, example: '1_13'.
    * @return If the server version is greater than or equal to the specified version.
    */
	public static boolean hasPreciseUpdate(final String versionString) {
		if (Integer.parseInt(serverPreciseVersion) >= Integer.parseInt(versionString.replace("_", ""))) {
			return true;
		}
		return false;
	}

   /**
    * Checks if the server supports UUIDS.
    *
    * @return If the server supports UUIDs.
    */
    public static boolean isUUIDCompatible() {
        return hasSpecificUpdate("1_8");
    }
    
   /**
    * Attempts to manually register a PluginCommands list for the plugin instance.
    *
    * @param commands - The PluginCommands to be registered.
    */
    public static void registerCommands(final List<PluginCommand> commands){
        try {
        	CommandMap commandMap = null;
            if (Bukkit.getPluginManager() instanceof SimplePluginManager) {
                Field f = SimplePluginManager.class.getDeclaredField("commandMap");
                f.setAccessible(true);
                commandMap = (CommandMap)f.get((Object)Bukkit.getPluginManager());
            } {
	            for (PluginCommand command : commands) {
	            	commandMap.register(ItemJoin.getInstance().getDescription().getName(), (Command)command);
	            }
            }
        } catch (Exception e) {
            ServerUtils.sendDebugTrace(e);
        }
    }
    
   /**
    * Attempts to manually unregister a PluginCommands list for the plugin instance.
    *
    * @param commands - The PluginCommands to be unregistered.
    */
    public static void unregisterCommands(final List<PluginCommand> commands) {
        Field commandMap = null;
        Field knownCommands = null;
        try {
        	if (Bukkit.getPluginManager() instanceof SimplePluginManager) {
	            commandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap");
	            commandMap.setAccessible(true);
	            knownCommands = SimpleCommandMap.class.getDeclaredField("knownCommands");
	            knownCommands.setAccessible(true);
        	} {
	            for (PluginCommand command : commands) {
		            ((Map<String, Command>) knownCommands.get((SimpleCommandMap) commandMap.get(Bukkit.getServer()))).remove(command.getName());
		            command.unregister((CommandMap) commandMap.get(Bukkit.getServer()));
	            }
        	}
        } catch (Exception e) {
        	ServerUtils.sendDebugTrace(e);
        }
    }
	
   /**
    * Sends a low priority log message as the plugin header.
    * 
    * @param message - The unformatted message text to be sent.
    */
	public static void logInfo(String message) {
		String prefix = "[ItemJoin] ";
		message = prefix + message;
		if (message.equalsIgnoreCase("") || message.isEmpty()) { message = ""; }
		Bukkit.getServer().getLogger().info(message);
	}
	
   /**
    * Sends a warning message as the plugin header.
    * 
    * @param message - The unformatted message text to be sent.
    */
	public static void logWarn(String message) {
		String prefix = "[ItemJoin_WARN] ";
		message = prefix + message;
		if (message.equalsIgnoreCase("") || message.isEmpty()) { message = ""; }
		Bukkit.getServer().getLogger().warning(message);
	}
	
   /**
    * Sends a developer warning message as the plugin header.
    * 
    * @param message - The unformatted message text to be sent.
    */
	public static void logDev(String message) {
		String prefix = "[ItemJoin_DEVELOPER] ";
		message = prefix + message;
		if (message.equalsIgnoreCase("") || message.isEmpty()) { message = ""; }
		Bukkit.getServer().getLogger().warning(message);
	}
	
   /**
    * Sends a error message as the plugin header.
    * 
    * @param message - The unformatted message text to be sent.
    */
	public static void logSevere(String message) {
		String prefix = "[ItemJoin_ERROR] ";
		if (message.equalsIgnoreCase("") || message.isEmpty()) { message = ""; }
		Bukkit.getServer().getLogger().severe(prefix + message);
		if (!errorStatements.contains(message)) { errorStatements.add(message); }
	}
	
   /**
    * Sends a debug message as a loggable warning as the plugin header.
    * 
    * @param message - The unformatted message text to be sent.
    */
	public static void logDebug(String message) {
		if (ConfigHandler.getConfig().debugEnabled()) {
			String prefix = "[ItemJoin_DEBUG] ";
			message = prefix + message;
			if (message.equalsIgnoreCase("") || message.isEmpty()) { message = ""; }
			Bukkit.getServer().getLogger().warning(message);
			Player player = PlayerHandler.getPlayerString("ad6e8c0e-6c47-4e7a-a23d-8a2266d7baee");
			if (player != null && player.isOnline()) {
				player.sendMessage(message);
			}
		}
	}

   /**
    * Sends the StackTrace of an Exception if debugging is enabled.
    * 
    * @param e - The exception to be sent.
    */
	public static void sendDebugTrace(final Exception e) {
		if (ConfigHandler.getConfig().debugEnabled()) { 
			e.printStackTrace(); 
			Player player = PlayerHandler.getPlayerString("ad6e8c0e-6c47-4e7a-a23d-8a2266d7baee");
			if (player != null && player.isOnline()) {
				player.sendMessage(e.toString());
			}
		}
	}
	
   /**
    * Sends the StackTrace of an Exception if it is Severe.
    * 
    * @param e - The exception to be sent.
    */
	public static void sendSevereTrace(final Exception e) {
		e.printStackTrace();
	}
	
   /**
    * Sends a chat message to the specified sender.
    * 
    * @param sender - The entity to have the message sent.
    * @param message - The unformatted message text to be sent.
    */
	public static void messageSender(final CommandSender sender, String message) {
		String prefix = "&7[&eItemJoin&7] ";
		message = prefix + message;
		message = ChatColor.translateAlternateColorCodes('&', message).toString();
		if (message.contains("blankmessage") || message.equalsIgnoreCase("") || message.isEmpty()) { message = ""; }
		if	(sender instanceof ConsoleCommandSender) { message = ChatColor.stripColor(message); }
		sender.sendMessage(message);
	}
	
   /**
    * Sends the current error statements to the online admins.
    * 
    * @param player - The Player to have the message sent.
    */
	public static void sendErrorStatements(final Player player) {
		if (player != null && player.isOp()) {
			SchedulerUtils.runLater(60L, () -> {
				for (String statement: errorStatements) {
					player.sendMessage(StringUtils.translateLayout("&7[&eItemJoin&7] &c" + statement, player));
				}
			});
		} else {
			for (String statement: errorStatements) {
				PlayerHandler.forOnlinePlayers(player_2 -> {
					if (player_2 != null && player_2.isOp()) {
						player_2.sendMessage(StringUtils.translateLayout("&7[&eItemJoin&7] &c" + statement, player_2));
					}
				});
			}
		}
	}
	
   /**
    * Clears the current error statements.
    * 
    */
	public static void clearErrorStatements() {
		errorStatements.clear();
	}
} public class ChanceAPI {
	private List < Chance > chances;
	private int sum;
	private Random random;
	
	private Map < ItemMap, Integer > probabilityItems = new HashMap < ItemMap, Integer > ();
	
	private static ChanceAPI chance;
	
   /**
    * Creates a new Chances instance.
    * 
    */
	public ChanceAPI() { }
	
   /**
    * Initializes the Chances instance.
    * 
    */
	public void newChance() {
		this.random = new Random();
		this.chances = new ArrayList < > ();
		this.sum = 0;
	}
	
   /**
    * Initializes the Chances instance.
    * 
    * @param seed - The random seed.
    */
	public void newChance(final long seed) {
		this.random = new Random(seed);
		this.chances = new ArrayList < > ();
		this.sum = 0;
	}
	
   /**
    * Adds an Object and its Chance to the pool of Objects to be randomly selected.
    * 
    * @param element - The Object to be selected.
    * @param chance - The Integer chance the Object has to be selected.
    */
	public void addChance(final Object element, final int chance) {
		if (!this.chances.contains(element)) {
			this.chances.add(new Chance(element, this.sum, this.sum + chance));
			this.sum += chance;
		}
	}
	
   /**
    * Gets a randomly selected Object.
    * 
    * @return The randomly selected Object.
    */
	public Object getRandomElement() {
		final int index = this.random.nextInt(this.sum);
		final List < Chance > chanceList = this.chances;
		final Iterator < Chance > itr = chanceList.iterator();
		while (itr.hasNext()) {
			final Chance chanceFound = itr.next();
			if (chanceFound != null && chanceFound.getLowerLimit() <= index && chanceFound.getUpperLimit() > index) {
				return chanceFound.getElement();
			}
		}
		return null;
	}
	
   /**
    * Gets the sum.
    * 
    * @return The options of the sum.
    */
	public int getOptions() {
		return this.sum;
	}
	
   /**
    * Gets the ItemMap and the Probability HashMap.
    * 
    * @return The ItemMaps and their Probabilities as a HashMap.
    */
	public Map<ItemMap, Integer> getItems() {
		return this.probabilityItems;
	}
	
   /**
    * Adds an ItemMap and its Probability to the HashMap pool.
    * 
    * @param itemMap - The ItemMap to be selected.
    * @param i - The chance the ItemMap has to be selected.
    */
	public void putItem(final ItemMap itemMap, final int i) {
		this.probabilityItems.put(itemMap, i);
	}
	
   /**
    * Checks if the ItemMap is a probability item.
    * 
    * @param itemMap - The ItemMap being checked.
    * @param probability - The Probability ItemMap being compared.
    * @return If the ItemMap is a probability item.
    */
	public boolean isProbability(final ItemMap itemMap, final ItemMap probability) {
		if ((probability != null && itemMap.getConfigName().equals(probability.getConfigName())) || itemMap.getProbability().equals(-1)) {
			return true;
		}
		return false;
	}
	
   /**
    * Selects a Random ItemMap from the list of Probability items.
    * 
    * @param player - The Player to have its Probability Item chosen.
    */
	public ItemMap getRandom(final Player player) {
		this.newChance();
		if (probabilityItems != null && !probabilityItems.isEmpty()) {
			for (ItemMap itemMap: probabilityItems.keySet()) {
				if (itemMap.hasItem(player, true)) { 
					return itemMap; 
				}
				if (probabilityItems.get(itemMap) != null) { 
					this.addChance(itemMap, probabilityItems.get(itemMap)); 
				}
			}
			return ((ItemMap) this.getRandomElement());
		}
		return null;
	}
	
   /**
    * Gets the instance of the Chances.
    * 
    * @return The Chances instance.
    */
    public static ChanceAPI getChances() { 
        if (chance == null) {
        	chance = new ChanceAPI(); 
        }
        return chance; 
    } 
	
   /**
    * The Chances class.
    * 
    */
	private class Chance {
		private int upperLimit;
		private int lowerLimit;
		private Object element;
		
	   /**
    	* Creates a new Chance instance.
    	* 
    	* @param element - The Object to be chosen.
    	* @param lowerLimit - The lowest probability. 
    	* @param upperLimit - The highest probability.
    	*/
		private Chance(final Object element, final int lowerLimit, final int upperLimit) {
			this.element = element;
			this.upperLimit = upperLimit;
			this.lowerLimit = lowerLimit;
		}
		
	   /**
    	* Gets the highest probability.
    	* 
    	* @return The highest probability.
    	*/
		private int getUpperLimit() { return this.upperLimit; }
		
	   /**
    	* Gets the lowest probability.
    	* 
    	* @return The lowest probability.
    	*/
		private int getLowerLimit() { return this.lowerLimit; }
		
	   /**
    	* Gets the Object to be chosen.
    	* 
    	* @return The Object to be chosen.
    	*/
		private Object getElement() { return this.element; }
		
	   /**
    	* Handles the toString of a Map Element.
    	* 
    	* @return The newly formatted Map Element as a String instance.
    	*/
		@Override
		public String toString() { return "[" + Integer.toString(this.lowerLimit) + "|" + Integer.toString(this.upperLimit) + "]: " + this.element.toString(); }
	}
} public class LanguageAPI {
	private Lang langType = Lang.ENGLISH;
	private String langPrefix = "ItemJoin";
	
    private static LanguageAPI lang;
	
   /**
    * Executes a Message to the Sender.
    * 
    * @param sender - The sender receiving the Message.
    * @param langMessage - The Message being sent.
    */
	public void dispatchMessage(final CommandSender sender, String langMessage) { 
		Player player = null; if (sender instanceof Player) { player = (Player) sender; }
		langMessage = StringUtils.translateLayout(langMessage, player);
		if (sender instanceof ConsoleCommandSender) { langMessage = ChatColor.stripColor(langMessage); } 
		sender.sendMessage(langMessage);
	}
	
   /**
    * Executes a Message to the Sender.
    * 
    * @param sender - The sender receiving the Message.
    * @param langMessage - The Message being sent.
    * @param hoverMessage - The Hoverable Message being attached to langMessage.
    * @param clickMessage - The Clicked Message being attached to langMessage.
    */
	public void dispatchMessage(final CommandSender sender, String langMessage, String hoverMessage, String clickMessage, final ClickAction action) { 
		Player player = null; if (sender instanceof Player) { player = (Player) sender; }
		langMessage = StringUtils.translateLayout(langMessage, player);
		hoverMessage = (hoverMessage != null ? StringUtils.translateLayout(hoverMessage, player) : null);
		clickMessage = (clickMessage != null ? StringUtils.translateLayout(clickMessage, player) : null);
		if (sender instanceof ConsoleCommandSender) { 
			langMessage = ChatColor.stripColor(langMessage); 
			sender.sendMessage(langMessage);
		} else if (ServerUtils.hasSpecificUpdate("1_8")) {
			TextSection textComponent = ChatComponent.of(langMessage);
			if (hoverMessage != null) {
				TextSection.HoverEvent hoverEvent = new TextSection.HoverEvent(ChatComponent.of(hoverMessage));
				textComponent.hoverEvent(hoverEvent);
			}
			if (clickMessage != null) {
				ClickEvent clickEvent = new ClickEvent();
				clickEvent.action(action);
				clickEvent.click(clickMessage);
				textComponent.clickEvent(clickEvent);
			}
			ChatComponent.sendTo(textComponent, player);
		} else {
			sender.sendMessage(langMessage);
		}
	}
	
   /**
    * Executes a Lang Message for the Sender.
    * 
    * @param nodeLocation - The String location of the Language Message. 
    * @param sender - The Sender who will receive the Message. 
    * @param placeHolder - Placeholders to be placed into the Langugage Message.
    */
	public void sendLangMessage(final String nodeLocation, final CommandSender sender, final String...placeHolder) {
		Player player = null; if (sender instanceof Player) { player = (Player) sender; }
		String langMessage = (sender.isPermissionSet("itemjoin.lang." + nodeLocation) ? sender.hasPermission("itemjoin.lang." + nodeLocation) ? this.getLangMessage(nodeLocation) : null : this.getLangMessage(nodeLocation));
		if (langMessage != null && !langMessage.isEmpty()) {
			langMessage = this.translateLangHolders(langMessage, this.initializeRows(placeHolder));
			langMessage = StringUtils.translateLayout(langMessage, player).replace(" \\n ", " \\n").replace(" /n ", " \\n").replace(" /n", " \\n");
			String[] langLines = langMessage.split(Pattern.quote(" \\" + "n"));
			for (String langLine : langLines) {
				String langStrip = langLine;
				if (sender instanceof ConsoleCommandSender) { langStrip = ChatColor.stripColor(langStrip); } 
				if (this.isConsoleMessage(nodeLocation)) { ServerUtils.logInfo(ChatColor.stripColor(langLine)); }
				else { sender.sendMessage(langStrip);	}
			}
		}
	}
	
   /**
    * Gets the lang message at the node location.
    * 
    * @param nodeLocation - The String location of the Language Message. 
    */
	public String getLangMessage(final String nodeLocation) {
		String message = ConfigHandler.getConfig().getFile(this.langType.nodeLocation()).getString(nodeLocation);
		return (message != null && message.isEmpty() ? null : message);
	}
	
   /**
    * Initializes the Placeholders for the Lang Message.
    * 
    * @param placeHolder - Placeholders to be placed into the Langugage Message.
    */
	private String[] initializeRows(final String...placeHolder) {
		if (placeHolder == null || placeHolder.length != this.newString().length) {
			String[] langHolder = this.newString();
			for (int i = 0; i < langHolder.length; i++) {
				langHolder[i] = "&lnull";
			}
			return langHolder;
		} else {
			String[] langHolder = placeHolder;
			for (int i = 0; i < langHolder.length; i++) {
				if (langHolder[i] == null) {
					langHolder[i] = "&lnull";
				}
			}
			return langHolder;
		}
	}
	
   /**
    * Translates the Language PlaceHolders into the actual Placeholders defined for the Message.
    * 
    * @param langMessage - The Message being sent.
    * @param langHolder - Placeholders to be placed into the Langugage Message.
    */
	private String translateLangHolders(final String langMessage, final String...langHolder) {
		return langMessage
				.replace("%world%", langHolder[0])
				.replace("%target_player%", langHolder[1])
				.replace("%target_player_world%", langHolder[2])
				.replace("%item%", langHolder[3])
				.replace("%item_type%", langHolder[4])
				.replace("%balance%", langHolder[5])
				.replace("%cost%", langHolder[6])
				.replace("%fail_count%", langHolder[7])
				.replace("%command%", langHolder[9])
				.replace("%purge_data%", langHolder[10])
				.replace("%amount%", langHolder[11])
				.replace("%players%", langHolder[12])
				.replace("%time_left%", langHolder[13])
				.replace("%input_example%", langHolder[15])
				.replace("%input%", langHolder[16])
				.replace("%item_slot%", langHolder[17])
				.replace("%item_permission%", langHolder[18])
				.replace("%prefix%", this.langPrefix);
		
	}
	
   /**
    * Checks if the Language Message is a Console Message.
    * 
    * @param nodeLocation - The String location of the Language Message.
    * @return If the Language Message is a Console Message.
    */
	private boolean isConsoleMessage(final String nodeLocation) {
		if (nodeLocation.equalsIgnoreCase("Commands.Updates.checking") 
				|| nodeLocation.equalsIgnoreCase("Commands.Updates.forcing")) {
			return true;
		}
		return false;
	}
	
   /**
    * Creates a new String Array for langHolders.
    * 
    * @return The new String Array.
    */
	public String[] newString() {
		return new String[20];
	}
	
   /**
    * Gets the current Language that is being translated.
    * 
    * @return The Language.
    */
	public String getLanguage() {
		return this.langType.name().substring(0, 1).toUpperCase() + this.langType.name().substring(1).toLowerCase();
	}
	
   /**
    * Gets the current Language File name.
    * 
    * @return The Language File name.
    */
	public String getFile() {
		return this.langType.nodeLocation();
	}
	
   /**
    * Sets the Language Prefix
    * 
    */
	public void setPrefix() {
		this.langPrefix = StringUtils.colorFormat(ConfigHandler.getConfig().getFile(this.langType.nodeLocation()).getString("Prefix"));
	}
	
   /**
    * Sets the current Language.
    * 
    * @param lang - The Language to be set.
    */
	public void setLanguage(final String lang) {
		if (lang.equalsIgnoreCase("tw")) {
			this.langType = Lang.TWCHINESE;
		} else if (lang.equalsIgnoreCase("cn")) {
			this.langType = Lang.CNCHINESE;
		} else if (lang.equalsIgnoreCase("en")) {
			this.langType = Lang.ENGLISH;
		} else if (lang.equalsIgnoreCase("es")) {
			this.langType = Lang.SPANISH;
		} else if (lang.equalsIgnoreCase("ru")) {
			this.langType = Lang.RUSSIAN;
		} else if (lang.equalsIgnoreCase("fr")) {
			this.langType = Lang.FRENCH;
		} else if (lang.equalsIgnoreCase("nl")) {
			this.langType = Lang.DUTCH;
		}
	}
	
   /**
    * Gets the current Language from the config and saves it to memory.
    * 
    */
	public void langFile() {
		String lang = ConfigHandler.getConfig().getFile("config.yml").getString("Language").replace(" ", "");
		if (lang.equalsIgnoreCase("TraditionalChinese") || lang.equalsIgnoreCase("TwChinese")) { this.setLanguage("tw"); } 
		else if (lang.equalsIgnoreCase("SimplifiedChinese") || lang.equalsIgnoreCase("CnChinese") || lang.equalsIgnoreCase("Chinese")) { this.setLanguage("cn"); } 
		else if (StringUtils.containsIgnoreCase(lang, "Chinese")) { this.setLanguage("cn"); } 
		else if (lang.equalsIgnoreCase("Spanish")) { this.setLanguage("es"); } 
		else if (lang.equalsIgnoreCase("Russian")) { this.setLanguage("ru"); } 
		else if (lang.equalsIgnoreCase("French")) { this.setLanguage("fr"); } 
		else if (lang.equalsIgnoreCase("Dutch")) { this.setLanguage("nl"); } 
		else { this.setLanguage("en"); }
	}
	
   /**
	* Defines the Lang type for the Language.
	* 
	*/
	private enum Lang {
		DEFAULT("en-lang.yml", 0), ENGLISH("en-lang.yml", 1), SPANISH("es-lang.yml", 2), TWCHINESE("tw-lang.yml", 3), CNCHINESE("cn-lang.yml", 4), RUSSIAN("ru-lang.yml", 5), FRENCH("fr-lang.yml", 6), DUTCH("nl-lang.yml", 7);
		private Lang(final String nodeLocation, final int i) { this.nodeLocation = nodeLocation; }
		private final String nodeLocation;
		private String nodeLocation() { return nodeLocation; }
	}
	
   /**
    * Gets the instance of the Language.
    * 
    * @param regen - If the instance should be regenerated.
    * @return The Language instance.
    */
    public static LanguageAPI getLang(final boolean regen) { 
        if (lang == null || regen) {
        	lang = new LanguageAPI();
        	lang.langFile();
        }
        return lang; 
    } 
} @SuppressWarnings("deprecation")
public class LegacyAPI {
	
	private static boolean legacyMaterial = false;
	
   /**
    * Updates the Players Inventory.
    * 
    * @param player - The Player to have their Inventory updated.
    */
    public static void updateInventory(final Player player) {
    	player.updateInventory();
    }
    
   /**
    * Gets the ItemStack in the Players Hand.
    * 
    * @param player - The Player to have its ItemStack found.
    * @return The found ItemStack.
    */
    public static ItemStack getInHandItem(final Player player) {
    	return player.getInventory().getItemInHand();
    }
    
   /**
    * Sets the ItemStack to the Players Hand.
    * 
    * @param player - The Player to have the ItemStack given.
    * @param item - The ItemStack to be set to the Players Hand.
    */
    public static void setInHandItem(final Player player, final ItemStack item) {
    	player.setItemInHand(item);
    }
	
   /**
    * Creates a new ItemStack.
    * 
    * @param material - The Material to be set to the ItemStack.
    * @param count - The ItemStack size.
    * @param dataValue - The Data Value to set to the ItemStack.
    * @return The new ItemStack.
    */
    public static ItemStack newItemStack(final Material material, final int count, final short dataValue) {
    	return new ItemStack(material, count, dataValue);
    }
    
   /**
    * Gets the GameRule for the World.
    * 
    * @param world - The world being referenced.
    * @param gamerule - The gamerule to locate.
    * @return The boolean value fo the gamerule.
    */
    public static boolean getGameRule(final World world, final String gamerule) {
    	String value = world.getGameRuleValue(gamerule);
    	return (value != null && !value.isEmpty() ? Boolean.valueOf(value) : false);
    }
    
   /**
    * Creates a new ShapedRecipe.
    * 
    * @param item - The ItemStack to be crafted.
    * @return The new ShapedRecipe.
    */
    public static ShapedRecipe newShapedRecipe(final ItemStack item) {
    	return new ShapedRecipe(item);
    }

   /**
    * Matches the Material from its Bukkit Material and Data Value.
    * 
    * @param typeID - The ID of the Material to be fetched.
    * @param dataValue - The Data value to be matched.
    * @return The found Bukkit Material.
    */
    public static org.bukkit.Material getMaterial(final int typeID, final byte dataValue) {
        initializeLegacy();
		return ItemJoin.getInstance().getServer().getUnsafe().fromLegacy(new org.bukkit.material.MaterialData(findMaterial(typeID), dataValue));
    }
    
   /**
    * Matches the Material from its Bukkit Material and Data Value.
    * 
    * @param material - The Material to be matched.
    * @param dataValue - The Data value to be matched.
    * @return The found Bukkit Material.
    */
    public static org.bukkit.Material getMaterial(final Material material, final byte dataValue) {
        initializeLegacy();
  		return ItemJoin.getInstance().getServer().getUnsafe().fromLegacy(new org.bukkit.material.MaterialData(material, dataValue));
    }
    
   /**
    * Gets the Material from its corresponding ID.
    * 
    * @param typeID - The ID of the Material to be fetched.
    * @return The found Bukkit Material.
    */
    public static org.bukkit.Material findMaterial(final int typeID) {
        final Material[] foundMaterial = new Material[1];
        EnumSet.allOf(Material.class).forEach(material -> { 
        	try { 
        		if (StringUtils.containsIgnoreCase(material.toString(), "LEGACY_") && material.getId() == typeID || !ServerUtils.hasSpecificUpdate("1_13") && material.getId() == typeID) {
        			try { 
        				initializeLegacy();
        			} catch (Exception e) { e.printStackTrace(); }
        			foundMaterial[0] = material; 
        		} 
        	} catch (Exception e) { }});
        return foundMaterial[0];
    }
    
   /**
    * Sends a info/debug message if the server is running Minecraft 1.13+ and is attempting to call a Legacy material.
    * 
    */
    private static void initializeLegacy() {
		if (ServerUtils.hasSpecificUpdate("1_13") && !legacyMaterial) {
			legacyMaterial = true;
			ServerUtils.logInfo("Initializing Legacy Material Support ..."); 
			ServerUtils.logDebug("Your items.yml has one or more item(s) containing a numerical id and/or data values."); 
			ServerUtils.logDebug("Minecraft 1.13 removed the use of these values, please change your items ids to reflect this change.");
			ServerUtils.logDebug("Your custom items will continue to function but the id set may not appear as expected.");
			ServerUtils.logDebug("If you believe this is a bug, please report it to the developer!"); 
			try {
				throw new Exception("Invalid usage of item id, this is not a bug!");
			} catch (Exception e) {
				ServerUtils.sendDebugTrace(e);
			}
		}
    }

   /**
    * Gets the ID of the specified Material.
    * 
    * @param material - The Material to have its ID fetched.
    * @return The ID of the Material.
    */
	public static int getMaterialID(final Material material) {
	    return material.getId();
	}
	
   /**
    * Gets the Durability from the ItemStack.
    * 
    * @param item - The ItemStack to have its durability fetched.
    * @return The Durability of the ItemStack.
    */
	public static short getDurability(final ItemStack item) {
		return item.getDurability();
	}
	
   /**
    * Sets the Durability to the ItemStack.
    * 
    * @param item - The ItemStack to have its Durability set.
    * @param durability - The Durability to be set to the ItemStack.
    * @return the newly set Durability on the ItemStack.
    */
	public static ItemStack setDurability(final ItemStack item, final short durability) {
		item.setDurability(durability);
		return item;
	}
	
   /**
    * Gets the Enchantments String name.
    * 
    * @param enchant - The Enchantment to have its String name fetched.
    * @return The Enchantments String name.
    */
	public static String getEnchantName(final org.bukkit.enchantments.Enchantment enchant) {
		return enchant.getName();
	}
	
   /**
    * Gets the Enchantment from its String name.
    * 
    * @param name - The String name of the Enchantment.
    * @return The found Enchantment.
    */
	public static org.bukkit.enchantments.Enchantment getEnchant(final String name) {
		return org.bukkit.enchantments.Enchantment.getByName(name.toUpperCase());
	}
	
   /**
    * Gets the current Skull Owner of the SkullMeta.
    * 
    * @param skullMeta - The SkullMeta to have its owner fetched.
    * @return The found Skull Owner.
    */
    public static String getSkullOwner(final org.bukkit.inventory.meta.SkullMeta skullMeta) {
    	return skullMeta.getOwner();
    }
	
   /**
    * Sets the owner to the SkullMeta.
    * 
    * @param skullMeta - The SkullMeta to have its owner set.
    * @param owner - The owner to be set to the SkullMeta.
    * @return The newly set SkullMeta.
    */
	public static org.bukkit.inventory.meta.ItemMeta setSkullOwner(final org.bukkit.inventory.meta.SkullMeta skullMeta, final String owner) {
		skullMeta.setOwner(owner);
		if (!ServerUtils.hasSpecificUpdate("1_13") && ServerUtils.hasSpecificUpdate("1_8")) {
			final Location loc = new Location(Bukkit.getWorlds().get(0), 200, 1, 200);
			final BlockState blockState = loc.getBlock().getState();
			try {
				loc.getBlock().setType(Material.valueOf("SKULL"));
				Skull skull = (Skull)loc.getBlock().getState();
				skull.setSkullType(SkullType.PLAYER);
				skull.setOwner(owner);
				skull.update();
				final String texture = ItemHandler.getSkullTexture(skull);
				if (texture != null && !texture.isEmpty()) {
					ItemHandler.setSkullTexture(skullMeta, texture);
				}
			} catch (Exception e) { }
			blockState.update(true);
		}
		return skullMeta;
	}
	
   /**
    * Gets the Bukkit Player from their String name.
    * 
    * @param playerName - The String name of the Bukkit Player.
    * @return The found Player.
    */
	public static Player getPlayer(final String playerName) {
		return Bukkit.getPlayer(playerName);
	}
	
   /**
    * Gets the Bukkit OfflinePlayer from their String name.
    * 
    * @param playerName - The String name of the Bukkit OfflinePlayer.
    * @return The found OfflinePlayer.
    */
	public static OfflinePlayer getOfflinePlayer(final String playerName) {
		return Bukkit.getOfflinePlayer(playerName);
	}
	
   /**
    * Sets the Map ID to the MapMeta.
    * 
    * @param meta - The MapMeta to have its Map ID set.
    * @param mapId - The Map ID to be set to the item.
    */
    public static org.bukkit.inventory.meta.MapMeta setMapID(final org.bukkit.inventory.meta.MapMeta meta, final int mapId) {
    	org.bukkit.inventory.meta.MapMeta mapmeta = meta;
    	mapmeta.setMapId(mapId);
    	return mapmeta; 
    }
	
   /**
    * Gets the ID from the MapView.
    * 
    * @param view - The MapView to have its ID fetched.
    * @return The ID of the MapView.
    */
    public static short getMapID(final org.bukkit.map.MapView view) {
    	try { 
    		return (short) view.getId();
    	} catch (Exception | NoSuchMethodError e) { 			
			try { 
				return (short) ReflectionUtils.getBukkitClass("map.MapView").getMethod("getId").invoke(view);
			} catch (Exception | NoSuchMethodError e2) { return 1; }
		}
    }
    
   /**
    * Gets the MapView from the specified ID.
    * 
    * @param id - The ID of the MapView to be fetched.
    * @return The Fetched MapView.
    */
    public static org.bukkit.map.MapView getMapView(final int id) {
    	try { 
    		return ItemJoin.getInstance().getServer().getMap((short) id); 
    	} catch (Exception | NoSuchMethodError e) { 
			try {
				return (org.bukkit.map.MapView)ReflectionUtils.getBukkitClass("Bukkit").getMethod("getMap", short.class).invoke(ReflectionUtils.getBukkitClass("map.MapView"), (short)id);
			} catch (Exception | NoSuchMethodError e2) { return null; }
		}
    }
    
   /**
    * Creates a MapView for the main Server World.
    * 
    * @return The new MapView.
    */
    public static org.bukkit.map.MapView createMapView() {
    	try {
    		return ItemJoin.getInstance().getServer().createMap(ItemJoin.getInstance().getServer().getWorlds().get(0));
    	} catch (Exception | NoSuchMethodError e) { return null; }
    }
    
   /**
    * Sets the Legacy Book Pages to the ItemStack.
    * 
    * @param player - The Player being used for placeholders.
    * @param meta - The ItemMeta to be updated.
    * @param pages - The book pages to be set.
    * @param itemMap - The ItemMap having their book pages set.
    * @warn Only to be used on server versions below 1.8.
    * @return The updated ItemMeta.
    */
	public static ItemMeta setBookPages(final Player player, final ItemMeta meta, final List<String> pages, final ItemMap itemMap) {
		return setPages(player, meta, pages, itemMap);
	}
    
   /**
    * Sets the Legacy Book Pages to the ItemStack.
    * 
    * @param player - The Player being used for placeholders.
    * @param meta - The ItemMeta to be updated.
    * @param pages - The book pages to be set.
    * @param itemMap - The ItemMap having their book pages set.
    * @deprecated Only to be used on server versions below 1.8.
    * @return The updated ItemMeta.
    */
	public static ItemMeta setPages(final Player player, final ItemMeta meta, final List<String> pages, final ItemMap itemMap) {
		if (!ServerUtils.hasSpecificUpdate("1_8") && pages != null && !pages.isEmpty()) {
			List<String> copyPages = new ArrayList<String>();
			for (String page: pages) { copyPages.add(page); }
			copyPages.set(0, ItemHandler.cutDelay(copyPages.get(0)));
			List < String > bookList = new ArrayList < String > ();
			for (int k = 0; k < pages.size(); k++) {
				bookList.add(StringUtils.translateLayout(pages.get(k), player));
			}
			((BookMeta) meta).setPages(bookList);
			itemMap.setPages(bookList);
			return meta;
		}
		return meta;
	}
	
   /**
    * Sets the ItemStack as glowing.
    * 
    * @param tempItem - The ItemStack to be updated.
    * @param itemMap - The ItemMap having their book pages set.
    */
	public static void setGlowing(final ItemStack tempItem, final ItemMap itemMap) {
		itemMap.setTempItem(setGlowEnchant(tempItem, itemMap));
	}
	
   /**
    * Sets the armor value to the items attributes.
    * 
    * @param tempItem - The ItemStack to be updated.
    * @param itemMap - The ItemMap having their armor value set.
    */
	public static void setAttributes(final ItemStack tempItem, final ItemMap itemMap) {
		if (!ServerUtils.hasSpecificUpdate("1_13") && itemMap.getAttributes() != null && !itemMap.getAttributes().isEmpty()) {
			try {
				String slot = null;
				if (ItemHandler.getDesignatedSlot(itemMap.getMaterial()).equalsIgnoreCase("noslot")) {
					slot = "HAND";
				} else {
					slot = ItemHandler.getDesignatedSlot(itemMap.getMaterial()).toUpperCase();
				}
				Class < ? > craftItemStack = ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack");
				Class < ? > itemClass = ReflectionUtils.getMinecraftClass("ItemStack");
				Class < ? > baseClass = ReflectionUtils.getMinecraftClass("NBTBase");
				Object nms = craftItemStack.getMethod("asNMSCopy", ItemStack.class).invoke(null, tempItem);
				Object tag = itemClass.getMethod(MinecraftMethod.getTag.getMethod(itemClass)).invoke(nms);
				Object modifiers = ReflectionUtils.getMinecraftClass("NBTTagList").getConstructor().newInstance();
				if (tag == null) { tag = ReflectionUtils.getMinecraftClass("NBTTagCompound").getConstructor().newInstance(); }
				for (String attribute: itemMap.getAttributes().keySet()) {
					int uuid = new BigInteger((itemMap.getConfigName() + attribute).getBytes()).intValue();
					Object attrib = ReflectionUtils.getMinecraftClass("NBTTagCompound").getConstructor().newInstance();
					double value = itemMap.getAttributes().get(attribute);
					String name = attribute.toLowerCase().replaceFirst("_", ".");
					if (name.contains("_")) { String[] nameSplit = name.split("_"); name = nameSplit[0]; nameSplit[0] = ""; for (String rename: nameSplit) { name += org.apache.commons.lang.StringUtils.capitalize(rename); } }
					attrib.getClass().getMethod(MinecraftMethod.setString.getMethod(attrib, String.class, String.class), String.class, String.class).invoke(attrib, "AttributeName", name);
					attrib.getClass().getMethod(MinecraftMethod.setString.getMethod(attrib, String.class, String.class), String.class, String.class).invoke(attrib, "Name", name);
					attrib.getClass().getMethod(MinecraftMethod.setString.getMethod(attrib, String.class, String.class), String.class, String.class).invoke(attrib, "Slot", slot);
					attrib.getClass().getMethod(MinecraftMethod.setDouble.getMethod(attrib, String.class, double.class), String.class, double.class).invoke(attrib, "Amount", value);
					attrib.getClass().getMethod(MinecraftMethod.setInt.getMethod(attrib, String.class, int.class), String.class, int.class).invoke(attrib, "Operation", 0);
					attrib.getClass().getMethod(MinecraftMethod.setInt.getMethod(attrib, String.class, int.class), String.class, int.class).invoke(attrib, "UUIDLeast", uuid);
					attrib.getClass().getMethod(MinecraftMethod.setInt.getMethod(attrib, String.class, int.class), String.class, int.class).invoke(attrib, "UUIDMost", (uuid / 2));
					modifiers.getClass().getMethod(MinecraftMethod.add.getMethod(modifiers, baseClass), baseClass).invoke(modifiers, attrib);
				}
				tag.getClass().getMethod(MinecraftMethod.set.getMethod(tag, String.class, baseClass), String.class,baseClass).invoke(tag, "AttributeModifiers", modifiers);
				itemMap.setTempItem((ItemStack) craftItemStack.getMethod("asCraftMirror", nms.getClass()).invoke(null, nms));
			} catch (Exception e) {
				ServerUtils.sendDebugTrace(e);
			}
		}
	}
	
   /**
    * Sets the ItemStack as glowing.
    * 
    * @param tempItem - The ItemStack to be updated.
    * @param itemMap - The ItemMap having their book pages set.
    * @deprecated Only to be used on server versions below 1.8.
    * @return The updated ItemStack.
    */
	private static ItemStack setGlowEnchant(final ItemStack tempItem, final ItemMap itemMap) {
		if (itemMap.isGlowing() && !ServerUtils.hasSpecificUpdate("1_11")) {
			try {
				Class <?> craftItemStack = ReflectionUtils.getCraftBukkitClass("inventory.CraftItemStack");
				Class < ? > itemClass = ReflectionUtils.getMinecraftClass("ItemStack");
				Class < ? > baseClass = ReflectionUtils.getMinecraftClass("NBTBase");
				Object nms = craftItemStack.getMethod("asNMSCopy", ItemStack.class).invoke(null, tempItem);
				Object tag = itemClass.getMethod(MinecraftMethod.getTag.getMethod(itemClass)).invoke(nms);
				if (tag == null) { tag = ReflectionUtils.getMinecraftClass("NBTTagCompound").getConstructor().newInstance(); }
				Object ench = ReflectionUtils.getMinecraftClass("NBTTagList").getConstructor().newInstance();
				tag.getClass().getMethod(MinecraftMethod.set.getMethod(tag, String.class, baseClass), String.class, baseClass).invoke(tag, "ench", ench);
				nms.getClass().getMethod(MinecraftMethod.setTag.getMethod(nms, tag.getClass()), tag.getClass()).invoke(nms, tag);
				return (((ItemStack) craftItemStack.getMethod("asCraftMirror", nms.getClass()).invoke(null, nms)));
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		}
		return tempItem;
	}
	
   /**
    * Color Encodes a String so that it is completely hidden in color codes,
    * this will be invisible to a normal eye and will not display any text.
    * Only to be used on server versions below 1.13, will not function on 1.13+.
    * 
    * @param str - The String to be Color Encoded.
    * @return The Color Encoded String.
    */
	public static String colorEncode(final String str) {
		try {
			String hiddenData = "";
			for (char c: str.toCharArray()) {
				hiddenData += "§" + c;
			}
			return hiddenData;
		} catch (Exception e) {
			ServerUtils.sendDebugTrace(e);
			return null;
		}
	}

   /**
    * Decodes a Color Encoded String.
    * Only to be used on server versions below 1.13, will not function on 1.13+.
    * 
    * @param str - The String to be Color Decoded.
    * @return The Color Decoded String.
    */
	public static String colorDecode(final String str) {
		try {
			String[] hiddenData = str.split("(?:\\w{2,}|\\d[0-9A-Fa-f])+");
			String returnData = "";
			if (hiddenData == null) {
				hiddenData = str.split("§");
				for (int i = 0; i < hiddenData.length; i++) {
					returnData += hiddenData[i];
				}
				return returnData;
			} else {
				String[] d = hiddenData[hiddenData.length - 1].split("§");
				for (int i = 1; i < d.length; i++) {
					returnData += d[i];
				}
				return returnData;
			}
		} catch (Exception e) {
			ServerUtils.sendDebugTrace(e);
			return null;
		}
	}
	
   /**
    * Checks if the Sk89q Plugins are the Legacy version.
    * 
    * @return If the plugins are Legacy.
    */
	public static boolean legacySk89q() {
		try {
			if (Class.forName("com.sk89q.worldedit.Vector") != null) { 
				return true; 
			}
		} catch (Exception e) { }
		return false;
	}
	
   /**
    * Gets the Data Value from the ItemStack.
    * 
    * @param item - The ItemStack to have its Data Value fetched.
    */
    public static int getDataValue(final ItemStack item) {
    	return item.getData().getData();
    }
    
   /**
    * Gets the Data Value for the corresponding Material.
    * 
    * @param material - The Material to have its data value fetched.
    * @return The Data Value.
    */
	public static int getDataValue(final Material material) {
		if (material == Material.STONE) { return 6; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "DIRT")) { return 2; }
		else if (material.toString().equalsIgnoreCase("WOOD")) { return 5; }
		else if (material.toString().equalsIgnoreCase("LOG")) { return 3; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "SAPLING")) { return 5; }
		else if (material.toString().equalsIgnoreCase("SAND")) { return 1; }
		else if (material.toString().equalsIgnoreCase("LEAVES")) { return 3; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "SPONGE")) { return 1; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "SANDSTONE") && !StringUtils.containsIgnoreCase(material.toString(), "STAIRS")) { return 2; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "LONG_GRASS")) { return 2; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "RED_ROSE")) { return 8; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "WOOD_STEP")) { return 5; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "STEP")) { return 7; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "STAINED_GLASS")) { return 15; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "MONSTER_EGGS")) { return 5; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "SMOOTH_BRICK")) { return 3; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "COBBLE_WALL")) { return 1; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "QUARTZ_BLOCK")) { return 2; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "STAINED_CLAY")) { return 15; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "LOG_2")) { return 1; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "LEAVES_2")) { return 1; }
		else if (material.toString().equalsIgnoreCase("PRISMARINE")) { return 2; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "CARPET")) { return 15; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "DOUBLE_PLANT")) { return 5; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "RED_SANDSTONE")) { return 2; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "GOLDEN_APPLE")) { return 1; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "RAW_FISH")) { return 3; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "COOKED_FISHED")) { return 1; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "INK_SAC")) { return 15; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "SKULL_ITEM") && ServerUtils.hasSpecificUpdate("1_9")) { return 5; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "SKULL_ITEM")) { return 4; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "CONCRETE")) { return 15; }
		else if (StringUtils.containsIgnoreCase(material.toString(), "WOOL")) { return 15; }
		return 0;
	}
    
   /**
    * Registers the Legacy Pickups Listener.
    * Only called when the Server version is below 1.12.
    * 
    */
	public static void registerPickups() {
		if (!StringUtils.isRegistered(me.RockinChaos.itemjoin.listeners.legacy.Legacy_Pickups.class.getSimpleName())) { 
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new me.RockinChaos.itemjoin.listeners.legacy.Legacy_Pickups(), ItemJoin.getInstance()); 
		}
	}
	
   /**
    * Registers the Legacy Stackable Listener.
    * Only called when the Server version is below 1.12.
    * 
    */
	public static void registerStackable() {
		if (!ServerUtils.hasSpecificUpdate("1_12") && !StringUtils.isRegistered(me.RockinChaos.itemjoin.listeners.legacy.Legacy_Stackable.class.getSimpleName())) { 
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new me.RockinChaos.itemjoin.listeners.legacy.Legacy_Stackable(), ItemJoin.getInstance()); 
		}
	}
	
   /**
    * Registers the Legacy Interact Listener.
    * Only called when the Server version is below 1.8.
    * 
    */
	public static void registerCommands() {
		if (!ServerUtils.hasSpecificUpdate("1_8") && !StringUtils.isRegistered(me.RockinChaos.itemjoin.listeners.legacy.Legacy_Commands.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new me.RockinChaos.itemjoin.listeners.legacy.Legacy_Commands(), ItemJoin.getInstance());
		}
	}
	
   /**
    * Registers the Legacy Consumes Listener.
    * Only called when the Server version is below 1.11.
    * 
    */
	public static void registerConsumes() {
		if (!ServerUtils.hasSpecificUpdate("1_11") && !StringUtils.isRegistered( me.RockinChaos.itemjoin.listeners.legacy.Legacy_Consumes.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new  me.RockinChaos.itemjoin.listeners.legacy.Legacy_Consumes(), ItemJoin.getInstance());
		}
	}
	
   /**
    * Registers the Legacy Storable Listener.
    * Only called when the Server version is below 1.8.
    * 
    */
	public static void registerStorable() {
		if (!ServerUtils.hasSpecificUpdate("1_8") && !StringUtils.isRegistered(me.RockinChaos.itemjoin.listeners.legacy.Legacy_Storable.class.getSimpleName())) {
			ItemJoin.getInstance().getServer().getPluginManager().registerEvents(new me.RockinChaos.itemjoin.listeners.legacy.Legacy_Storable(), ItemJoin.getInstance());
		}
	}
} public class Menu {
	private static String GUIName = ServerUtils.hasSpecificUpdate("1_9") ? StringUtils.colorFormat("&7           &0&n ItemJoin Menu") : StringUtils.colorFormat("&7           &0&n ItemJoin Menu");
	private static ItemStack fillerPaneBItem = ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLACK_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:15"), 1, false, "&7", "");
	private static ItemStack fillerPaneGItem = ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRAY_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:7"), 1, false, "&7", "");
	private static ItemStack fillerPaneItem = ItemHandler.getItem("GLASS_PANE", 1, false, "&7", "");
	private static ItemStack exitItem = ItemHandler.getItem("BARRIER", 1, false, "&c&l&nExit", "&7", "&7*Returns you to the game");
	private static List<String> modifyMenu = new ArrayList<String>();

//  ============================================== //
//  			   Selection Menus      	       //
//	============================================== //
	
   /**
    * Opens the MAIN CREATOR PANE for the Player.
    * 
    * @param sender - The Sender to have the Pane opened.
    */
	public static void startMenu(final CommandSender sender) {
		final Player player = (Player) sender;
		Interface pagedPane = new Interface(false, 1, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			pagedPane.addButton(new Button(exitItem, event -> player.closeInventory()));
			pagedPane.addButton(new Button(ItemHandler.getItem("ENDER_CHEST", 1, false, "&b&l&nConfig Settings", "&7", "&7*Change the GLOBAL plugin", "&7configuration settings."), event -> configSettings(player)));
			pagedPane.addButton(new Button(fillerPaneBItem));
			pagedPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, false, "&a&l&nCreate", "&7", "&7*Create a new item from scratch."),
					event -> materialPane(player, new ItemMap("item_" + StringUtils.getPath(1), "ARBITRARY"), 0, 0)));
			pagedPane.addButton(new Button(ItemHandler.getItem("HOPPER", 1, false, "&e&l&nSave", "&7", "&7*Save an existing item as a custom item."), event -> startHopper(player)));
			pagedPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&c&l&nModify", "&7", "&7*Modify an existing custom item"), event -> startModify(player, null, 0)));
			pagedPane.addButton(new Button(fillerPaneBItem));
			pagedPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&b&l&nItem Settings", "&7", "&7*Change the GLOBAL custom items", "&7configuration settings."), event -> itemSettings(player)));
			pagedPane.addButton(new Button(exitItem, event -> player.closeInventory()));
		});
		pagedPane.open(player);
	}
	
   /**
    * Opens the ITEM SETTINGS PANE for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void itemSettings(final Player player) {
		Interface itemPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			itemPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&bTrigger Delay", "&7", "&7*This is the delay in half-seconds", "&7that ItemJoin will wait", "&7to give you the items.", "&7",
					"&cNOTE: &7It is recommended to", "&7set this to 2 or 3 half-seconds.", "&9&lDELAY: &a" + String.valueOf(ConfigHandler.getConfig().getFile("items.yml").getString("items-Delay")).toUpperCase() + " half-second(s)"), 
					event -> numberPane(player, 1)));
			itemPane.addButton(new Button(fillerPaneBItem));
			final String defaultTriggers = ConfigHandler.getConfig().getFile("config.yml").getString("Settings.Default-Triggers");
			itemPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, 
					"&bDefault Triggers", "&7", "&7*This will be the default", "&7triggers used if a custom", "&7item is defined without", "&7specifying any triggers.", 
					"&9&lENABLED: &a" + String.valueOf((defaultTriggers != null && !defaultTriggers.isEmpty() && !StringUtils.containsIgnoreCase(defaultTriggers, "DISABLE")) ? defaultTriggers : "FALSE").toUpperCase()), 
					event -> triggerPane(player, 0)));
			itemPane.addButton(new Button(fillerPaneBItem));
			itemPane.addButton(new Button(ItemHandler.getItem("COOKIE", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items"), 
					"&bItem Permissions", "&7", "&7*If custom items should require", "&7the player to have specific", "&7permissions to receive the item.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Permissions.Obtain-Items", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			itemPane.addButton(new Button(fillerPaneBItem));
			itemPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PISTON" : "33"), 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items-OP"), 
					"&bItem Permissions &c&l[OP PLAYERS]", "&7", "&7*If custom items should require", "&7the &c&lOP player(s)&7 to have specific", "&7permissions to receive the item.", "&c&lNOTE: &7This only applies to &c&lOP player(s)&7.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items-OP")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Permissions.Obtain-Items-OP", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items-OP")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			itemPane.addButton(new Button(fillerPaneBItem));
			itemPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Overwrite"), 
					"&bOverwrite", "&7", "&7*Setting this to true will allow", "&7all custom items to overwrite", "&7any custom or vanilla items.", "&7", "&cNOTE: &7If set to false, the", "&7overwrite itemflag will still", "&7function normally.",
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("items.yml").getString("items-Overwrite")).toUpperCase()), event -> overwritePane(player)));
			itemPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_FENCE" : "85"), 1, ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Spamming"), 
					"&bSpamming", "&7", "&7*Setting this to false will prevent", "&7players from macro spamming", "&7the use of item commands.", "&7", "&cNOTE: &7It is recommended to", "&7leave this set to false.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Spamming")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("items-Spamming", !ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Spamming")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "items.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			itemPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-RestrictCount"), 
					"&bRestrict Count", "&7", "&7*Settings this to true will", "&7allow players to have their items", "&7refreshed (topped up) if they have", "&7used/consumed some of the given", "&7stack of custom items.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-RestrictCount")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("items-RestrictCount", !ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-RestrictCount")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "items.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			itemPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_WOOD" : "17"), 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Log-Commands"), 
					"&bLog Commands", "&7", "&7*If the plugin prevent CONSOLE", "&7from logging any executed", "&7comamnd from the custom items.", "&7This only works for item command(s).", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Log-Commands")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("General.Log-Commands", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Log-Commands")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			itemPane.addButton(new Button(ItemHandler.getItem("IRON_HELMET", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.HeldItem-Animations"), 
					"&bHeld Item Animations", "&7", "&7*If the animate or dynamic", "&7itemflags should update the item", "&7while the player is holding the item.", "&7", 
					"&7This essentially prevents the", "&7glitchy held item animation", "&7from the item constantly updating.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.HeldItem-Animations")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Settings.HeldItem-Animations", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.HeldItem-Animations")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().reloadConfigs(true);
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			final int heldSlot = ConfigHandler.getConfig().getFile("config.yml").getInt("Settings.HeldItem-Slot");
			itemPane.addButton(new Button(ItemHandler.getItem("DIAMOND_SWORD", (heldSlot > 0 ? heldSlot : 1), false, 
					"&bHeld Item Slot", "&7", "&7*This is the hotbar slot that", "&7the player will automatically", "&7have selected upon performing", "&7one of the held item triggers.", 
					"&9&lSLOT: &a" + String.valueOf((heldSlot >= 0 ? heldSlot : "NONE"))), 
					event -> numberPane(player, 2)));
			final String heldTriggers = ConfigHandler.getConfig().getFile("config.yml").getString("Settings.HeldItem-Triggers");
			itemPane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, 
					"&bHeld Item Triggers", "&7", "&7*When these trigger(s)", "&7are performed, the held item", "&7slot will be set.", 
					"&9&lENABLED: &a" + String.valueOf((heldTriggers != null && !heldTriggers.isEmpty() && !StringUtils.containsIgnoreCase(heldTriggers, "DISABLE")) ? heldTriggers : "FALSE").toUpperCase()), 
					event -> triggerPane(player, 1)));
			itemPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTING_TABLE" : "116"), 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.DataTags"), 
					"&bDataTags", "&7", "&7*If custom items should use", "&7data tags (NBTTags) to distinguish", "&7each custom item, making them unqiue.", 
					"&c&lNOTE: &7This only works on Minecraft 1.8+", "&7It is recommended to keep", "&7this set to TRUE.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.DataTags")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Settings.DataTags", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Settings.DataTags")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().reloadConfigs(true);
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
			itemPane.addButton(new Button(ItemHandler.getItem("LAVA_BUCKET", 1, false, 
					"&bClear Items", "&7", "&7*Modify settings for clearing", "&7specific items when a player", "&7performed a specified action."),
					event -> clearPane(player)));
			itemPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COMMAND_BLOCK" : "137"), 1, false, 
					"&bPrevent Actions", "&7", "&7*Disable certain actions", "&7with items for players."),
					event -> preventPane(player)));
			itemPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the main menu."), event -> startMenu(player)));
			itemPane.addButton(new Button(fillerPaneBItem), 7);
			itemPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the main menu."), event -> startMenu(player)));
		});
		itemPane.open(player);
	}
	
   /**
    * Opens the CONFIG SETTINGS PANE for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void configSettings(final Player player) {
		Interface configPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			configPane.addButton(new Button(fillerPaneBItem), 3);
			configPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, 
					"&6Language", "&7", "&7*The selected lang.yml language.", "&7This is for messages sent", "&7from the plugin to the player.", 
					"&9&lLANG: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getString("Language")).toUpperCase()), 
					event -> languagePane(player)));
			configPane.addButton(new Button(fillerPaneBItem));
			configPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COMMAND_BLOCK" : "137"), 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Database.MySQL"), 
					"&bMySQL Database", "&7", "&7*If the plugin should use", "&7a MySQL Database instead", "&7of the locale SQLite Database.",
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Database.MySQL")).toUpperCase()), 
					event -> databasePane(player)));
			configPane.addButton(new Button(fillerPaneBItem), 4);
			configPane.addButton(new Button(ItemHandler.getItem("BUCKET", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.CheckforUpdates"), 
					"&bCheck for Updates", "&7", "&7*If the plugin should check", "&7for updates at start-up.", "&7This includes the use of the", "&7/itemjoin updates/upgrade command(s).", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.CheckforUpdates")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("General.CheckforUpdates", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.CheckforUpdates")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> configSettings(player));
					}));
			configPane.addButton(new Button(ItemHandler.getItem("COMPASS", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Metrics-Logging"), 
					"&bMetrics Logging", "&7", "&7*If the plugin is allowed", "&7to log plugin data such as", "&7the server(s) Java version.", "&7It is recommended to keep this", "&7set to true as it improves", "&7the quality of plugin updates.",
					"&7", "&7You can view the logged data", "&7Here: https://bstats.org/plugin/bukkit/ItemJoin",
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Metrics-Logging")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("General.Metrics-Logging", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Metrics-Logging")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> configSettings(player));
					}));
			configPane.addButton(new Button(ItemHandler.getItem("STICK", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Debugging"), 
					"&bDebugging", "&7", "&7*Allows for more detailed", "&7CONSOLE messages from the plugin.", "&7Typically only used by the", "&7plugin developer to determine", "&7issues or bugs with the plugin.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Debugging")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("General.Debugging", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("General.Debugging")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> configSettings(player));
					}));
			configPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, ((ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands").size() != 0 
					&& !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds"), "DISABLED"))), 
					"&bActive Commands", "&7", "&7*Specify a list of commands", "&7to be executed upon performing a trigger.", "&7These commands are not related to", "&7custom items, rather the server itself.", 
					"&9&lENABLED: &a" + ((ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands").size() != 0 
					&& !StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds"), "DISABLED")) ? "YES" : "NO")), 
					event -> activeCommands(player)));
			configPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_APPLE" : "322"), 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-OP"), 
					"&bPlugin Commands &c&l[OP PLAYERS]", "&7", "&7*If the plugin should check", "&7if the OP player has the", "&7proper permissions set to", "&7use the plugin commands.", 
					"&7OP Players will no longer get", "&7access to all plugin commands", "&7by default.",
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-OP")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Permissions.Commands-OP", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-OP")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> configSettings(player));
					}));
			configPane.addButton(new Button(ItemHandler.getItem("BOOK", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-Get"), 
					"&bGet Commands", "&7", "&7*If the get and getAll", "&7commands should check for item", "&c&lpermissions &7before giving the item.",
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-Get")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Permissions.Commands-Get", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Commands-Get")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> configSettings(player));
					}));
			configPane.addButton(new Button(ItemHandler.getItem("BEDROCK", 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Movement-Bypass"), 
					"&bMovement Bypass", "&7", "&7*Enables the use of the", "&aitemjoin.bypass.inventorymodify", "&7permission-node, used to ignore", "&7the global itemMovement prevention", "&7or a custom items itemflag.", 
					"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Movement-Bypass")).toUpperCase()), 
					event -> {
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Permissions.Movement-Bypass", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Movement-Bypass")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> configSettings(player));
					}));
			configPane.addButton(new Button(fillerPaneBItem));
			configPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the main menu."), event -> startMenu(player)));
			configPane.addButton(new Button(fillerPaneBItem), 7);
			configPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the main menu."), event -> startMenu(player)));
		});
		configPane.open(player);
	}
	
   /**
    * Opens the MODIFY PANE for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void startModify(final Player player, final ItemMap itemMap, final int k) {
		Interface modifyPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			setPage(player, modifyPane, ItemUtilities.getUtilities().copyItems(), null, itemMap, k);
		});
		modifyPane.open(player);
	}
	
   /**
    * Opens the SAVING PANE for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void startHopper(Player player) {
		Interface dragDrop = new Interface(false, 1, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			dragDrop.allowClick(true);
			dragDrop.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nMain Menu", "&7", "&7*Returns you to the main menu."), event -> startMenu(player)));
			dragDrop.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&a&lAutosave", "&7", "&7*Click me to save your whole", "&7inventory to the items.yml as-is,", "&7including current slot positions!", "&7" , "&c&l[&nALL&c&l ITEMS]"), event -> {
				PlayerInventory playerInv = event.getWhoClicked().getInventory();
				if (playerInv != null) {
					for (int i = 0; i <= 35; i++) {
						if (playerInv.getItem(i) != null && playerInv.getItem(i).getType() != Material.AIR) {
							convertStack(player, playerInv.getItem(i), Integer.toString(i));
						}
					}
					if (playerInv.getHelmet() != null && playerInv.getHelmet().getType() != Material.AIR) { convertStack(player, playerInv.getHelmet(), "HELMET"); }
					if (playerInv.getChestplate() != null && playerInv.getChestplate().getType() != Material.AIR) { convertStack(player, playerInv.getChestplate(), "CHESTPLATE"); }
					if (playerInv.getLeggings() != null && playerInv.getLeggings().getType() != Material.AIR) { convertStack(player, playerInv.getLeggings(),"LEGGINGS"); }
					if (playerInv.getBoots() != null && playerInv.getBoots().getType() != Material.AIR) { convertStack(player, playerInv.getBoots(), "BOOTS"); }
					if (ServerUtils.hasSpecificUpdate("1_9") && PlayerHandler.getOffHandItem(player) != null && PlayerHandler.getOffHandItem(player).getType() != Material.AIR) { convertStack(player, PlayerHandler.getOffHandItem(player), "OFFHAND"); }
					ConfigHandler.getConfig().reloadConfigs(true);
					startMenu(player);
				}
			}));
			dragDrop.addButton(new Button(fillerPaneGItem), 2);
			dragDrop.addButton(new Button(ItemHandler.getItem("HOPPER", 1, false, "&a&lDrop an Item", "&7", "&7*Click an item from your inventory", "&7to save and drop it in this", "&7friendly little hopper!", "&7" , "&a&l[&nSINGLE&a&l ITEM]"), event -> {
				if (event.getCursor().getType() != Material.AIR) {
					ItemStack item = event.getCursor().clone();
					event.getWhoClicked().setItemOnCursor(null);
					event.getWhoClicked().getInventory().addItem(item);
					convertStack(player, item, null);
					dragDrop.allowClick(false);
				}
			}));
			dragDrop.addButton(new Button(fillerPaneGItem), 2);
			dragDrop.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&a&lAutosave", "&7", "&7*Click me to save your whole", "&7inventory to the items.yml as-is,", "&7including current slot positions!", "&7" , "&c&l[&nALL&c&l ITEMS]"), event -> {
				PlayerInventory playerInv = event.getWhoClicked().getInventory();
				if (playerInv != null) {
					for (int i = 0; i <= 35; i++) {
						if (playerInv.getItem(i) != null && playerInv.getItem(i).getType() != Material.AIR) {
							convertStack(player, playerInv.getItem(i), Integer.toString(i));
						}
					}
					if (playerInv.getHelmet() != null && playerInv.getHelmet().getType() != Material.AIR) { convertStack(player, playerInv.getHelmet(), "HELMET"); }
					if (playerInv.getChestplate() != null && playerInv.getChestplate().getType() != Material.AIR) { convertStack(player, playerInv.getChestplate(), "CHESTPLATE"); }
					if (playerInv.getLeggings() != null && playerInv.getLeggings().getType() != Material.AIR) { convertStack(player, playerInv.getLeggings(),"LEGGINGS"); }
					if (playerInv.getBoots() != null && playerInv.getBoots().getType() != Material.AIR) { convertStack(player, playerInv.getBoots(), "BOOTS"); }
					if (ServerUtils.hasSpecificUpdate("1_9") && PlayerHandler.getOffHandItem(player) != null && PlayerHandler.getOffHandItem(player).getType() != Material.AIR) { convertStack(player, PlayerHandler.getOffHandItem(player), "OFFHAND"); }
					ConfigHandler.getConfig().reloadConfigs(true);
					startMenu(player);
				}
			}));
			dragDrop.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nMain Menu", "&7", "&7*Returns you to the main menu."), event -> startMenu(player)));
		});
		dragDrop.open(player);
	}
	
//  ===================================================================================================================================================================================================================
	
//  ============================================== //
//  			   Menu Utilities        	       //
//  ============================================== //
	
   /**
    * Adds a button to the PagedPane.
    * 
    * @param player - The Player.
    * @param itemMap - The ItemMap currently being modified.
    * @param pagedPane - The PagedPane.
    */
	private static void setButton(final Player player, final ItemMap itemMap, final Interface modifyPane, final ItemMap contents, final ItemMap refMap, final int k) {
		final ItemStack item = itemMap.getTempItem().clone();
		if (item.getType() == Material.AIR) { item.setType(fillerPaneItem.getType()); }
		if (itemMap.isAnimated() || itemMap.isDynamic()) { setModifyMenu(true, player); itemMap.getAnimationHandler().get(player).setMenu(true, 0); }
		String lore = (contents == null && refMap == null ? "&7*Click to modify this custom item." : refMap != null ? "&7*Click to set this custom item as an ingredient." : "&7*Click to add into the contents of " + contents.getConfigName() + ".");
		String space = (contents == null ? "&6---------------------------" : "&6----------------------------------");
		modifyPane.addButton(new Button(ItemHandler.addLore(item, "&7", space, lore, "&9&lNode: &a" + itemMap.getConfigName(), "&7", (contents != null ? "&9&lENABLED: " + (contents.getContents().contains(itemMap.getConfigName()) ? "&aYES" : "&aNO") : "")), event -> 
		{
			if (refMap != null) {
				setIngredients(player, refMap, itemMap.getConfigName(), k);
			} else if (contents == null) {
				choicePane(player, itemMap, item);
			} else {
				List<String> contentList = contents.getContents();
				if (contents.getContents().contains(itemMap.getConfigName())) { contentList.remove(itemMap.getConfigName()); } 
				else { contentList.add(itemMap.getConfigName()); }
				contents.setContents(contentList);
				Interface contentsPane = new Interface(true, 6, GUIName, player);
				SchedulerUtils.runAsync(() -> {
					setPage(player, contentsPane, ItemUtilities.getUtilities().copyItems(), contents, refMap, k);
				});
				contentsPane.open(player);
			}
		}));
	}
	
   /**
    * Adds the ItemMaps to the PagedPane for viewing.
    * 
    * @param player - The Player.
    * @param modifyPane - The PagedPane to have buttons added.
    * @param items - The items to be added to the Pane.
    */
	private static void setPage(final Player player, final Interface modifyPane, final List < ItemMap > items, final ItemMap contents, final ItemMap itemMap, final int k) {
		ItemMap currentItem = null;
		boolean crafting = false;
		boolean arbitrary = false;
		if (contents != null) {
			modifyPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to the item definition menu."), event -> creatingPane(player, contents)));
		} else if (itemMap != null) { 
			modifyPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to the recipe menu."), event -> recipePane(player, itemMap)));
		}
		Interface craftingPane = new Interface(false, 4, GUIName, player);
		craftingPane.addButton(new Button(fillerPaneGItem), 3);
		currentItem = ItemUtilities.getUtilities().getItemMap("CRAFTING[1]", items);
		if (currentItem != null) {
			crafting = true;
			setButton(player, currentItem, craftingPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			craftingPane.addButton(new Button(fillerPaneGItem));
		}
		craftingPane.addButton(new Button(fillerPaneGItem));
		currentItem = ItemUtilities.getUtilities().getItemMap("CRAFTING[2]", items);
		if (currentItem != null) {
			crafting = true;
			setButton(player, currentItem, craftingPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			craftingPane.addButton(new Button(fillerPaneGItem));
		}
		craftingPane.addButton(new Button(fillerPaneGItem), 10);
		currentItem = ItemUtilities.getUtilities().getItemMap("CRAFTING[0]", items);
		if (currentItem != null) {
			crafting = true;
			setButton(player, currentItem, craftingPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			craftingPane.addButton(new Button(fillerPaneGItem));
		}
		craftingPane.addButton(new Button(fillerPaneGItem), 4);
		currentItem = ItemUtilities.getUtilities().getItemMap("CRAFTING[3]", items);
		if (currentItem != null) {
			crafting = true;
			setButton(player, currentItem, craftingPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			craftingPane.addButton(new Button(fillerPaneGItem));
		}
		craftingPane.addButton(new Button(fillerPaneGItem));
		currentItem = ItemUtilities.getUtilities().getItemMap("CRAFTING[4]", items);
		if (currentItem != null) {
			crafting = true;
			setButton(player, currentItem, craftingPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			craftingPane.addButton(new Button(fillerPaneGItem));
		}
		craftingPane.addButton(new Button(fillerPaneGItem), 3);
		String lore = (contents == null ? "&7the modifying selection menu" : "&7the contents selection menu.");
		craftingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", lore), event -> modifyPane.open(player)));
		craftingPane.addButton(new Button(fillerPaneBItem), 7);
		craftingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", lore), event -> modifyPane.open(player)));
		Interface arbitraryPane = new Interface(true, 6, GUIName, player);
		arbitraryPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", lore), event -> modifyPane.open(player)));
		List < ItemMap > tempList = new ArrayList < ItemMap > ();
		tempList.addAll(items);
		for (final ItemMap item: tempList) {
			if (item.getSlot().equalsIgnoreCase("ARBITRARY")) {
				setButton(player, item, arbitraryPane, contents, itemMap, k);
				items.remove(item);
				arbitrary = true;
			}
		}
		modifyPane.addButton(new Button(fillerPaneGItem));
		if (arbitrary == true) {
			modifyPane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&fArbitrary", "&7", "&7*Click to view the existing", "&7Arbitrary slot items."), event -> arbitraryPane.open(player)));
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		if (crafting == true) {
			modifyPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, false, "&fCrafting", "&7", "&7*Click to view the existing", "&7crafting slot items."), event -> craftingPane.open(player)));
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		currentItem = ItemUtilities.getUtilities().getItemMap("HELMET", items);
		if (currentItem != null) {
			setButton(player, currentItem, modifyPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		currentItem = ItemUtilities.getUtilities().getItemMap("CHESTPLATE", items);
		if (currentItem != null) {
			setButton(player, currentItem, modifyPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		currentItem = ItemUtilities.getUtilities().getItemMap("LEGGINGS", items);
		if (currentItem != null) {
			setButton(player, currentItem, modifyPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		currentItem = ItemUtilities.getUtilities().getItemMap("BOOTS", items);
		if (currentItem != null) {
			setButton(player, currentItem, modifyPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		currentItem = ItemUtilities.getUtilities().getItemMap("OFFHAND", items);
		if (currentItem != null) {
			setButton(player, currentItem, modifyPane, contents, itemMap, k);
			items.remove(currentItem);
		} else {
			modifyPane.addButton(new Button(fillerPaneGItem));
		}
		modifyPane.addButton(new Button(fillerPaneGItem));
		for (int i = 9; i < 36; i++) {
			currentItem = ItemUtilities.getUtilities().getItemMap(i + "", items);
			if (currentItem != null) {
				setButton(player, currentItem, modifyPane, contents, itemMap, k);
				items.remove(currentItem);
			} else {
				modifyPane.addButton(new Button(fillerPaneGItem));
			}
		}
		for (int j = 0; j < 9; j++) {
			currentItem = ItemUtilities.getUtilities().getItemMap(j + "", items);
			if (currentItem != null) {
				setButton(player, currentItem, modifyPane, contents, itemMap, k);
				items.remove(currentItem);
			} else {
				modifyPane.addButton(new Button(fillerPaneGItem));
			}
		}
		if (!items.isEmpty()) {
			setPage(player, modifyPane, items, contents, itemMap, k);
		}
	}
	
   /**
    * Converts the ItemStack that is attempting to be saved to a ItemMap.
    * 
    * @param player - The Player saving the ItemStack.
    * @param item - The ItemStack to be saved.
    */
	private static void convertStack(final Player player, final ItemStack item, final String slot) {
		ItemMap itemMap = new ItemMap("item_" + StringUtils.getPath(1), "ARBITRARY");
		itemMap.setMaterial(item.getType());
		if (!ServerUtils.hasSpecificUpdate("1_13")) { itemMap.setDataValue((short)LegacyAPI.getDataValue(item)); }
		itemMap.setCount(String.valueOf(item.getAmount()));
		if (item.getType().getMaxDurability() > 30 && ItemHandler.getDurability(item) != 0 && ItemHandler.getDurability(item) != (item.getType().getMaxDurability())) {
			itemMap.setDurability(ItemHandler.getDurability(item));
		}
		if (item.hasItemMeta()) {
			if (item.getItemMeta().hasDisplayName()) {
				itemMap.setCustomName(item.getItemMeta().getDisplayName().replace("§", "&"));
			}
			if (item.getItemMeta().hasLore()) {
				List < String > newLore = new ArrayList < String > ();
				for (String lore: item.getItemMeta().getLore()) {
					newLore.add(lore.replace("§", "&"));
				}
				itemMap.setCustomLore(newLore);
			}
			if (item.getItemMeta().hasEnchants()) {
				Map < String, Integer > enchantList = new HashMap < String, Integer > ();
				for (Enchantment e: item.getItemMeta().getEnchants().keySet()) {
					enchantList.put(ItemHandler.getEnchantName(e).toUpperCase(), item.getItemMeta().getEnchants().get(e));
				}
				itemMap.setEnchantments(enchantList);
			}
		}
		if (StringUtils.containsIgnoreCase(item.getType().toString(), "LEATHER_")) {
			LeatherArmorMeta meta = (LeatherArmorMeta) item.getItemMeta();
			if (meta.getColor() != null) {
				itemMap.setLeatherColor(DyeColor.getByColor(meta.getColor()).name());
			}
		} else if (item.getType().toString().equalsIgnoreCase("SKULL_ITEM") || item.getType().toString().equalsIgnoreCase("PLAYER_HEAD")) {
			if (!PlayerHandler.getSkullOwner(item).equalsIgnoreCase("NULL")) {
				itemMap.setSkull(PlayerHandler.getSkullOwner(item));
			} else if (!ItemHandler.getSkullTexture(item.getItemMeta()).isEmpty()) {
				itemMap.setSkullTexture(ItemHandler.getSkullTexture(item.getItemMeta()));
			}
		} else if (itemMap.getMaterial().toString().contains("CHARGE") || itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK_STAR")) {
			itemMap.setChargeColor(DyeColor.getByFireworkColor(((FireworkEffectMeta) item.getItemMeta()).getEffect().getColors().get(0)));
		} else if (itemMap.getMaterial().toString().contains("BANNER")) {
			itemMap.setBannerPatterns(((BannerMeta) item.getItemMeta()).getPatterns());
		} else if (itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK") || itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK_ROCKET")) {
			List < DyeColor > colors = new ArrayList < DyeColor > ();
			for (Color color: ((FireworkMeta) item.getItemMeta()).getEffects().get(0).getColors()) {
				colors.add(DyeColor.getByFireworkColor(color));
			}
			itemMap.setFirework(((FireworkMeta) item.getItemMeta()).getEffects().get(0));
			itemMap.setFireworkColor(colors);
			itemMap.setFireworkFlicker(((FireworkMeta) item.getItemMeta()).getEffects().get(0).hasFlicker());
			itemMap.setFireworkTrail(((FireworkMeta) item.getItemMeta()).getEffects().get(0).hasTrail());
			itemMap.setFireworkType(((FireworkMeta) item.getItemMeta()).getEffects().get(0).getType());
			itemMap.setFireworkPower(((FireworkMeta) item.getItemMeta()).getPower());
		} else if (itemMap.getMaterial() == Material.WRITTEN_BOOK) {
			itemMap.setAuthor(((BookMeta) item.getItemMeta()).getAuthor().replace("§", "&"));
			itemMap.setTitle(((BookMeta) item.getItemMeta()).getTitle().replace("§", "&"));
			if (ServerUtils.hasSpecificUpdate("1_10")) {
				itemMap.setGeneration(((BookMeta) item.getItemMeta()).getGeneration());
			}
			List < String > newPages = new ArrayList < String > ();
			for (String page: ((BookMeta) item.getItemMeta()).getPages()) {
				newPages.add(page.replace("§", "&"));
			}
			itemMap.setPages(newPages);
			List < List < String >> savePages = new ArrayList < List < String >> ();
			for (String page: ((BookMeta) item.getItemMeta()).getPages()) {
				List < String > pageList = new ArrayList < String > ();
				for (String splitPage: page.split("\n")) {
					pageList.add(splitPage.replace("§", "&"));
				}
				savePages.add(pageList);
			}
			itemMap.setListPages(savePages);
		}
		if (slot == null) { switchPane(player, itemMap, 0); }
		else { 
			itemMap.setSlot(slot);
			itemMap.saveToConfig();
			String[] placeHolders = LanguageAPI.getLang(false).newString();
			placeHolders[3] = (item.hasItemMeta() && item.getItemMeta().hasDisplayName() ? item.getItemMeta().getDisplayName() : itemMap.getConfigName());
			LanguageAPI.getLang(false).sendLangMessage("commands.menu.itemSaved", player, placeHolders);
		}
		itemMap.renderItemStack();
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting item modification or deletion.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param item - The ItemStack currently being modified.
    */
	private static void choicePane(final Player player, final ItemMap itemMap, final ItemStack item) {
		Interface choicePane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			choicePane.addButton(new Button(fillerPaneBItem), 4);
			choicePane.addButton(new Button(item));
			choicePane.addButton(new Button(fillerPaneBItem), 4);
			choicePane.addButton(new Button(fillerPaneBItem), 3);
			choicePane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, true, "&b&lSettings", "&7", "&7*Change the settings for this item.", "&7Make changes to the item name, lore,", "&7permissions, enabled-worlds, and more."), event -> {
				creatingPane(player, itemMap);
			}));
			choicePane.addButton(new Button(fillerPaneBItem));
			choicePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, true, "&c&lDelete", "&7", "&7*Delete this item.", "&7This will remove the item from the", "&7items.yml and will no longer be useable.", "&c&lWARNING: &7This &lCANNOT &7be undone!"), event -> {
				itemMap.removeFromConfig();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[3] = itemMap.getConfigName();
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.itemRemoved", player, placeHolders);
				ConfigHandler.getConfig().reloadConfigs(true);
				SchedulerUtils.runLater(6L, () -> {
					startModify(player, null, 0); 
				});
			}));
			choicePane.addButton(new Button(fillerPaneBItem), 3);
			choicePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the modify menu"), event -> startModify(player, null, 0)));
			choicePane.addButton(new Button(fillerPaneBItem), 7);
			choicePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the modify menu"), event -> startModify(player, null, 0)));
		});
		choicePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for Creating a NEW custom item.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void creatingPane(final Player player, final ItemMap itemMap) {
		Interface creatingPane = new Interface(false, 5, GUIName, player);
			SchedulerUtils.runAsync(() -> {
			String slotList = "";
			String slotString = "";
			if (StringUtils.nullCheck(itemMap.getMultipleSlots().toString()) != "NONE") {
				for (String slot: itemMap.getMultipleSlots()) {
					slotString += slot + ", ";
				}
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(slotString.substring(0, slotString.length())))) {
					slotList += "&a" + split + " /n ";
				}
			}
			String itemflagsList = "";
			if (StringUtils.nullCheck(itemMap.getItemFlags()) != "NONE") {
				for (String split: StringUtils.softSplit(itemMap.getItemFlags())) {
					itemflagsList += "&a" + split + " /n ";
				}
			}
			String triggersList = "";
			if (StringUtils.nullCheck(itemMap.getTriggers()) != "NONE") {
				for (String split: StringUtils.softSplit(itemMap.getTriggers())) {
					triggersList += "&a" + split + " /n ";
				}
			}
			String disabledList = "";
			if (StringUtils.nullCheck(itemMap.getDisabledWorlds().toString()) != "NONE") {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getDisabledWorlds().toString()))) {
					disabledList += "&a" + split + " /n ";
				}
			}
			String enabledList = "";
			if (StringUtils.nullCheck(itemMap.getEnabledWorlds().toString()) != "NONE") {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getEnabledWorlds().toString()))) {
					enabledList += "&a" + split + " /n ";
				}
			}
			String regionList = "";
			if (StringUtils.nullCheck(itemMap.getEnabledRegions().toString()) != "NONE") {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getEnabledRegions().toString()))) {
					regionList += "&a" + split + " /n ";
				}
			}
			String enchantList = "";
			if (StringUtils.nullCheck(itemMap.getEnchantments().toString()) != "NONE") {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getEnchantments().toString()))) {
					enchantList += "&a" + split + " /n ";
				}
			}
			String potionList = "";
			String potionString = "";
			if (StringUtils.nullCheck(itemMap.getPotionEffect().toString()) != "NONE") {
				for (PotionEffect potions: itemMap.getPotionEffect()) {
					potionString += potions.getType().getName().toUpperCase() + ":" + potions.getAmplifier() + ":" + potions.getDuration() + ", ";
				}
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(potionString.substring(0, potionString.length())))) {
					potionList += "&a" + split + " /n ";
				}
			}
			String attributeList = "";
			String attributeString = "";
			if (StringUtils.nullCheck(itemMap.getAttributes().toString()) != "NONE") {
				for (String attribute: itemMap.getAttributes().keySet()) {
					attributeString += attribute + ":" + itemMap.getAttributes().get(attribute) + ", ";
				}
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(attributeString.substring(0, attributeString.length())))) {
					attributeList += "&a" + split + " /n ";
				}
			}
			String patternList = "";
			String patternString = "";
			if (StringUtils.nullCheck(itemMap.getBannerPatterns().toString()) != "NONE") {
				for (Pattern patterns: itemMap.getBannerPatterns()) {
					patternString += patterns.getColor() + ":" + patterns.getPattern().name().toUpperCase() + ", ";
				}
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(patternString.substring(0, patternString.length())))) {
					patternList += "&a" + split + " /n ";
				}
			}
			creatingPane.addButton(new Button(fillerPaneGItem), 4);
			creatingPane.addButton(new Button(headerStack(player, itemMap)));
			creatingPane.addButton(new Button(fillerPaneGItem), 4);
			creatingPane.addButton(new Button(ItemHandler.getItem(itemMap.getMaterial().toString() + ((itemMap.getDataValue() != null && itemMap.getDataValue() != 0) ? ":" + itemMap.getDataValue() : ""), 1, false, "&c&lMaterial", "&7", "&7*Set the material of the item.", "&9&lMATERIAL: &a" + 
			itemMap.getMaterial().toString() + ((itemMap.getDataValue() != null && itemMap.getDataValue() != 0) ? ":" + itemMap.getDataValue() : "")), event -> { 
				if (itemMap.getDynamicMaterials() != null && !itemMap.getDynamicMaterials().isEmpty()) {
					animateMaterialPane(player, itemMap);
				} else {
					materialPane(player, itemMap, 1, 0);
				}
				}));
			creatingPane.addButton(new Button(ItemHandler.getItem("GLASS", 1, false, "&c&lSlot", "&7", "&7*Set the slot that the", "&7item will be given in.", (itemMap.getMultipleSlots() != null && 
					!itemMap.getMultipleSlots().isEmpty() ? "&9&lSlot(s): &a" + slotList : "&9&lSLOT: &a" + itemMap.getSlot().toUpperCase())), event -> switchPane(player, itemMap, 1)));
			creatingPane.addButton(new Button(ItemHandler.getItem("DIAMOND", itemMap.getCount(), false, "&b&lCount", "&7", "&7*Set the amount of the", "&7item to be given.", "&9&lCOUNT: &a" + 
					itemMap.getCount()), event -> countPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&b&lName", "&7", "&7*Set the name of the item.", "&9&lNAME: &f" + StringUtils.nullCheck(itemMap.getCustomName())), event -> {
				if (itemMap.getDynamicNames() != null && !itemMap.getDynamicNames().isEmpty()) {
					animatedNamePane(player, itemMap);
				} else {
					if (StringUtils.nullCheck(itemMap.getCustomName()) != "NONE") {
						itemMap.setCustomName(null);
						creatingPane(player, itemMap);
					} else {
						player.closeInventory();
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "NAME";
						placeHolders[15] = "&bUltimate Sword";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
					}
				}
			}, event -> {
				itemMap.setCustomName(ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NAME";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				creatingPane(event.getPlayer(), itemMap);
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, false, "&b&lLore", "&7", "&7*Set the lore of the item.", "&9&lLORE: &f" + StringUtils.nullCheck(itemMap.getCustomLore().toString())), event -> {
				if (itemMap.getDynamicLores() != null && !itemMap.getDynamicLores().isEmpty()) {
					animatedLorePane(player, itemMap);
				} else { 
					lorePane(player, itemMap);
				}
			}, event -> {
				itemMap.setCustomLore(StringUtils.split(ChatColor.stripColor(event.getMessage())));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "LORE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				creatingPane(event.getPlayer(), itemMap);
			}));
			creatingPane.addButton(new Button(ItemHandler.setDurability(ItemHandler.getItem("DIAMOND_BOOTS", 1, false, "&e&lData", "&7", "&7*Set the damage or the", "&7custom texture of the item."), 160), event -> { dataPane(player, itemMap); }));
			creatingPane.addButton(new Button(ItemHandler.getItem("BOOK", 1, false, "&e&lCommand Settings", "&7", "&7*Define commands for the item", "&7which execute upon being", "&7interacted with."), event -> commandPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem("ENCHANTED_BOOK", 1, false, "&b&lEnchantments", "&7", "&7*Add enchants to make the", "&7item sparkle and powerful.", "&9&lENCHANTMENTS: &a" + 
			(StringUtils.nullCheck(itemMap.getEnchantments().toString()) != "NONE" ? "&a" + enchantList : "NONE")), event -> enchantPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&b&lItemflags", "&7", "&7*Special flags that will give", "&7the item abilities and", "&7custom features.", "&9&lITEMFLAGS: &a" + 
			(StringUtils.nullCheck(itemMap.getItemFlags()) != "NONE" ? "&a" + itemflagsList : "NONE")), event -> flagPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&b&lTriggers", "&7", "&7*When the players act upon these", "&7events, the item will be given.", "&9&lTRIGGERS: &a" +
			(StringUtils.nullCheck(itemMap.getTriggers()) != "NONE" ? "&a" + triggersList : "NONE")), event -> triggerPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "REDSTONE_TORCH" : "76"), 1, false, "&b&lPermission Node", "&7", "&7*Custom permission node that", "&7will be required by a permission", "&7plugin to receive the item.", "&7&lNote: &7Do NOT include", 
					"&7any spaces or special characters", "&9&lPERMISSION-NODE: &a" + StringUtils.nullCheck(itemMap.getPermissionNode())), event -> {
				if (StringUtils.nullCheck(itemMap.getPermissionNode()) != "NONE") {
					itemMap.setPerm(null);
					creatingPane(player, itemMap);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "CUSTOM PERMISSION";
					placeHolders[15] = "itemjoin.ultra";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				itemMap.setPerm(ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "CUSTOM PERMISSION";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				creatingPane(event.getPlayer(), itemMap);
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BEDROCK" : "7"), 1, false, "&b&lDisabled Worlds", "&7", "&7*Define the world(s) that the", "&7item will &l&nNOT&7 be given in.", 
					"&9&lDISABLED-WORLDS: &a" + (StringUtils.nullCheck(itemMap.getDisabledWorlds().toString()) != "NONE" ? "&a" + disabledList : "NONE")), event -> worldPane(player, itemMap, 0)));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, false, "&b&lEnabled Worlds", "&7", "&7*Define the world(s) that the", "&7item will be given in.", 
					"&9&lENABLED-WORLDS: &a" + (StringUtils.nullCheck(itemMap.getEnabledWorlds().toString()) != "NONE" ? "&a" + enabledList : "NONE")), event -> worldPane(player, itemMap, 1)));
			creatingPane.addButton(new Button(ItemHandler.getItem("GOLD_BLOCK", 1, true, "&b&lEnabled Regions", "&7", "&7*Define the region(s) that the", "&7item will be given in.", (DependAPI.getDepends(false).getGuard().guardEnabled() ? 
					"&9&lENABLED-REGIONS: &a" + (StringUtils.nullCheck(itemMap.getEnabledRegions().toString()) != "NONE" ? "&a" + regionList : "NONE") : ""), (DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&7"), 
					(DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&c&lERROR: &7WorldGuard was NOT found."), (DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&7This button will do nothing...")), event -> {
				if (DependAPI.getDepends(false).getGuard().guardEnabled()) {
					regionPane(player, itemMap);
				}
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "STICKY_PISTON" : "29"), 1, false, "&e&lAnimation Settings", "&7", "&7*Define animations for the item", "&7Example: Custom iterations for the", 
					"&7items name, lore, and material type"), event -> animationPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_FENCE" : "FENCE"), 1, false, "&b&lLimit-Modes", "&7", "&7*Define the gamemode(s) that the", "&7item will be limited to.", "&9&lLIMIT-MODES: &a" + 
					StringUtils.nullCheck(itemMap.getLimitModes())), event -> limitPane(player, itemMap)));
			creatingPane.addButton(new Button(ItemHandler.getItem("NETHER_STAR", 1, false, "&b&lProbability", "&7", "&7*Define the chance that the", "&7item will be given to the player.", "&7", "&c&lNOTICE:&7 Only ONE item defined with", "&7a probability value will be selected.", "&7Probability is the same as a dice roll.", "&7", "&9&lPROBABILITY: &a" +
					StringUtils.nullCheck(itemMap.getProbability() + "&a%")), event -> {
				if (StringUtils.nullCheck(itemMap.getProbability() + "&a%") != "NONE") {
					itemMap.setProbability(-1);
					creatingPane(player, itemMap);
				} else {
					probabilityPane(player, itemMap);
				}
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem("ICE", 1, false, "&b&lUsage Cooldown", "&7", "&7*Define the cooldown for", "&7interacting with the item.", "&9&lUSE-COOLDOWN: &a" +
			StringUtils.nullCheck(itemMap.getInteractCooldown() + "&7")), event -> {
				if (StringUtils.nullCheck(itemMap.getInteractCooldown() + "&7") != "NONE") {
					itemMap.setInteractCooldown(0);
					creatingPane(player, itemMap);
				} else {
					usePane(player, itemMap);
				}
			}));
			creatingPane.addButton(new Button(fillerPaneGItem));
			creatingPane.addButton(new Button(ItemHandler.getItem("LAVA_BUCKET", 1, false, "&b&lConditions", "&7", "&7*Define conditions for triggers,", "&7commands, and the disposable itemflag.", "&9Enabled: &a" + 
			((itemMap.getTriggerConditions() != null && !itemMap.getTriggerConditions().isEmpty()) || (itemMap.getDisposableConditions() != null && !itemMap.getDisposableConditions().isEmpty()) 
			|| (itemMap.getCommandConditions() != null && !itemMap.getCommandConditions().isEmpty()) ? "YES" : "NONE")), event -> {
					conditionsPane(player, itemMap);
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "REPEATER" : "356"), 1, false, "&b&lToggle", "&7", "&7*Specify command(s) players can", "&7execute to enable or disable the", "&7custom item for themselves.", "&9Enabled: &a" + (itemMap.getToggleCommands() != null && !itemMap.getToggleCommands().isEmpty() ? "YES" : "NONE")), event -> {
					togglePane(player, itemMap);
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, false, "&b&lRecipe", "&7", "&7*Define the recipe to be", "&7able to craft this item.", "&9Enabled: &a" + (itemMap.getIngredients() != null && !itemMap.getIngredients().isEmpty() ? "YES" : "NONE")), event -> {
					recipePane(player, itemMap);
			}));
			creatingPane.addButton(new Button(fillerPaneGItem));
			creatingPane.addButton(new Button(ItemHandler.getItem("GOLD_INGOT", 1, false, "&e&lDrop Chances", "&7", "&7*Define the drop chance for receiving", "&7this item from mobs or breaking blocks."), event -> {
					dropsPane(player, itemMap);
			}));
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COMMAND_BLOCK" : "137"), 1, false, "&c&lNBT Properties", "&7", "&7*Define specific NBT Properties", "&7to be set to the item.", "&9Enabled: &a" + (itemMap.getNBTValues() != null && !itemMap.getNBTValues().isEmpty() ? "YES" : "NONE")), event -> {
					nbtPane(player, itemMap);
			}));
			if (itemMap.getMaterial().toString().contains("MAP")) {
				creatingPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&e&lMap Image", "&7", "&7*Adds a custom map image that", "&7will be displayed when held.", "&7", "&7Place the custom map image", 
						"&7in the MAIN ItemJoin folder.", "&7", "&7The map CAN be a GIF but", "&7must be a 128x128 pixel image.", "&9&lImage: &a" + StringUtils.nullCheck(itemMap.getMapImage())), event -> {
					if (StringUtils.nullCheck(itemMap.getMapImage()) != "NONE") {
						itemMap.setMapImage(null);
						creatingPane(player, itemMap);
					} else {
						player.closeInventory();
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "MAP IMAGE";
						placeHolders[15] = "minecraft.png OR minecraft-dance.gif";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
					}
				}, event -> {
					itemMap.setMapImage(ChatColor.stripColor(event.getMessage()));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "MAP IMAGE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					creatingPane(event.getPlayer(), itemMap);
				}));
			} else if (itemMap.getMaterial().toString().contains("ARROW") && !itemMap.getMaterial().toString().contains("TIPPED_ARROW")) {
				creatingPane.addButton(new Button(ItemHandler.getItem("ENDER_PEARL", 1, false, "&e&lTeleport", "&7", "&7*Set the arrow to teleport", "&7the player upon landing.", "&9&lEnabled: &a" + String.valueOf(itemMap.isTeleport()).toUpperCase()),
						event -> teleportPane(player, itemMap, 0)));
			} else if (itemMap.getMaterial().toString().contains("CHARGE") || itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK_STAR")) {
				Interface colorPane = new Interface(true, 6, GUIName, player);
				colorPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu"), event -> creatingPane(player, itemMap)));
				for (DyeColor color: DyeColor.values()) {
					colorPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRAY_DYE" : "351:8"), 1, false, "&f" + color.name(), "&7", "&7*This will be the color", "&7of your firework charge."), event -> {
						itemMap.setChargeColor(color);
						creatingPane(player, itemMap);
					}));
				}
				creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_DYE" : "351:9"), 1, false, "&e&lCharge Color", "&7", "&7*Set the color of", "&7the firework star.", "&9&lColor: &a" +
				StringUtils.nullCheck(itemMap.getChargeColor() + "")), event -> {
					if (StringUtils.nullCheck(itemMap.getChargeColor() + "") != "NONE") {
						itemMap.setChargeColor(null);
						creatingPane(player, itemMap);
					} else {
						colorPane.open(player);
					}
				}));
			} else if (itemMap.getMaterial().isEdible() || itemMap.getMaterial().toString().equalsIgnoreCase("POTION")) {
				creatingPane.addButton(new Button(ItemHandler.getItem("POTION", 1, false, "&e&lEffects", "&7", "&7*Add custom effects after", "&7consuming the item.", "&9&lPotion-Effects: &a" + StringUtils.nullCheck(potionList)),
						event -> potionPane(player, itemMap, 0)));
			} else if (itemMap.getMaterial().toString().contains("BANNER")) {
				creatingPane.addButton(new Button(ItemHandler.getItem("CLAY_BALL", 1, false, "&e&lBanner Patterns", "&7", "&7*Set custom patterns that", "&7will appear on the item.", "&9&lBanner-Meta: &a" + StringUtils.nullCheck(patternList)),
						event -> bannerPane(player, itemMap)));
			} else if (!ItemHandler.getDesignatedSlot(itemMap.getMaterial()).equalsIgnoreCase("noslot") && !itemMap.getMaterial().toString().contains("LEATHER_")) {
				creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1"), 1, false, "&a&lAttributes", "&7", "&7*Add a custom attribute to", "&7your armor or weapon.", (StringUtils.nullCheck(attributeList) != "NONE" ? "&9&lAttributes: &a" + attributeList : "")), event -> {
					attributePane(player, itemMap, false);
				}));
			} else if (itemMap.getMaterial().toString().contains("SHULKER")) {
				creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PURPLE_SHULKER_BOX" : "229"), 1, false, "&a&lContents", "&7", "&7*Add existing custom items into", "&7the contents of this box.", "&9Enabled: &a" + (itemMap.getContents() != null && !itemMap.getContents().isEmpty() ? "YES" : "NONE")), event -> {
					Interface contentsPane = new Interface(true, 6, GUIName, player);
					SchedulerUtils.runAsync(() -> {
						setPage(player, contentsPane, ItemUtilities.getUtilities().copyItems(), itemMap, null, 0);
					});
					contentsPane.open(player);
				}));
			} else {
				creatingPane.addButton(new Button(ItemHandler.getItem("MAGMA_CREAM", 1, false, "&e&lOther Settings", "&7", "&7*Settings that are specific", "&7to the item's material type.", (specialItem(itemMap) ? "" : "&7"),
						(specialItem(itemMap) ? "" : "&c&lERROR: &7A " + itemMap.getMaterial().name() + " &7is NOT"), (specialItem(itemMap) ? "" : "&7a special material type.")), event -> {
					if (specialItem(itemMap)) {
						otherPane(player, itemMap);
					}
				}));
			}
			creatingPane.addButton(new Button(fillerPaneGItem));
			creatingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nMain Menu", "&7", "&7*Cancel and return to the main menu.", "&7", "&c&lWARNING: &7This item has NOT been saved!"), event -> returnConfirm(player, itemMap)));
			creatingPane.addButton(new Button(fillerPaneBItem), 3);
			creatingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIME_WOOL" : "WOOL:5"), 1, false, "&a&l&nSave to Config", "&7", "&7*Saves the custom item", "&7settings to the items.yml file."), event -> {
				itemMap.saveToConfig();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[3] = itemMap.getConfigName();
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.itemSaved", player, placeHolders);
				ConfigHandler.getConfig().reloadConfigs(true);
				player.closeInventory();
			}));
			creatingPane.addButton(new Button(fillerPaneBItem), 3);
			creatingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nMain Menu", "&7", "&7*Cancel and return you to the main menu.", "&7", "&c&lWARNING: &7This item has NOT been saved!"), event -> returnConfirm(player, itemMap)));
			});
		creatingPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for confirming the return to the main menu.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void returnConfirm(final Player player, final ItemMap itemMap) {
		Interface returnPane = new Interface(false, 1, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			returnPane.addButton(new Button(fillerPaneBItem));
			returnPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "RED_WOOL" : "WOOL:14"), 1, false, "&c&l&nMain Menu", "&7", "&7*Cancel and return to the", "&7main menu, all modified", "&7settings will be lost.", "&7", "&c&lWARNING: &cThis item has &lNOT&c been saved!"), event -> startMenu(player)));
			returnPane.addButton(new Button(fillerPaneBItem), 2);
			returnPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIME_WOOL" : "WOOL:5"), 1, false, "&a&l&nSave to Config", "&7", "&7*Saves the custom item", "&7settings to the items.yml file."), event -> {
				itemMap.saveToConfig();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[3] = itemMap.getConfigName();
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.itemSaved", player, placeHolders);
				ConfigHandler.getConfig().reloadConfigs(true);
				startMenu(player);
			}));
			returnPane.addButton(new Button(fillerPaneBItem), 2);
			returnPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_WOOL" : "WOOL:4"), 1, false, "&e&l&nModify Settings", "&7", "&7*Continue modifying the", "&7custom item settings."), event -> creatingPane(player, itemMap)));
			returnPane.addButton(new Button(fillerPaneBItem));
		});
		returnPane.open(player);
	}
	
	
// =======================================================================================================================================================================================================================================

//  ============================================== //
//                 Settings Menus      	           //
//  ============================================== //
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    * @param stage - The type of selection Pane.
    */
	private static void numberPane(final Player player, final int stage) {
		Interface numberPane = new Interface((stage == 2 ? false : true), (stage == 2 ? 2 : 6), GUIName, player);
		SchedulerUtils.runAsync(() -> {
			numberPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> {
				if (stage == 1) {
					itemSettings(player);
				} else if (stage == 3) {
					clearPane(player);
				}
			}));
			for (int i = 0; i <= (stage == 1 || stage == 3 ? 64 : stage == 2 ? 8 : 0); i++) {
				final int k = i;
				if (stage == 1) {
					numberPane.addButton(new Button(ItemHandler.getItem((i == 0 ? (ServerUtils.hasSpecificUpdate("1_13") ? "RED_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:14") : (ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11")), (i == 0 ? 1 : i), false, "&9&lDelay: &a&l" + i, "&7", 
					"&7*Click to set the trigger", "&7delay for giving custom items.", "&aSecond(s): &e" + (i == 0 ? 0 : ((Double.parseDouble(String.valueOf(i))) / 2))), event -> {
						File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("items-Delay", k); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "items.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
				} else if (stage == 2) {
					numberPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), (i == 0 ? 1 : i), false, "&9&lSlot: &a&l" + i + " &9&l[HOTBAR]", "&7", 
					"&7*Click to set the held item slot", "&7that is automatically selected", "&7when performing a held item trigger.", "&aSlot: &e" + k), event -> {
						File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Settings.HeldItem-Slot", k); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> itemSettings(player));
					}));
				} else if (stage == 3) {
					numberPane.addButton(new Button(ItemHandler.getItem((i == 0 ? (ServerUtils.hasSpecificUpdate("1_13") ? "RED_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:14") : (ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11")), (i == 0 ? 1 : i), false, "&9&lDelay: &a&l" + i, "&7", 
					"&7*Click to set the trigger", "&7delay for clearing items.", "&aSecond(s): &e" + (i == 0 ? 0 : (Double.parseDouble(String.valueOf(i))))), event -> {
						File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Clear-Items.Delay-Tick", k); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> clearPane(player));
					}));
				} 
			}
			if (stage == 2) {
				numberPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
				numberPane.addButton(new Button(fillerPaneBItem), 7);
				numberPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
			}
		});
		numberPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void languagePane(final Player player) {
		Interface languagePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			final String language = ConfigHandler.getConfig().getFile("config.yml").getString("Language").replace(" ", "");
			languagePane.addButton(new Button(fillerPaneBItem));
			languagePane.addButton(new Button(ItemHandler.getItem(ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2", 1, language.equalsIgnoreCase("ENGLISH"), "&6&l&nEnglish", "&7", 
			"&7*Sets the messages sent by", "&7the plugin to the player", "&7to be written in &c&lEnglish&7.", "&7This is the type of lang.yml file", "&7generated in the plugin folder.", 
			"&9&lENABLED: &a" + (language.equalsIgnoreCase("ENGLISH") + "").toUpperCase()), event -> {
				if (!language.equalsIgnoreCase("ENGLISH")) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Language", "ENGLISH"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> languagePane(player));
				}
			}));
			languagePane.addButton(new Button(ItemHandler.getItem("SAND", 1, language.equalsIgnoreCase("SPANISH"), "&6&l&nSpanish", "&7", 
			"&7*Sets the messages sent by", "&7the plugin to the player", "&7to be written in &c&lSpanish&7.", "&7This is the type of lang.yml file", "&7generated in the plugin folder.", 
			"&9&lENABLED: &a" + (language.equalsIgnoreCase("SPANISH") + "").toUpperCase()), event -> {
				if (!language.equalsIgnoreCase("SPANISH")) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Language", "SPANISH"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> languagePane(player));
				}
			}));
			languagePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "SNOW_BLOCK" : "80"), 1, language.equalsIgnoreCase("RUSSIAN"), "&6&l&nRussian", "&7", 
			"&7*Sets the messages sent by", "&7the plugin to the player", "&7to be written in &c&lRussian&7.", "&7This is the type of lang.yml file", "&7generated in the plugin folder.", 
			"&9&lENABLED: &a" + (language.equalsIgnoreCase("RUSSIAN") + "").toUpperCase()), event -> {
				if (!language.equalsIgnoreCase("RUSSIAN")) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Language", "RUSSIAN"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> languagePane(player));
				}
			}));
			languagePane.addButton(new Button(fillerPaneBItem));
			languagePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "STONE_BRICKS" : "98"), 1, language.equalsIgnoreCase("FRENCH"), "&6&l&nFrench", "&7", 
			"&7*Sets the messages sent by", "&7the plugin to the player", "&7to be written in &c&lFrench&7.", "&7This is the type of lang.yml file", "&7generated in the plugin folder.", 
			"&9&lENABLED: &a" + (language.equalsIgnoreCase("FRENCH") + "").toUpperCase()), event -> {
				if (!language.equalsIgnoreCase("FRENCH")) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Language", "FRENCH"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> languagePane(player));
				}
			}));
			languagePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "DIORITE" : (ServerUtils.hasSpecificUpdate("1_8") ? "1:3" : "5")), 1, language.equalsIgnoreCase("TRADITIONALCHINESE"), "&6&l&nTraditional Chinese", "&7", 
			"&7*Sets the messages sent by", "&7the plugin to the player", "&7to be written in &c&lTraditional Chinese&7.", "&7This is the type of lang.yml file", "&7generated in the plugin folder.", 
			"&9&lENABLED: &a" + (language.equalsIgnoreCase("TRADITIONALCHINESE") + "").toUpperCase()), event -> {
				if (!language.equalsIgnoreCase("TRADITIONALCHINESE")) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Language", "TRADITIONAL CHINESE"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> languagePane(player));
				}
			}));
			languagePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "POLISHED_DIORITE" : (ServerUtils.hasSpecificUpdate("1_8") ? "1:4" : "5:3")), 1, language.equalsIgnoreCase("SIMPLIFIEDCHINESE"), "&6&l&nSimplified Chinese", "&7", 
			"&7*Sets the messages sent by", "&7the plugin to the player", "&7to be written in &c&lSimplified Chinese&7.", "&7This is the type of lang.yml file", "&7generated in the plugin folder.", 
			"&9&lENABLED: &a" + (language.equalsIgnoreCase("SIMPLIFIEDCHINESE") + "").toUpperCase()), event -> {
				if (!language.equalsIgnoreCase("SIMPLIFIEDCHINESE")) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Language", "SIMPLIFIED CHINESE"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> languagePane(player));
				}
			}));
			languagePane.addButton(new Button(fillerPaneBItem));
			languagePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the config settings menu."), event -> configSettings(player)));
			languagePane.addButton(new Button(fillerPaneBItem), 7);
			languagePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the config settings menu."), event -> configSettings(player)));
		});
		languagePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void activeCommands(final Player player) {
		Interface activePane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			final String triggers = ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.triggers");
			final String enabledList = ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds");
			activePane.addButton(new Button(fillerPaneBItem), 4);
			activePane.addButton(new Button(ItemHandler.getItem("BOOK", 1, ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands").size() != 0, "&b&l&nCommands", "&7", 
			"&7*Specify a list of commands to be", "&7executed upon performing a trigger.", 
			"&9&lENABLED: &a" + (ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands").size() != 0 ? "YES" : "NO")), event -> altCommandPane(player, null, 4)));
			activePane.addButton(new Button(fillerPaneBItem), 6);
			activePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "REPEATER" : "356"), 1, false, "&a&lSequence", "&7", "&7*The order that the command lines", 
					"&7will be executed in.", "&9&lCOMMANDS-SEQUENCE: &a" + StringUtils.nullCheck(ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.commands-sequence") + "")), event -> sequencePane(player, null, 4)));
			activePane.addButton(new Button(fillerPaneBItem));
			activePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, 
					"&bTriggers", "&7", "&7*This will be the triggers", "&7that will cause the command lines", "&7to execute.", 
					"&9&lENABLED: &a" + String.valueOf((triggers != null && !triggers.isEmpty() && !StringUtils.containsIgnoreCase(triggers, "DISABLE")) ? triggers : "FALSE").toUpperCase()), 
					event -> triggerPane(player, 4)));
			activePane.addButton(new Button(fillerPaneBItem));
			activePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, false, "&b&lEnabled Worlds", "&7", "&7*Define the world(s) that the", "&7commands will be executed in.", 
					"&9&lENABLED-WORLDS: &a" + (StringUtils.nullCheck(enabledList) != "NONE" ? "&a" + enabledList : "NONE")), event -> worldPane(player, null, 4)));
			activePane.addButton(new Button(fillerPaneBItem), 2);
			activePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the config settings menu."), event -> configSettings(player)));
			activePane.addButton(new Button(fillerPaneBItem), 7);
			activePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the config settings menu."), event -> configSettings(player)));
		});
		activePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void databasePane(final Player player) {
		Interface databasePane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			databasePane.addButton(new Button(fillerPaneBItem), 4);
			databasePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COMMAND_BLOCK" : "137"), 1, ConfigHandler.getConfig().getFile("config.yml").getBoolean("Database.MySQL"), "&b&l&nMySQL", "&7", 
			"&7*If the plugin should use a", "&7MySQL connection instead of the", "&7local SQLite database inside", "&7the plugin folder.", "&7", "&c&lNote: &7Keep this set to false", "&7if you do not know what", "&7you are doing.", 
			"&7", "&c&l&nWARNING: &7Changing this value requires", "&7a server restart for the", "&7changes to take affect.",  
			"&9&lENABLED: &a" + String.valueOf(ConfigHandler.getConfig().getFile("config.yml").getBoolean("Database.MySQL")).toUpperCase()), 
				event -> {
					File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Database.MySQL", !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Database.MySQL")); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(fillerPaneBItem), 4);
			databasePane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&a&lHost", "&7", 
			"&7*Set the &c&lHost &7for", "&7the MySQL databse connection.", "&9&lHOST: &a" + ConfigHandler.getConfig().getFile("config.yml").getString("Database.host")), 
				event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "HOST ADDRESS";
					placeHolders[15] = "localhost";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "HOST ADDRESS";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Database.host", ChatColor.stripColor(event.getMessage())); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(ItemHandler.getItem("STONE_BUTTON", 1, false, "&a&lPort", "&7", 
			"&7*Set the &c&lPort &7for", "&7the MySQL databse connection.", "&9&lPORT: &a" + ConfigHandler.getConfig().getFile("config.yml").getString("Database.port")), 
				event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "ADDRESS PORT";
					placeHolders[15] = "3306";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "ADDRESS PORT";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Database.port", Integer.parseInt(ChatColor.stripColor(event.getMessage()))); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
					} else {
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = ChatColor.stripColor(event.getMessage());
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					}
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(fillerPaneBItem));
			final String databaseString = (ConfigHandler.getConfig().getFile("config.yml").getString("Database.table") != null ? "Database.table" : "Database.database");
			databasePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_WOOD" : "17"), 1, false, "&a&lTable", "&7", 
			"&7*Set the &c&lTable &7for", "&7the MySQL databse connection.", "&9&lTABLE: &a" + ConfigHandler.getConfig().getFile("config.yml").getString(databaseString)), 
				event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TABLE NAME";
					placeHolders[15] = "ITEMJOIN_LOCAL";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TABLE NAME";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set(databaseString, ChatColor.stripColor(event.getMessage())); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(fillerPaneBItem));
			databasePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&a&lPrefix", "&7", 
			"&7*Set the &c&lTable &7for", "&7the MySQL databse connection.", "&9&lTABLE: &a" + ConfigHandler.getConfig().getFile("config.yml").getString("Database.prefix")), 
				event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TABLE PREFIX";
					placeHolders[15] = "IJ_";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TABLE PREFIX";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Database.prefix", ChatColor.stripColor(event.getMessage())); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(fillerPaneBItem));
			databasePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_STAIRS" : "53"), 1, false, "&a&lUser", "&7", 
			"&7*Set the &c&lUser &7for", "&7the MySQL databse connection.", "&9&lUSER: &a***********"), 
				event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "USER";
					placeHolders[15] = "rockinchaos";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "USER";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Database.user", ChatColor.stripColor(event.getMessage())); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&a&lPassword", "&7", 
			"&7*Set the &c&lPassword &7for", "&7the MySQL databse connection.", "&9&lPORT: &a****"),  
				event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "PASSWORD";
					placeHolders[15] = "cooldude6";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "PASSWORD";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Database.pass", ChatColor.stripColor(event.getMessage())); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> databasePane(player));
				}));
			databasePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the config settings menu."), event -> configSettings(player)));
			databasePane.addButton(new Button(fillerPaneBItem), 7);
			databasePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the config settings menu."), event -> configSettings(player)));
		});
		databasePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void triggerPane(final Player player, final int stage) {
		final Interface triggerPane = new Interface(false, 3, GUIName, player);
		final String triggerOption = (stage == 4 ? "&7*Executes the commands when the" : (stage == 0 ? "&7*Gives the custom item when the" : "&7*Sets the held item slot when the"));
		final String triggerString = (stage == 4 ? "Active-Commands.triggers" : (stage == 0 ? "Settings.Default-Triggers" : "Settings.HeldItem-Triggers"));
		SchedulerUtils.runAsync(() -> {
			List<String> triggers = new ArrayList<String>();
			try {
				for (String trigger: ConfigHandler.getConfig().getFile("config.yml").getString(triggerString).replace(" ", "").split(",")) {
					if (trigger != null && !trigger.isEmpty()) {
						triggers.add(trigger);
					}
				}
			} catch (Exception e) {}
			triggerPane.addButton(new Button(fillerPaneBItem), 3);
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "FILLED_MAP" : "MAP"), 1, StringUtils.containsValue(triggers, "FIRST-JOIN"), "&e&l&nFirst Join", "&7", triggerOption, "&7player logs into the server", 
					"&7for the first time only.", "&7This will overwrite any triggers", "&7such as respawn, and world-switch.", "&9&lENABLED: &a" + (StringUtils.containsValue(triggers, "FIRST-JOIN") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "FIRST-JOIN")) {
					triggers.remove("FIRST-JOIN");
				} else {
					triggers.add("FIRST-JOIN");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("STONE_SWORD", 1, StringUtils.containsValue(triggers, "FIRST-WORLD"), "&e&l&nFirst World", "&7", triggerOption, "&7player enters each of the defined", "&7worlds for the first time.", "&7", 
					"&7This flag overwrites any triggers", "&7such as respawn, and join.", "&9&lENABLED: &a" + (StringUtils.containsValue(triggers, "FIRST-WORLD") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "FIRST-WORLD")) {
					triggers.remove("FIRST-WORLD");
				} else {
					triggers.add("FIRST-WORLD");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem(ServerUtils.hasSpecificUpdate("1_13") ? "TOTEM_OF_UNDYING" : "322:1", 1, StringUtils.containsValue(triggers, "FIRST-LIFE"), "&e&l&nFirst Life", "&7", triggerOption, "&7player logs into the server", 
					"&7for the first time only,", "&7but will give the item", "&7EVERY TIME on player RESPAWN.", "&7This flag overwrites any triggers", "&7such as respawn, and join.", "&9&lENABLED: &a" + (StringUtils.containsValue(triggers, "FIRST-LIFE") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "FIRST-LIFE")) {
					triggers.remove("FIRST-LIFE");
				} else {
					triggers.add("FIRST-LIFE");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(fillerPaneBItem), 3);
			triggerPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, (StringUtils.containsValue(triggers, "DISABLE") || StringUtils.containsValue(triggers, "DISABLED")), "&c&l&nDISABLED", "&7", "&7*Disables the use of triggers", "&7for this section.", "&7", "&9&lENABLED: &a" + ((StringUtils.containsValue(triggers, "DISABLE") || StringUtils.containsValue(triggers, "DISABLED")) + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "DISABLE") || StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED"); 
					triggers.remove("DISABLE");
				} else if (!(StringUtils.containsValue(triggers, "DISABLE") || StringUtils.containsValue(triggers, "DISABLED"))) {
					triggers.add("DISABLED"); 
					triggers.remove("JOIN");
					triggers.remove("FIRST-JOIN");
					triggers.remove("FIRST-WORLD");
					triggers.remove("FIRST-LIFE");
					triggers.remove("RESPAWN");
					triggers.remove("WORLD-SWITCH");
					triggers.remove("GAMEMODE-SWITCH");
					triggers.remove("REDGION-ENTER");
					triggers.remove("REGION-LEAVE");
					triggers.remove("REGION-ACCESS");
					triggers.remove("REGION-ENGRESS");
				} 
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_SIGN" : "323"), 1, StringUtils.containsValue(triggers, "JOIN"), "&e&l&nJoin", "&7", triggerOption, "&7player logs into the server.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(triggers, "JOIN") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "JOIN")) {
					triggers.remove("JOIN");
				} else {
					triggers.add("JOIN");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, StringUtils.containsValue(triggers, "RESPAWN"), "&e&l&nRespawn", "&7", triggerOption, "&7player respawns from a death event.", "&9&lENABLED: &a" + 
			(StringUtils.containsValue(triggers, "RESPAWN") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "RESPAWN")) {
					triggers.remove("RESPAWN");
				} else {
					triggers.add("RESPAWN");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("STONE_BUTTON", 1, StringUtils.containsValue(triggers, "WORLD-SWITCH"), "&e&l&nWorld Switch", "&7", triggerOption, "&7player teleports to one", "&7of the specified worlds.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(triggers, "WORLD-SWITCH") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "WORLD-SWITCH")) {
					triggers.remove("WORLD-SWITCH");
				} else {
					triggers.add("WORLD-SWITCH");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("LEVER", 1, StringUtils.containsValue(triggers, "GAMEMODE-SWITCH"), "&e&l&nGamemode Switch", "&7", triggerOption, "&7player changes gamemodes to any", "&7of the defined limit-modes.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(triggers, "GAMEMODE-SWITCH") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "GAMEMODE-SWITCH")) {
					triggers.remove("GAMEMODE-SWITCH");
				} else {
					triggers.add("GAMEMODE-SWITCH");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("MINECART", 1, StringUtils.containsValue(triggers, "REGION-ENTER"), "&e&l&nRegion Enter", "&7", triggerOption, "&7player enters any of the enabled-regions.", "&9&lENABLED: &a" +
			(StringUtils.containsValue(triggers, "REGION-ENTER") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "REGION-ENTER")) {
					triggers.remove("REGION-ENTER");
				} else {
					triggers.add("REGION-ENTER");
					triggers.add("REGION-ACCESS");
					triggers.add("REGION-ENGRESS");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "HOPPER_MINECRAFT" : "408"), 1, StringUtils.containsValue(triggers, "REGION-LEAVE"), "&e&l&nRegion Leave", "&7", triggerOption.replace("Gives", "Removes"), "&7player leaves any of the enabled-regions.", "&9&lENABLED: &a" +
			(StringUtils.containsValue(triggers, "REGION-LEAVE") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "REGION-LEAVE")) {
					triggers.remove("REGION-LEAVE");
				} else {
					triggers.add("REGION-LEAVE");
					triggers.remove("REGION-ACCESS");
					triggers.remove("REGION-ENGRESS");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "TNT_MINECART" : "407"), 1, StringUtils.containsValue(triggers, "REGION-ACCESS"), "&e&l&nRegion Access", "&7", triggerOption, "&7player enters any of the enabled-regions", "&7and removes the item when leaving", "&7any of the enabled-regions.", "&9&lENABLED: &a" +
			(StringUtils.containsValue(triggers, "REGION-ACCESS") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "REGION-ACCESS")) {
					triggers.remove("REGION-ACCESS");
				} else {
					triggers.add("REGION-ACCESS");
					triggers.remove("REGION-ENTER");
					triggers.remove("REGION-LEAVE");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CHEST_MINECART" : "342"), 1, StringUtils.containsValue(triggers, "REGION-ENGRESS"), "&e&l&nRegion Engress", "&7", triggerOption.replace("Gives", "Removes"), "&7player enters any of the enabled-regions", "&7and gives the item when leaving", "&7any of the enabled-regions.", "&9&lENABLED: &a" +
			(StringUtils.containsValue(triggers, "REGION-ENGRESS") + "").toUpperCase()), event -> {
				if (StringUtils.containsValue(triggers, "REGION-ENGRESS")) {
					triggers.remove("REGION-ENGRESS");
				} else {
					triggers.add("REGION-ENGRESS");
					triggers.remove("REGION-ENTER");
					triggers.remove("REGION-LEAVE");
				}
				if (triggers.isEmpty()) { 
					triggers.add("DISABLED"); 
				} else if (StringUtils.containsValue(triggers, "DISABLED")) {
					triggers.remove("DISABLED");
				} else if (StringUtils.containsValue(triggers, "DISABLE")) {
					triggers.remove("DISABLE");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set(triggerString, triggers.toString().replace("[", "").replace("]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> triggerPane(player, stage));
			}));
			if (stage == 4) {
				triggerPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> activeCommands(player)));
			} else {
				triggerPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
			}
			triggerPane.addButton(new Button(fillerPaneBItem), 7);
			if (stage == 4) {
				triggerPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> activeCommands(player)));
			} else {
				triggerPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
			}
		});
		triggerPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void preventPane(final Player player) {
		Interface preventPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			List<String> bypassList = new ArrayList<String>();
			for (String bypass: ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Bypass").replace(" ", "").split(",")) {
				if (bypass != null && !bypass.isEmpty()) {
					bypassList.add(bypass);
				}
			}
			preventPane.addButton(new Button(fillerPaneBItem), 3);
			preventPane.addButton(new Button(ItemHandler.getItem(StringUtils.containsValue(bypassList, "CREATIVE") ? (ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1") : (ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_APPLE" : "322"), 1, StringUtils.containsValue(bypassList, "CREATIVE"), 
					"&bCreative Bypass", "&7", "&7*Players in creative mode", "&7will ignore the prevent actions.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(bypassList, "CREATIVE") + "").toUpperCase()), 
					event -> {
						if (StringUtils.containsValue(bypassList, "CREATIVE")) {
							bypassList.remove("CREATIVE");
						} else {
							bypassList.add("CREATIVE");
						}
						if (bypassList.isEmpty()) {
							bypassList.add("DISABLED");
						} else if (StringUtils.containsValue(bypassList, "DISABLED")) {
							bypassList.remove("DISABLED");
						} else if (StringUtils.containsValue(bypassList, "DISABLE")) {
							bypassList.remove("DISABLE");
						}
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Prevent.Bypass", bypassList.toString().replace("[", "").replace("]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> preventPane(player));
					}));
			preventPane.addButton(new Button(fillerPaneBItem));
			preventPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, StringUtils.containsValue(bypassList, "OP"), 
					"&bOP Bypass", "&7", "&7*Players that are OP", "&7will ignore the prevent actions.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(bypassList, "OP") + "").toUpperCase()), 
					event -> {
						if (StringUtils.containsValue(bypassList, "OP")) {
							bypassList.remove("OP");
						} else {
							bypassList.add("OP");
						}
						if (bypassList.isEmpty()) {
							bypassList.add("DISABLED");
						} else if (StringUtils.containsValue(bypassList, "DISABLED")) {
							bypassList.remove("DISABLED");
						} else if (StringUtils.containsValue(bypassList, "DISABLE")) {
							bypassList.remove("DISABLE");
						}
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Prevent.Bypass", bypassList.toString().replace("[", "").replace("]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> preventPane(player));
					}));
			preventPane.addButton(new Button(fillerPaneBItem), 4);
			preventPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, 
					"&c&l&nPrevent Pickups", "&7", "&7*Prevent players from picking up", "&7ANY items, not just custom items.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Pickups"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Pickups") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Prevent.Pickups")));
			preventPane.addButton(new Button(fillerPaneBItem));
			preventPane.addButton(new Button(ItemHandler.getItem("BEDROCK", 1, false, 
					"&c&l&nPrevent Movement", "&7", "&7*Prevent players from moving", "&7ANY items around in their", "&7inventory, not just custom items.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.itemMovement"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.itemMovement") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Prevent.itemMovement")));
			preventPane.addButton(new Button(fillerPaneBItem));
			preventPane.addButton(new Button(ItemHandler.getItem("HOPPER", 1, false, 
					"&c&l&nPrevent Drops", "&7", "&7*Prevent players from dropping", "&7ANY items, not just custom items.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Self-Drops"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Self-Drops") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Prevent.Self-Drops")));
			preventPane.addButton(new Button(fillerPaneBItem));
			preventPane.addButton(new Button(ItemHandler.getItem("BONE", 1, false, 
					"&c&l&nPrevent Death Drops", "&7", "&7*Prevent players from dropping", "&7ANY items on death, not just custom items.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Death-Drops"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Prevent.Death-Drops") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Prevent.Death-Drops")));
			preventPane.addButton(new Button(fillerPaneBItem));
			preventPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
			preventPane.addButton(new Button(fillerPaneBItem), 7);
			preventPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
		});
		preventPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void clearPane(final Player player) {
		Interface clearPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			clearPane.addButton(new Button(fillerPaneBItem), 3);
			clearPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type").equalsIgnoreCase("ALL"), 
					"&bType: &a&lALL", "&7", "&7*ALL items including other plugin(s)", "&7and vanilla items should be cleared", "&7upon performing a trigger.", 
					"&9&lENABLED: &a" + (ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type").equalsIgnoreCase("ALL") + "").toUpperCase()), 
					event -> {
						if (!ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type").equalsIgnoreCase("ALL")) {
							File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
							FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
							dataFile.set("Clear-Items.Type", "ALL"); 	
							ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
							ConfigHandler.getConfig().softReload();
							SchedulerUtils.runLater(2L, () -> clearPane(player));
						}
					}));
			clearPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "342"), 1, false, 
					"&b&lClear Delay", "&7", "&7*The number of second(s)", "&7to wait before clearing", "&7items from the player inventory.", 
					"&9&lDelay: &a" + (ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Delay-Tick") + "").toUpperCase()), 
					event -> numberPane(player, 3)));
			clearPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PISTON" : "33"), 1, ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type").equalsIgnoreCase("ITEMJOIN"), 
					"&bType: &a&lITEMJOIN", "&7", "&7*Only ItemJoin (custom items)", "&7should be cleared upon", "&7performing a trigger.", 
					"&9&lENABLED: &a" + (ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type").equalsIgnoreCase("ITEMJOIN") + "").toUpperCase()), 
					event -> {
						if (!ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Type").equalsIgnoreCase("ITEMJOIN")) {
							File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
							FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
							dataFile.set("Clear-Items.Type", "ITEMJOIN"); 	
							ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
							ConfigHandler.getConfig().softReload();
							SchedulerUtils.runLater(2L, () -> clearPane(player));
						}
					}));
			clearPane.addButton(new Button(fillerPaneBItem), 3);
			clearPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_SIGN" : "323"), 1, false, 
					"&c&l&nJoin", "&7", "&7*Clears the items from the", "&7player upon joining the server.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Join"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Join") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Clear-Items.Join")));
			clearPane.addButton(new Button(ItemHandler.getItem("LAVA_BUCKET", 1, false, 
					"&c&l&nQuit", "&7", "&7*Clears the items from the", "&7player upon quiting the server.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Quit"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Quit") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Clear-Items.Quit")));
			clearPane.addButton(new Button(fillerPaneBItem));
			clearPane.addButton(new Button(ItemHandler.getItem("STONE_BUTTON", 1, false, 
					"&c&l&nWorld-Switch", "&7", "&7*Clears the items from the", "&7player upon changing worlds.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.World-Switch"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.World-Switch") : "FALSE")).toUpperCase()), 
					event -> worldPane(player, "Clear-Items.World-Switch")));
			clearPane.addButton(new Button(fillerPaneBItem));
			clearPane.addButton(new Button(ItemHandler.getItem("MINECART", 1, false, 
					"&c&l&nRegion-Enter", "&7", "&7*Clears the items from the", "&7player upon entering", "&7a WorldGuard region.", 
					(DependAPI.getDepends(false).getGuard().guardEnabled() ? "&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Region-Enter"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Region-Enter") : "FALSE")).toUpperCase() : ""), (DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&7"), 
					(DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&c&lERROR: &7WorldGuard was NOT found."), (DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&7This button will do nothing...")), 
					event -> {
						if (DependAPI.getDepends(false).getGuard().guardEnabled()) {
							worldPane(player, "Clear-Items.Region-Enter");
						}
					}));
			clearPane.addButton(new Button(fillerPaneBItem));
			clearPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COMMAND_BLOCK" : "137"), 1, false, 
					"&b&lOptions", "&7", "&7*Actions to apply to", "&7the clear items triggers", "&7such as OP bypass.", 
					"&9&lENABLED: &a" + ((!StringUtils.containsIgnoreCase(ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options"), "DISABLE") ? 
					ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options") : "FALSE")).toUpperCase()), 
					event -> optionPane(player)));
			clearPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, 
					"&b&lBlackList", "&7", "&7*Materials, Slots, or Item Names", "&7to be blacklisted from being", "&7cleared upon performing a trigger.", 
					"&9&lENABLED: &a" + (!ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Blacklist").isEmpty() + "").toUpperCase()), 
					event -> blacklistPane(player)));
			clearPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
			clearPane.addButton(new Button(fillerPaneBItem), 7);
			clearPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item settings menu."), event -> itemSettings(player)));
		});
		clearPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void blacklistPane(final Player player) {
		Interface blacklistPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			String[] blacklist = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Blacklist").split(",");
			List<String> materials = new ArrayList<String>();
			List<String> slots = new ArrayList<String>();
			List<String> names = new ArrayList<String>();
			try {
				if (blacklist != null) {
					for (String value: blacklist) {
						String valType = (StringUtils.containsIgnoreCase(value, "{id") ? "id" : (StringUtils.containsIgnoreCase(value, "{slot") ? "slot" : (StringUtils.containsIgnoreCase(value, "{name") ? "name" : "")));
						String inputResult = org.apache.commons.lang.StringUtils.substringBetween(value, "{" + valType + ":", "}");
						if (valType.equalsIgnoreCase("id") && ItemHandler.getMaterial(inputResult.trim(), null) != null) {
							materials.add(inputResult.trim().toUpperCase());
						} else if (valType.equalsIgnoreCase("slot")) {
							slots.add(inputResult.trim().toUpperCase());
						} else if (valType.equalsIgnoreCase("name")) {
							names.add(inputResult.trim());
						}
					}
				}
			} catch (Exception e) { }
			blacklistPane.addButton(new Button(fillerPaneBItem), 3);
			blacklistPane.addButton(new Button(ItemHandler.getItem("DIAMOND_SWORD", 1, false, 
					"&b&l&nMaterials", "&7", "&7*The material to be blacklisted", "&7from being cleared.", "&7",
					"&9&lMaterials: &a" + ((!materials.isEmpty() ? StringUtils.replaceLast(materials.toString().replaceFirst("\\[", ""), "]", "") : "NONE"))), 
					event -> blacklistMatPane(player)));
			blacklistPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GLASS" : "20"), 1, false, 
					"&b&l&nSlots", "&7", "&7*The inventory slots to be", "&7blacklisted from being cleared.", "&7",
					"&9&lSlots: &a" + ((!slots.isEmpty() ? StringUtils.replaceLast(slots.toString().replaceFirst("\\[", ""), "]", "") : "NONE"))), 
					event -> blacklistSlotPane(player)));
			blacklistPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, 
					"&b&l&nNames", "&7", "&7*The items display names to", "&7be blacklisted from being cleared.", "&7",
					"&9&lNames: &a" + ((!names.isEmpty() ? StringUtils.replaceLast(names.toString().replaceFirst("\\[", ""), "]", "") : "NONE"))), 
					event -> blacklistNamePane(player)));
			blacklistPane.addButton(new Button(fillerPaneBItem), 3);
			blacklistPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the clear settings."), event -> clearPane(player)));
			blacklistPane.addButton(new Button(fillerPaneBItem), 7);
			blacklistPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the clear settings."), event -> clearPane(player)));
		});
		blacklistPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void blacklistMatPane(final Player player) {
		Interface materialPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			materialPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the blacklist menu."), event -> blacklistPane(player)));
			String[] blacklist = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Blacklist").split(",");
			List<String> materials = new ArrayList<String>();
			List<String> saveList = new ArrayList<String>();
			try {
				if (blacklist != null) {
					for (String value: blacklist) {
						String valType = (StringUtils.containsIgnoreCase(value, "{id") ? "id" : (StringUtils.containsIgnoreCase(value, "{slot") ? "slot" : (StringUtils.containsIgnoreCase(value, "{name") ? "name" : "")));
						String inputResult = org.apache.commons.lang.StringUtils.substringBetween(value, "{" + valType + ":", "}");
						if (valType.equalsIgnoreCase("id") && ItemHandler.getMaterial(inputResult.trim(), null) != null) {
							materials.add(inputResult.trim().toUpperCase());
						} else if (!valType.equalsIgnoreCase("id") && !value.isEmpty()) {
							saveList.add(value.trim());
						}
					}
				}
			} catch (Exception e) { }
			materialPane.addButton(new Button(ItemHandler.getItem("STICK", 1, true, "&b&lBukkit Material", "&7", "&7*If you know the name", "&7of the BUKKIT material type", "&7simply click and type it."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "BUKKIT MATERIAL";
				placeHolders[15] = "IRON_SWORD";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null) != null) {
					if (!StringUtils.containsValue(materials, ChatColor.stripColor(event.getMessage()))) {
						materials.add(ChatColor.stripColor(event.getMessage()).toUpperCase());
					} else {
						materials.remove(ChatColor.stripColor(event.getMessage()).toUpperCase());
					}
					for (String mat : materials) {
						saveList.add("{id:" + mat + "}");
					}
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "BUKKIT MATERIAL";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> blacklistMatPane(player));
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noMaterial", player, placeHolders);
					blacklistMatPane(player);
				}
			}));
			Inventory inventoryCheck = Bukkit.getServer().createInventory(null, 9, GUIName);
			for (Material material: Material.values()) {
				if (!material.name().contains("LEGACY") && material.name() != "AIR" && safeMaterial(ItemHandler.getItem(material.toString(), 1, false, "", ""), inventoryCheck)) {
					materialPane.addButton(new Button(ItemHandler.getItem(material.toString(), 1, StringUtils.containsValue(materials, material.name()), "", "&7", "&7*Click to set the material.", "&7to be blacklisted from clearing.",
					"&7", (StringUtils.containsValue(materials, material.name()) ? "&a&l&nENABLED: &e&lYES" : "")), event -> {
						if (!StringUtils.containsValue(materials, material.name())) {
							materials.add(material.name());
						} else {
							materials.remove(material.name());
						}
						for (String mat : materials) {
							saveList.add("{id:" + mat + "}");
						}
						File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> blacklistMatPane(player));
					}));
				}
			}
			inventoryCheck.clear();
		});
		materialPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void blacklistSlotPane(final Player player) {
		Interface slotPane = new Interface(true, 6, GUIName, player);
		Interface craftingPane = new Interface(false, 4, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			slotPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the blacklist menu."), event -> blacklistPane(player)));
			String[] blacklist = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Blacklist").split(",");
			List<String> slots = new ArrayList<String>();
			List<String> saveList = new ArrayList<String>();
			try {
				if (blacklist != null) {
					for (String value: blacklist) {
						String valType = (StringUtils.containsIgnoreCase(value, "{id") ? "id" : (StringUtils.containsIgnoreCase(value, "{slot") ? "slot" : (StringUtils.containsIgnoreCase(value, "{name") ? "name" : "")));
						String inputResult = org.apache.commons.lang.StringUtils.substringBetween(value, "{" + valType + ":", "}");
						if (valType.equalsIgnoreCase("slot")) {
							slots.add(inputResult.trim().toUpperCase());
						} else if (!value.isEmpty()) {
							saveList.add(value.trim());
						}
					}
				}
			} catch (Exception e) { }
			craftingPane.addButton(new Button(fillerPaneGItem), 3);
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, StringUtils.containsValue(slots, "CRAFTING[1]"), "&9&lSlot: &7&lCRAFTING&a&l[1]", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "CRAFTING[1]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "CRAFTING[1]")) {
					slots.add("CRAFTING[1]");
				} else {
					slots.remove("CRAFTING[1]");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			craftingPane.addButton(new Button(fillerPaneGItem));
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 2, StringUtils.containsValue(slots, "CRAFTING[2]"), "&9&lSlot: &7&lCRAFTING&a&l[2]", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "CRAFTING[2]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "CRAFTING[2]")) {
					slots.add("CRAFTING[2]");
				} else {
					slots.remove("CRAFTING[2]");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			craftingPane.addButton(new Button(fillerPaneGItem), 10);
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, StringUtils.containsValue(slots, "CRAFTING[0]"), "&9&lSlot: &7&lCRAFTING&a&l[0]", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "CRAFTING[0]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "CRAFTING[0]")) {
					slots.add("CRAFTING[0]");
				} else {
					slots.remove("CRAFTING[0]");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			craftingPane.addButton(new Button(fillerPaneGItem), 4);
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 3, StringUtils.containsValue(slots, "CRAFTING[3]"), "&9&lSlot: &7&lCRAFTING&a&l[3]", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "CRAFTING[3]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "CRAFTING[3]")) {
					slots.add("CRAFTING[3]");
				} else {
					slots.remove("CRAFTING[3]");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			craftingPane.addButton(new Button(fillerPaneGItem));
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 4, StringUtils.containsValue(slots, "CRAFTING[4]"), "&9&lSlot: &7&lCRAFTING&a&l[4]", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "CRAFTING[4]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "CRAFTING[4]")) {
					slots.add("CRAFTING[4]");
				} else {
					slots.remove("CRAFTING[4]");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			craftingPane.addButton(new Button(fillerPaneGItem), 3);
			craftingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the slot blacklist menu"), event -> blacklistSlotPane(player)));
			craftingPane.addButton(new Button(fillerPaneBItem), 7);
			craftingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the slot blacklist menu"), event -> blacklistSlotPane(player)));
			slotPane.addButton(new Button(fillerPaneGItem));
			slotPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, false, "&9&lSlot: &a&lCRAFTING", "&7", "&7*Click to see a list of crafting slots"), event -> craftingPane.open(player)));
			slotPane.addButton(new Button(fillerPaneGItem));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_HELMET", 1, StringUtils.containsValue(slots, "HELMET"), "&9&lSlot: &a&lHELMET", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "HELMET")? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "HELMET")) {
					slots.add("HELMET");
				} else {
					slots.remove("HELMET");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_CHESTPLATE", 1, StringUtils.containsValue(slots, "CHESTPLATE"), "&9&lSlot: &a&lCHESTPLATE", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "CHESTPLATE") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "CHESTPLATE")) {
					slots.add("CHESTPLATE");
				} else {
					slots.remove("CHESTPLATE");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_LEGGINGS", 1, StringUtils.containsValue(slots, "LEGGINGS"), "&9&lSlot: &a&lLEGGINGS", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.",
				(StringUtils.containsValue(slots, "LEGGINGS") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "LEGGINGS")) {
					slots.add("LEGGINGS");
				} else {
					slots.remove("LEGGINGS");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_BOOTS", 1, StringUtils.containsValue(slots, "BOOTS"), "&9&lSlot: &a&lBOOTS", "&7", "&7*Click to prevent this slot", "&7from having its items cleared.", 
				(StringUtils.containsValue(slots, "BOOTS") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (!StringUtils.containsValue(slots, "BOOTS")) {
					slots.add("BOOTS");
				} else {
					slots.remove("BOOTS");
				}
				for (String slot : slots) {
					saveList.add("{slot:" + slot + "}");
				}
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
			}));
			if (ServerUtils.hasSpecificUpdate("1_9")) {
				slotPane.addButton(new Button(ItemHandler.getItem("SHIELD", 1, StringUtils.containsValue(slots, "OFFHAND"), "&9&lSlot: &a&lOFFHAND", "&7", "&7*Click to prevent this slot", "&7from having its item cleared.",
					(StringUtils.containsValue(slots, "OFFHAND") ? "&9&lENABLED: &aTRUE" : "")), event -> {
					if (!StringUtils.containsValue(slots, "OFFHAND")) {
						slots.add("OFFHAND");
					} else {
						slots.remove("OFFHAND");
					}
					for (String slot : slots) {
						saveList.add("{slot:" + slot + "}");
					}
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
				}));
			} else {
				slotPane.addButton(new Button(fillerPaneGItem));
			}
			slotPane.addButton(new Button(fillerPaneGItem));
			for (int i = 9; i < 36; i++) {
				final int slot = i;
				slotPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIGHT_BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:3"), i, (StringUtils.containsValue(slots, String.valueOf(slot))), "&9&lSlot: &a&l" + i, "&7", "&7*Click to prevent this slot", 
					"&7from having its item cleared.", (StringUtils.containsValue(slots, String.valueOf(slot)) ? "&9&lENABLED: &aTRUE" : "")), event -> {
					if (!StringUtils.containsValue(slots, String.valueOf(slot))) {
						slots.add(String.valueOf(slot));
					} else {
						slots.remove(String.valueOf(slot));
					}
					for (String slotS : slots) {
						saveList.add("{slot:" + slotS + "}");
					}
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
				}));
			}
			for (int j = 0; j < 9; j++) {
				final int slot = j;
				int count = j;
				if (slot == 0) {
					count = 1;
				}
				slotPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), count, (StringUtils.containsValue(slots, String.valueOf(slot))), "&9&lSlot: &a&l" + j, "&7", "&7*Click to prevent this slot", 
					"&7from having its item cleared.", (StringUtils.containsValue(slots, String.valueOf(slot)) ? "&9&lENABLED: &aTRUE" : "")), event -> {
					if (!StringUtils.containsValue(slots, String.valueOf(slot))) {
						slots.add(String.valueOf(slot));
					} else {
						slots.remove(String.valueOf(slot));
					}
					for (String slotS : slots) {
						saveList.add("{slot:" + slotS + "}");
					}
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> blacklistSlotPane(player));
				}));
			}
			slotPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the blacklist menu."), event -> blacklistPane(player)));
			slotPane.addButton(new Button(fillerPaneBItem), 7);
			slotPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the blacklist menu."), event -> blacklistPane(player)));
		});
		slotPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void blacklistNamePane(final Player player) {
		Interface namePane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			namePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the blacklist menu."), event -> blacklistPane(player)));
			String[] blacklist = ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Blacklist").split(",");
			List<String> names = new ArrayList<String>();
			List<String> saveList = new ArrayList<String>();
			try {
				if (blacklist != null) {
					for (String value: blacklist) {
						String valType = (StringUtils.containsIgnoreCase(value, "{id") ? "id" : (StringUtils.containsIgnoreCase(value, "{slot") ? "slot" : (StringUtils.containsIgnoreCase(value, "{name") ? "name" : "")));
						String inputResult = org.apache.commons.lang.StringUtils.substringBetween(value, "{" + valType + ":", "}");
						if (valType.equalsIgnoreCase("name")) {
							names.add(inputResult.trim().toUpperCase());
						} else if (!value.isEmpty()) {
							saveList.add(value.trim());
						}
					}
				}
			} catch (Exception e) { }
			namePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&b&lAdd Name", "&7", "&7*Add an items display", "&7name to be blacklisted", "&7simply click and type it.", "&7", 
				"&c&l&nNOTE:&7 Do NOT include any", "&7color codes as these are excluded."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ITEM NAME";
				placeHolders[15] = "Ultra Item";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (!StringUtils.containsValue(names, ChatColor.stripColor(event.getMessage()))) {
					names.add(ChatColor.stripColor(event.getMessage()));
				} else {
					names.remove(ChatColor.stripColor(event.getMessage()));
				}
				for (String name : names) {
					saveList.add("{name:" + name + "}");
				}
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ITEM NAME";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
				FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
				dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
				ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
				ConfigHandler.getConfig().softReload();
				SchedulerUtils.runLater(2L, () -> blacklistNamePane(player));
			}));
			for (String itemName : names) {
				namePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&f" + itemName, "&7", "&7*Click to remove this item name", "&7from the clearing blacklist.", "&7", 
					"&c&l&nNOTE:&7 Do NOT include any", "&7color codes as these are excluded."), event -> {
					names.remove(itemName);
					for (String name : names) {
						saveList.add("{name:" + name + "}");
					}
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Clear-Items.Blacklist", StringUtils.replaceLast(saveList.toString().replaceFirst("\\[", ""), "]", "")); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> blacklistNamePane(player));
				}));
			}
		});
		namePane.open(player);
	}

   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void optionPane(final Player player) {
		Interface optionPane = new Interface(false, 2, GUIName, player);
		List<String> optionList = new ArrayList<String>();
		for (String option: ConfigHandler.getConfig().getFile("config.yml").getString("Clear-Items.Options").replace(" ", "").split(",")) {
			if (option != null && !option.isEmpty()) {
				optionList.add(option);
			}
		}
		SchedulerUtils.runAsync(() -> {
			optionPane.addButton(new Button(ItemHandler.getItem("DIAMOND_CHESTPLATE", 1, StringUtils.containsValue(optionList, "PROTECT"), 
					"&e&lProtect", "&7", "&7*Prevents ALL players from", "&7having their first-join and", "&7first-world items cleared.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(optionList, "PROTECT") + "").toUpperCase()), 
					event -> {
						if (StringUtils.containsValue(optionList, "PROTECT")) {
							optionList.remove("PROTECT");
						} else {
							optionList.add("PROTECT");
						}
						if (optionList.isEmpty()) {
							optionList.add("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLED")) {
							optionList.remove("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLE")) {
							optionList.remove("DISABLE");
						}
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Clear-Items.Options", optionList.toString().replace("[", "").replace("]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> optionPane(player));
					}));
			optionPane.addButton(new Button(fillerPaneBItem));
			optionPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, StringUtils.containsValue(optionList, "PROTECT_OP"), 
					"&e&lProtect OP", "&7", "&7*Prevents OP players from", "&7having their first-join and", "&7first-world items cleared.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(optionList, "PROTECT_OP") + "").toUpperCase()), 
					event -> {
						if (StringUtils.containsValue(optionList, "PROTECT_OP")) {
							optionList.remove("PROTECT_OP");
						} else {
							optionList.add("PROTECT_OP");
						}
						if (optionList.isEmpty()) {
							optionList.add("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLED")) {
							optionList.remove("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLE")) {
							optionList.remove("DISABLE");
						}
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Clear-Items.Options", optionList.toString().replace("[", "").replace("]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> optionPane(player));
					}));
			optionPane.addButton(new Button(fillerPaneBItem));
			optionPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_APPLE" : "322"), 1, StringUtils.containsValue(optionList, "PROTECT_CREATIVE"), 
					"&e&lProtect Creative", "&7", "&7*Prevents players in creative mode", "&7from having their first-join", "&7and first-world items cleared.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(optionList, "PROTECT_CREATIVE") + "").toUpperCase()), 
					event -> {
						if (StringUtils.containsValue(optionList, "PROTECT_CREATIVE")) {
							optionList.remove("PROTECT_CREATIVE");
						} else {
							optionList.add("PROTECT_CREATIVE");
						}
						if (optionList.isEmpty()) {
							optionList.add("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLED")) {
							optionList.remove("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLE")) {
							optionList.remove("DISABLE");
						}
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Clear-Items.Options", optionList.toString().replace("[", "").replace("]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> optionPane(player));
					}));
			optionPane.addButton(new Button(fillerPaneBItem));
			optionPane.addButton(new Button(ItemHandler.getItem("GOLD_BLOCK", 1, (StringUtils.containsValue(optionList, "RETURN") && DependAPI.getDepends(false).getGuard().guardEnabled()), 
					"&e&lReturn Regions", "&7*Returns the cleared player inventory", "&7when exiting a cleared region", "&7or entering a region which is", "&7not listed as clearable.", (DependAPI.getDepends(false).getGuard().guardEnabled() ? 
					"&9&lENABLED: &a" + (StringUtils.containsValue(optionList, "RETURN") ? "true" : "false") : ""), (DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&7"), 
					(DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&c&lERROR: &7WorldGuard was NOT found."), (DependAPI.getDepends(false).getGuard().guardEnabled() ? "" : "&7This button will do nothing...")), 
					event -> {
						if (DependAPI.getDepends(false).getGuard().guardEnabled()) {
							if (StringUtils.containsValue(optionList, "RETURN")) {
								optionList.remove("RETURN");
							} else {
								optionList.add("RETURN");
							}
							if (optionList.isEmpty()) {
								optionList.add("DISABLED");
							} else if (StringUtils.containsValue(optionList, "DISABLED")) {
								optionList.remove("DISABLED");
							} else if (StringUtils.containsValue(optionList, "DISABLE")) {
								optionList.remove("DISABLE");
							}
							File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
							FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
							dataFile.set("Clear-Items.Options", optionList.toString().replace("[", "").replace("]", "")); 	
							ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
							ConfigHandler.getConfig().softReload();
							SchedulerUtils.runLater(2L, () -> optionPane(player));
						}
					}));
			optionPane.addButton(new Button(fillerPaneBItem));
			optionPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, StringUtils.containsValue(optionList, "RETURN_SWITCH"), 
					"&e&lReturn Worlds", "&7", "&7*Returns the prior cleared", "&7player inventory from the", "&7prior world upon returning", "&7to that prior world.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(optionList, "RETURN_SWITCH") + "").toUpperCase()), 
					event -> {
						if (StringUtils.containsValue(optionList, "RETURN_SWITCH")) {
							optionList.remove("RETURN_SWITCH");
						} else {
							optionList.add("RETURN_SWITCH");
						}
						if (optionList.isEmpty()) {
							optionList.add("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLED")) {
							optionList.remove("DISABLED");
						} else if (StringUtils.containsValue(optionList, "DISABLE")) {
							optionList.remove("DISABLE");
						}
						File fileFolder = new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Clear-Items.Options", optionList.toString().replace("[", "").replace("]", "")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> optionPane(player));
					}));
			optionPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the clear settings."), event -> clearPane(player)));
			optionPane.addButton(new Button(fillerPaneBItem), 7);
			optionPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the clear settings."), event -> clearPane(player)));
		});
		optionPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    * @param section - The world section type.
    */
	private static void worldPane(final Player player, final String section) {
		Interface preventPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			preventPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the prevent menu."), event -> { 
				if (section.contains("Prevent")) {
					preventPane(player);
				} else {
					clearPane(player);	
				}
			}));
			List < String > enabledWorlds = new ArrayList < String > ();
			String[] enabledParts = ConfigHandler.getConfig().getFile("config.yml").getString(section).replace(" ,  ", ",").replace(" , ", ",").replace(",  ", ",").replace(", ", ",").split(",");
			for (String enabledWorld : enabledParts) {
				if (enabledWorld.equalsIgnoreCase("ALL") || enabledWorld.equalsIgnoreCase("GLOBAL")) {
					enabledWorlds.add("ALL");
				} else {
					for (World world: Bukkit.getServer().getWorlds()) {
						if (enabledWorld.equalsIgnoreCase(world.getName())) {
							enabledWorlds.add(world.getName());
						}
					}
				}
			}
		    if (enabledWorlds.isEmpty() && ConfigHandler.getConfig().getFile("config.yml").getBoolean(section)) { enabledWorlds.add("ALL"); }
			preventPane.addButton(new Button(ItemHandler.getItem("OBSIDIAN", 1, StringUtils.containsValue(enabledWorlds, "ALL"), "&a&l&nGLOBAL", "&7", "&7*Click to enable &lALL WORLDS.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(enabledWorlds, "ALL") + "").toUpperCase()), event -> {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					if (StringUtils.containsValue(enabledWorlds, "ALL")) {
						dataFile.set(section, false); 
					} else {
						dataFile.set(section, true); 
					}
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> worldPane(player, section));
			}));
			for (World world: Bukkit.getServer().getWorlds()) {
				String worldMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2");
				if (world.getEnvironment().equals(Environment.NETHER)) {
					worldMaterial = "NETHERRACK";
				} else if (world.getEnvironment().equals(Environment.THE_END)) {
					worldMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "END_STONE" : "121");
				}
				preventPane.addButton(new Button(ItemHandler.getItem(worldMaterial, 1, StringUtils.containsValue(enabledWorlds, world.getName()), "&f&l" + world.getName(), "&7", 
						"&7*Click to enable this world.", "&9&lENABLED: &a" + (StringUtils.containsValue(enabledWorlds, world.getName()) + "").toUpperCase()), event -> {
					if (StringUtils.containsValue(enabledWorlds, world.getName())) {
						enabledWorlds.remove(world.getName());
					} else {
						enabledWorlds.add(world.getName());
					}
					if (!enabledWorlds.isEmpty() && enabledWorlds.size() > 1) {
						if (StringUtils.containsValue(enabledWorlds, "ALL")) {
							enabledWorlds.remove("ALL");
						} else if (StringUtils.containsValue(enabledWorlds, "GLOBAL")) {
							enabledWorlds.remove("GLOBAL");
						}
					}
					String worldList = "";
					for (String worldName : enabledWorlds) { worldList += worldName + ", "; }
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					if (enabledWorlds.isEmpty()) {
						dataFile.set(section, false); 
					} else {
						dataFile.set(section, worldList.substring(0, worldList.length() - 2)); 
					}
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> worldPane(player, section));
				}));
			}
		});
		preventPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * 
    * @param player - The Player to have the Pane opened.
    */
	private static void overwritePane(final Player player) {
		Interface overwritePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			overwritePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the configuration menu."), event -> itemSettings(player)));
			List < String > enabledWorlds = new ArrayList < String > ();
			String[] enabledParts = ConfigHandler.getConfig().getFile("items.yml").getString("items-Overwrite").replace(" ,  ", ",").replace(" , ", ",").replace(",  ", ",").replace(", ", ",").split(",");
			for (String enabledWorld : enabledParts) {
				if (enabledWorld.equalsIgnoreCase("ALL") || enabledWorld.equalsIgnoreCase("GLOBAL")) {
					enabledWorlds.add("ALL");
				} else {
					for (World world: Bukkit.getServer().getWorlds()) {
						if (enabledWorld.equalsIgnoreCase(world.getName())) {
							enabledWorlds.add(world.getName());
						}
					}
				}
			}
		    if (enabledWorlds.isEmpty() && ConfigHandler.getConfig().getFile("items.yml").getBoolean("items-Overwrite")) { enabledWorlds.add("ALL"); }
			overwritePane.addButton(new Button(ItemHandler.getItem("OBSIDIAN", 1, StringUtils.containsValue(enabledWorlds, "ALL"), "&a&l&nGLOBAL", "&7", "&7*Click to enable item", "&7overwriting in &lALL WORLDS.", 
					"&9&lENABLED: &a" + (StringUtils.containsValue(enabledWorlds, "ALL") + "").toUpperCase()), event -> {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					if (StringUtils.containsValue(enabledWorlds, "ALL")) {
						dataFile.set("items-Overwrite", false); 
					} else {
						dataFile.set("items-Overwrite", true); 
					}
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "items.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> overwritePane(player));
			}));
			for (World world: Bukkit.getServer().getWorlds()) {
				String worldMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2");
				if (world.getEnvironment().equals(Environment.NETHER)) {
					worldMaterial = "NETHERRACK";
				} else if (world.getEnvironment().equals(Environment.THE_END)) {
					worldMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "END_STONE" : "121");
				}
				overwritePane.addButton(new Button(ItemHandler.getItem(worldMaterial, 1, StringUtils.containsValue(enabledWorlds, world.getName()), "&f&l" + world.getName(), "&7", 
						"&7*Click to enable item", "&7overwriting in this world.", "&9&lENABLED: &a" + (StringUtils.containsValue(enabledWorlds, world.getName()) + "").toUpperCase()), event -> {
					if (StringUtils.containsValue(enabledWorlds, world.getName())) {
						enabledWorlds.remove(world.getName());
					} else {
						enabledWorlds.add(world.getName());
					}
					if (!enabledWorlds.isEmpty() && enabledWorlds.size() > 1) {
						if (StringUtils.containsValue(enabledWorlds, "ALL")) {
							enabledWorlds.remove("ALL");
						} else if (StringUtils.containsValue(enabledWorlds, "GLOBAL")) {
							enabledWorlds.remove("GLOBAL");
						}
					}
					String worldList = "";
					for (String worldName : enabledWorlds) { worldList += worldName + ", "; }
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "items.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					if (enabledWorlds.isEmpty()) {
						dataFile.set("items-Overwrite", false); 
					} else {
						dataFile.set("items-Overwrite", worldList.substring(0, worldList.length() - 2)); 
					}
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "items.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> overwritePane(player));
				}));
			}
		});
		overwritePane.open(player);
	}
	
// =======================================================================================================================================================================================================================================

//  ============================================== //
//             Item Definition Menus      	       //
//  ============================================== //
	
   /**
    * Checks if the ItemStack is a safe Material,
    * that it actually exists and is not AIR or NULL.
    * 
    * @param item - The ItemStack to be checked.
    * @param inventoryCheck - The Inventory used for checking the ItemStack.
    */
	private static boolean safeMaterial(final ItemStack item, final Inventory inventoryCheck) {
		inventoryCheck.setItem(0, item);
		if (inventoryCheck.getItem(0) != null && inventoryCheck.getItem(0).getType().name() != "AIR") {
			return true;
		}
		return false;
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items Material.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param stage - The stage of the modification.
    */
	private static void materialPane(final Player player, final ItemMap itemMap, final int stage, final int position) {
		Interface materialPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage != 0 && stage != 2 && stage != 3) {
				materialPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
					creatingPane(player, itemMap);
				}));
			} else if (stage == 2) {
				materialPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the commands menu."), event -> {
					commandPane(player, itemMap);
				}));
			} else if (stage == 3) {
				materialPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the recipe menu."), event -> {
					recipePane(player, itemMap);
				}));
			}
			materialPane.addButton(new Button(ItemHandler.getItem("STICK", 1, true, "&b&lBukkit Material", "&7", "&7*If you know the name", "&7of the BUKKIT material type", "&7simply click and type it."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				if (stage == 2) {
					placeHolders[16] = "ITEM COST";
				} else {
					placeHolders[16] = "BUKKIT MATERIAL";
				}
				placeHolders[15] = "IRON_SWORD";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null) != null) {
					if (stage == 2) {
						itemMap.setItemCost(ChatColor.stripColor(event.getMessage()).toUpperCase());
					} else if (stage != 3) { 
						itemMap.setMaterial(ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null)); 
						if (!ServerUtils.hasSpecificUpdate("1_13") && ChatColor.stripColor(event.getMessage()).contains(":")) {
							String[] dataValue = ChatColor.stripColor(event.getMessage()).split(":");
							if (StringUtils.isInt(dataValue[1])) {
								itemMap.setDataValue((short)Integer.parseInt(dataValue[1]));
							}	
						}
					}
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					if (stage == 2) {
						placeHolders[16] = "ITEM COST";
					} else {
						placeHolders[16] = "BUKKIT MATERIAL";
					}
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					if (stage == 3) {
						setIngredients(event.getPlayer(), itemMap, ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null).name(), position);
					} else if (stage == 2) {
						commandPane(event.getPlayer(), itemMap);
					} else {
						creatingPane(event.getPlayer(), itemMap);
					}
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noMaterial", player, placeHolders);
					materialPane(player, itemMap, stage, position);
				}
			}));
			Inventory inventoryCheck = Bukkit.getServer().createInventory(null, 9, GUIName);
			for (Material material: Material.values()) {
				if (!material.name().contains("LEGACY") && material.name() != "AIR" && safeMaterial(ItemHandler.getItem(material.toString(), 1, false, "", ""), inventoryCheck)) {
					if (!ServerUtils.hasSpecificUpdate("1_13") && LegacyAPI.getDataValue(material) != 0) {
						for (int i = 0; i <= LegacyAPI.getDataValue(material); i++) {
							if (!material.toString().equalsIgnoreCase("STEP") || material.toString().equalsIgnoreCase("STEP") && i != 2) {
								final int dataValue = i;
								materialPane.addButton(new Button(ItemHandler.getItem(material.toString() + ":" + dataValue, 1, false, "", "&7", "&7*Click to set the material."), event -> {
									if (stage == 2) {
										itemMap.setItemCost(material.toString());
									} else if (stage != 3) { 
										itemMap.setMaterial(material); 
										if (dataValue != 0) { itemMap.setDataValue((short)dataValue); }
									}
									if (stage == 0) {
										switchPane(player, itemMap, 0);
									} else if (stage == 2) {
										commandPane(player, itemMap);
									} else if (stage == 3) {
										setIngredients(player, itemMap, material.name(), position);
									} else {
										creatingPane(player, itemMap);
									}
								}));
							}
						}
					} else {
					materialPane.addButton(new Button(ItemHandler.getItem(material.toString(), 1, false, "", "&7", "&7*Click to set the material."), event -> {
						if (stage == 2) {
							itemMap.setItemCost(material.toString());
						} else if (stage != 3) { itemMap.setMaterial(material); }
						if (stage == 0) {
							switchPane(player, itemMap, 0);
						} else if (stage == 2) { 
							commandPane(player, itemMap);
						} else if (stage == 3) {
							setIngredients(player, itemMap, material.name(), position);
						} else {
							creatingPane(player, itemMap);
						}
					}));
					}
				}
			}
			inventoryCheck.clear();
		});
		materialPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting single or multiple slots for an item.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param stage - The stage in the modification.
    */
	private static void switchPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface switchPane = new Interface(false, 1, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage == 0) {
				switchPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the material selection menu."), event -> materialPane(player, itemMap, 0, 0)));
			} else { 
				switchPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			}
			switchPane.addButton(new Button(fillerPaneBItem), 2);
			switchPane.addButton(new Button(ItemHandler.getItem("GLASS", 1, false, "&a&lSingle Slot", "&7", "&7*Define a single dedicated", "&7 slot for the item."), event -> slotPane(player, itemMap, stage, 0)));
			switchPane.addButton(new Button(fillerPaneBItem), 1);
			switchPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "DISPENSER" : "23"), 1, false, "&b&lMultiple Slots", "&7", "&7*Define multiple slots for the item."), event -> slotPane(player, itemMap, stage, 1)));
			switchPane.addButton(new Button(fillerPaneBItem), 2);
			if (stage == 0) {
				switchPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the material selection menu."), event -> materialPane(player, itemMap, 0, 0)));
			} else { 
				switchPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			}
		});
		switchPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the an items slot.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param stage - The stage in the modification.
    * @param type - The type of slot being defined, single or multiple.
    */
	private static void slotPane(final Player player, final ItemMap itemMap, final int stage, final int type) {
		Interface slotPane = new Interface(false, 6, GUIName, player);
		Interface craftingPane = new Interface(false, 4, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			craftingPane.addButton(new Button(fillerPaneGItem), 3);
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[1]") : false), "&9&lSlot: &7&lCRAFTING&a&l[1]", "&7", "&7*Click to set the custom item", 
					"&7to appear in the &lCRAFTING &7slot &a&l[1]&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[1]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("CRAFTING[1]"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[1]")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("CRAFTING[1]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("CRAFTING[1]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					}
				}
			}));
			craftingPane.addButton(new Button(fillerPaneGItem));
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 2, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[2]") : false), "&9&lSlot: &7&lCRAFTING&a&l[2]", "&7", "&7*Click to set the custom item", 
					"&7to appear in the &lCRAFTING &7slot &a&l[2]&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[2]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("CRAFTING[2]"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[2]")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("CRAFTING[2]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("CRAFTING[2]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					}
				}
			}));
			craftingPane.addButton(new Button(fillerPaneGItem), 10);
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[0]") : false), "&9&lSlot: &7&lCRAFTING&a&l[0]", "&7", "&7*Click to set the custom item", 
					"&7to appear in the &lCRAFTING &7slot &a&l[0]&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[0]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("CRAFTING[0]"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[0]")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("CRAFTING[0]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("CRAFTING[0]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					}
				}
			}));
			craftingPane.addButton(new Button(fillerPaneGItem), 4);
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 3, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[3]") : false), "&9&lSlot: &7&lCRAFTING&a&l[3]", "&7", "&7*Click to set the custom item", 
					"&7to appear in the &lCRAFTING &7slot &a&l[3]&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[3]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("CRAFTING[3]"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[3]")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("CRAFTING[3]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("CRAFTING[3]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					}
				}
			}));
			craftingPane.addButton(new Button(fillerPaneGItem));
			craftingPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 4, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[4]") : false), "&9&lSlot: &7&lCRAFTING&a&l[4]", "&7", "&7*Click to set the custom item", 
					"&7to appear in the &lCRAFTING &7slot &a&l[4]&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[4]") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("CRAFTING[4]"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "CRAFTING[4]")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("CRAFTING[4]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("CRAFTING[4]"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 2);
					}
				}
			}));
			craftingPane.addButton(new Button(fillerPaneGItem), 3);
			craftingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the main slot selection menu"), event -> slotPane.open(player)));
			if (type > 0) {
				craftingPane.addButton(new Button(fillerPaneBItem), 3);
				craftingPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&a&lFinish Selecting", "&7", "&7*Saves the chosen slots", "&7to the item definition."), event -> creatingPane(player, itemMap)));
				craftingPane.addButton(new Button(fillerPaneBItem), 3);
			} else {
				craftingPane.addButton(new Button(fillerPaneBItem), 7);
			}
			craftingPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the main slot selection menu"), event -> slotPane.open(player)));
			slotPane.addButton(new Button(fillerPaneGItem));
			slotPane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "ARBITRARY") : false), "&9&lSlot: &a&lARBITRARY", "&7", "&7*Click to set the custom item", 
					"&7to appear in slot &a&lArbitrary&7", "&7", "&7*Arbitrary is defined as giving the", "&7item in the first available slot.", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "ARBITRARY") ? "&9&lENABLED: &aTRUE" : "")), 
					event -> {
				if (type == 0) { 
					itemMap.setSlot("ARBITRARY"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "ARBITRARY")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("ARBITRARY"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("ARBITRARY"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					}
				}
			}));
			slotPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, false, "&9&lSlot: &a&lCRAFTING", "&7", "&7*Click to see a list of crafting slots"), event -> craftingPane.open(player)));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_HELMET", 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "HELMET") : false), "&9&lSlot: &a&lHELMET", "&7", "&7*Click to set the custom item", 
					"&7to appear in slot &a&lHELMET&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "HELMET") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("HELMET"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "HELMET")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("HELMET"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("HELMET"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					}
				}
			}));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_CHESTPLATE", 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "CHESTPLATE") : false), "&9&lSlot: &a&lCHESTPLATE", "&7", "&7*Click to set the custom item", 
					"&7to appear in slot &a&lCHESTPLATE&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "CHESTPLATE") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("CHESTPLATE"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "CHESTPLATE")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("CHESTPLATE"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("CHESTPLATE"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					}
				}
			}));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_LEGGINGS", 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "LEGGINGS") : false), "&9&lSlot: &a&lLEGGINGS", "&7", "&7*Click to set the custom item", 
					"&7to appear in slot &a&lLEGGINGS&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "LEGGINGS") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("LEGGINGS"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "LEGGINGS")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("LEGGINGS"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("LEGGINGS"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					}
				}
			}));
			slotPane.addButton(new Button(ItemHandler.getItem("LEATHER_BOOTS", 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "BOOTS") : false), "&9&lSlot: &a&lBOOTS", "&7", "&7*Click to set the custom item", 
					"&7to appear in slot &a&lBOOTS&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "BOOTS") ? "&9&lENABLED: &aTRUE" : "")), event -> {
				if (type == 0) { 
					itemMap.setSlot("BOOTS"); 
					itemMap.setMultipleSlots(new ArrayList<String>()); 
					creatingPane(player, itemMap);
				} else { 
					if (StringUtils.containsValue(itemMap.getMultipleSlots(), "BOOTS")) {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.remove("BOOTS"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					} else {
						List<String> slots = itemMap.getMultipleSlots(); 
						slots.add("BOOTS"); 
						itemMap.setMultipleSlots(slots);
						slotPane(player, itemMap, stage, 1);
					}
				}
			}));
			if (ServerUtils.hasSpecificUpdate("1_9")) {
				slotPane.addButton(new Button(ItemHandler.getItem("SHIELD", 1, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), "OFFHAND") : false), "&9&lSlot: &a&lOFFHAND", "&7", "&7*Click to set the custom item", 
						"&7to appear in slot &a&lOFFHAND&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), "OFFHAND") ? "&9&lENABLED: &aTRUE" : "")), event -> {
					if (type == 0) { 
						itemMap.setSlot("OFFHAND"); 
						itemMap.setMultipleSlots(new ArrayList<String>()); 
						creatingPane(player, itemMap);
					} else { 
						if (StringUtils.containsValue(itemMap.getMultipleSlots(), "OFFHAND")) {
							List<String> slots = itemMap.getMultipleSlots(); 
							slots.remove("OFFHAND"); 
							itemMap.setMultipleSlots(slots);
							slotPane(player, itemMap, stage, 1);
						} else {
							List<String> slots = itemMap.getMultipleSlots(); 
							slots.add("OFFHAND"); 
							itemMap.setMultipleSlots(slots);
							slotPane(player, itemMap, stage, 1);
						}
					}
				}));
			} else {
				slotPane.addButton(new Button(fillerPaneGItem));
			}
			slotPane.addButton(new Button(fillerPaneGItem));
			for (int i = 9; i < 36; i++) {
				final int slot = i;
				slotPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIGHT_BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:3"), i, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), slot + "") : false), "&9&lSlot: &a&l" + i, "&7", "&7*Click to set the custom item", 
						"&7to appear in slot &a&l" + i + "&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), slot + "") ? "&9&lENABLED: &aTRUE" : "")), event -> {
					if (type == 0) { 
						itemMap.setSlot(slot + ""); 
						itemMap.setMultipleSlots(new ArrayList<String>()); 
						creatingPane(player, itemMap);
					} else { 
						if (StringUtils.containsValue(itemMap.getMultipleSlots(), slot + "")) {
							List<String> slots = itemMap.getMultipleSlots(); 
							slots.remove(slot + ""); 
							itemMap.setMultipleSlots(slots);
							slotPane(player, itemMap, stage, 1);
						} else {
							List<String> slots = itemMap.getMultipleSlots(); 
							slots.add(slot + ""); 
							itemMap.setMultipleSlots(slots);
							slotPane(player, itemMap, stage, 1);
						}
					}
				}));
			}
			for (int j = 0; j < 9; j++) {
				final int slot = j;
				int count = j;
				if (slot == 0) {
					count = 1;
				}
				slotPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), count, (type > 0 ? StringUtils.containsValue(itemMap.getMultipleSlots(), slot + "") : false), "&9&lSlot: &a&l" + j, "&7", "&7*Click to set the custom item", 
						"&7to appear in slot &a&l" + j + "&7", (type > 0 && StringUtils.containsValue(itemMap.getMultipleSlots(), slot + "") ? "&9&lENABLED: &aTRUE" : "")), event -> {
					if (type == 0) { 
						itemMap.setSlot(slot + ""); 
						itemMap.setMultipleSlots(new ArrayList<String>()); 
						creatingPane(player, itemMap);
					} else { 
						if (StringUtils.containsValue(itemMap.getMultipleSlots(), slot + "")) {
							List<String> slots = itemMap.getMultipleSlots(); 
							slots.remove(slot + ""); 
							itemMap.setMultipleSlots(slots);
							slotPane(player, itemMap, stage, 1);
						} else {
							List<String> slots = itemMap.getMultipleSlots(); 
							slots.add(slot + ""); 
							itemMap.setMultipleSlots(slots);
							slotPane(player, itemMap, stage, 1);
						}
					}
				}));
			}
			slotPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the slot(s) selection menu."), event -> switchPane(player, itemMap, stage)));
			if (type > 0) {
				slotPane.addButton(new Button(fillerPaneBItem), 3);
				slotPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&a&lFinish Selecting", "&7", "&7*Saves the chosen slots", "&7to the item definition."), event -> creatingPane(player, itemMap)));
				slotPane.addButton(new Button(fillerPaneBItem), 3);
			} else {
				slotPane.addButton(new Button(fillerPaneBItem), 7);
			}
			slotPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you back to", "&7the slot(s) selection menu."), event -> switchPane(player, itemMap, stage)));
		});
		if (type == 2) {
			craftingPane.open(player);
		} else {
			slotPane.open(player);
		}
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items stack size.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void countPane(final Player player, final ItemMap itemMap) {
		Interface countPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			countPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				creatingPane(player, itemMap);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				countPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lCount: &a&l" + k, "&7", "&7*Click to set the", "&7count of the item."), event -> {
					itemMap.setCount(k + "");creatingPane(player, itemMap);
				}));
			}
		});
		countPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items data.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void dataPane(final Player player, final ItemMap itemMap) {
		Interface dataPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			dataPane.addButton(new Button(fillerPaneBItem));
			dataPane.addButton(new Button(ItemHandler.setDurability(ItemHandler.getItem("BOW", 1, false, "&b&lDamage", "&7", "&7*Set the damage of the item.", (itemMap.getMaterial().getMaxDurability() != 0 ? "&9&lDURABILITY: &a" + 
			StringUtils.nullCheck(itemMap.getDurability() + "&7") : "&c&lERROR: &7This item is NOT damagable.")), 50), event -> {
				if (StringUtils.nullCheck(itemMap.getDurability() + "&7") != "NONE") {
					itemMap.setDurability(null);
					dataPane(player, itemMap);
				} else if (itemMap.getMaterial().getMaxDurability() != 0) {
					damagePane(player, itemMap);
				}
			}));
			dataPane.addButton(new Button(fillerPaneBItem), 2);
			dataPane.addButton(new Button(ItemHandler.getItem("STICK", 1, false, "&a&lCustom Texture", "&7", "&7*Set the custom data of the item.", "&7This is the damage value assigned", "&7to the custom resource texture.", "&9&lDURABILITY DATA: &a" + StringUtils.nullCheck(itemMap.getData() + "&7")), event -> {
				if (StringUtils.nullCheck(itemMap.getData() + "&7") != "NONE") {
					itemMap.setData(null);
					dataPane(player, itemMap);
				} else {
					durabilityDataPane(player, itemMap);
				}
			}));
			dataPane.addButton(new Button(fillerPaneBItem), 2);
			dataPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&e&lCustom Model Data", "&7", "&7*Set the custom model data of the item.", 
					!ServerUtils.hasSpecificUpdate("1_14") ? "&c&l[ERROR] &7This version of Minecraft does" : "", !ServerUtils.hasSpecificUpdate("1_14") ? "&7not support custom model data." : "", 
					!ServerUtils.hasSpecificUpdate("1_14") ? "&7This was implemented in 1.14+." : "", "&9&lTEXTURE DATA: &a" + StringUtils.nullCheck(itemMap.getModelData() + "&7")), event -> {
				if (StringUtils.nullCheck(itemMap.getModelData() + "&7") != "NONE" && ServerUtils.hasSpecificUpdate("1_14")) {
					itemMap.setModelData(null);
					dataPane(player, itemMap);
				} else if (ServerUtils.hasSpecificUpdate("1_14")){
					modelDataPane(player, itemMap);
				}
			}));
			dataPane.addButton(new Button(fillerPaneBItem));
			dataPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu"), event -> {
				setTriggers(itemMap);creatingPane(player, itemMap);
			}));
			dataPane.addButton(new Button(fillerPaneBItem), 7);
			dataPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu"), event -> {
				setTriggers(itemMap);creatingPane(player, itemMap);
			}));
		});
		dataPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items durability.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void durabilityDataPane(final Player player, final ItemMap itemMap) {
		Interface texturePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			texturePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				dataPane(player, itemMap);
			}));
			texturePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Texture", "&7", "&7*Click to set a custom texture", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "DURABILITY DATA";
				placeHolders[15] = "1193";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setData(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "DURABILITY DATA";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				dataPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= 2000; i++) {
				final int k = i;
				texturePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:6"), 1, false, "&9&lData: &a&l" + k, "&7", "&7*Click to set the", "&7durability data of the item."), event -> {
					itemMap.setData(k); dataPane(player, itemMap);
				}));
			}
		});
		texturePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for an items model data.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modelDataPane(final Player player, final ItemMap itemMap) {
		Interface texturePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			texturePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				dataPane(player, itemMap);
			}));
			texturePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Model Data", "&7", "&7*Click to set the custom mode data", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "MODEL DATA";
				placeHolders[15] = "1193";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setModelData(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "MODEL DATA";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				dataPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= 2000; i++) {
				final int k = i;
				texturePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:6"), 1, false, "&9&lModel Data: &a&l" + k, "&7", "&7*Click to set the", "&7custom model data for the item."), event -> {
					itemMap.setModelData(k); dataPane(player, itemMap);
				}));
			}
		});
		texturePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items damage.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void damagePane(final Player player, final ItemMap itemMap) {
		Interface damagePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			damagePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				dataPane(player, itemMap);
			}));
			damagePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Damage", "&7", "&7*Click to set a custom damage", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "DAMAGE";
				placeHolders[15] = "1893";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setDurability((short) Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "DAMAGE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				dataPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= itemMap.getMaterial().getMaxDurability(); i++) {
				final int k = i;
				damagePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:6"), 1, false, "&9&lDamage: &a&l" + k, "&7", "&7*Click to set the", "&7damage of the item."), event -> {
					itemMap.setDurability((short) k); dataPane(player, itemMap);
				}));
			}
		});
		damagePane.open(player);
	}
	
//  ============================================== //
//               ItemCommand Menus        	       //
//  ============================================== //
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items commands.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void commandPane(final Player player, final ItemMap itemMap) {
		Interface commandPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			commandPane.addButton(new Button(fillerPaneGItem), 4);
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, false, "&e&lCommands", "&7", "&7*Click to define the custom command lines", "&7for the item and click type.", 
					"&7", "&9&lCommands: &a" + (itemMap.getCommands().length != 0 ? "YES" : "NONE")), event -> actionPane(player, itemMap)));
			commandPane.addButton(new Button(fillerPaneGItem), 4);
			commandPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&a&lParticle", "&7", "&7*Custom particle(s) that will be", "&7displayed when the commands", "&7are successfully executed.", "&9&lCOMMANDS-PARTICLE: &a" +
					StringUtils.nullCheck(itemMap.getCommandParticle() + "")), event -> {
				if (StringUtils.nullCheck(itemMap.getCommandParticle() + "") != "NONE") {
					itemMap.setCommandParticle(null);
					commandPane(player, itemMap);
				} else {
					particlePane(player, itemMap, 3);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&a&lItem Cost", "&7", "&7*Material that will", "&7be charged upon successfully", "&7executing the commands.", "&9&lCOMMANDS-ITEM: &a" + 
			(StringUtils.nullCheck(itemMap.getItemCost()))), event -> {
				if (StringUtils.nullCheck(itemMap.getItemCost()) != "NONE") {
					itemMap.setItemCost(null);
					commandPane(player, itemMap);
				} else {
					materialPane(player, itemMap, 2, 0);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, false, "&a&lCost", "&7", "&7*Amount that the player will", "&7be charged upon successfully", "&7executing the commands.", "&9&lCOMMANDS-COST: &a" + 
			(StringUtils.nullCheck(itemMap.getCommandCost() + "&7"))), event -> {
				if (StringUtils.nullCheck(itemMap.getCommandCost() + "&7") != "NONE") {
					itemMap.setCommandCost(0);
					commandPane(player, itemMap);
				} else {
					costPane(player, itemMap);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("STONE_BUTTON", 1, false, "&a&lReceive", "&7", "&7*The number of times the", "&7commands will execute when", "&7receiving the custom item.", 
					"&cNOTE: &7Only functions with", "&7the on-receive command action.", "&9&lCOMMANDS-RECEIVE: &a" + (StringUtils.nullCheck(itemMap.getCommandReceive() + "&7"))), event -> {
				if (StringUtils.nullCheck(itemMap.getCommandReceive() + "&7") != "NONE") {
					itemMap.setCommandReceive(0);
					commandPane(player, itemMap);
				} else {
					receivePane(player, itemMap);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("ICE", 1, false, "&a&lCooldown", "&7", "&7*The time that the commands will", "&7be on cooldown for.", "&7", "&9&lCOMMANDS-COOLDOWN: &a" + StringUtils.nullCheck(itemMap.getCommandCooldown() + "&7") + 
					(StringUtils.nullCheck(itemMap.getCommandCooldown() + "&7") != "NONE" ? "&a second(s)" : "")), event -> {
				if (StringUtils.nullCheck(itemMap.getCommandCooldown() + "&7") != "NONE") {
					itemMap.setCommandCooldown(0);
					commandPane(player, itemMap);
				} else {
					cooldownPane(player, itemMap);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_SIGN" : "323"), 1, false, "&a&lCooldown Message", "&7", "&7*Optional cooldown message", "&7to be displayed when", "&7the items commands are", 
					"&7on cooldown.", "&9&lCOOLDOWN-MESSAGE: &a" + StringUtils.nullCheck(itemMap.getCooldownMessage())), event -> {
				if (StringUtils.nullCheck(itemMap.getCooldownMessage()) != "NONE") {
					itemMap.setCooldownMessage(null);
					commandPane(player, itemMap);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "COOLDOWN MESSAGE";
					placeHolders[15] = "&cThis item is on cooldown for &a%timeleft% &cseconds..";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				itemMap.setCooldownMessage(ChatColor.stripColor(event.getMessage()));String[] placeHolders = LanguageAPI.getLang(false).newString();placeHolders[16] = "COOLDOWN MESSAGE";LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);commandPane(event.getPlayer(), itemMap);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("JUKEBOX", 1, false, "&a&lSound", "&7", "&7*The sound that will be", "&7played after a successful", "&7command execution.", "&9&lCOMMANDS-SOUND: &a" + 
			StringUtils.nullCheck(itemMap.getCommandSound() + ""), 
			"&9&lVOLUME: &a" + ((StringUtils.nullCheck(itemMap.getCommandSound() + "") != "NONE") ? itemMap.getCommandVolume() : "0"),
			"&9&lPITCH: &a" + ((StringUtils.nullCheck(itemMap.getCommandSound() + "") != "NONE") ? itemMap.getCommandPitch() : "0")), event -> {
				if (StringUtils.nullCheck(itemMap.getCommandSound() + "") != "NONE") {
					itemMap.setCommandSound(null);
					commandPane(player, itemMap);
				} else {
					soundPane(player, itemMap, 3);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "REPEATER" : "356"), 1, false, "&a&lSequence", "&7", "&7*The order that the command lines", "&7will be executed in.", "&9&lCOMMANDS-SEQUENCE: &a" + 
			StringUtils.nullCheck(itemMap.getCommandSequence() + "")), event -> {
				if (StringUtils.nullCheck(itemMap.getCommandSequence() + "") != "NONE") {
					itemMap.setCommandSequence(null);
					commandPane(player, itemMap);
				} else {
					sequencePane(player, itemMap, 0);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LAVA_BUCKET" : "327"), 1, false, "&a&lWarmup", "&7", "&7*The time it will take before", "&7the commands are executed.", "&7Player movement will cancel the", "&7pending commands execution.", "&7", 
					"&9&lCOMMANDS-WARMUP: &a" + StringUtils.nullCheck(itemMap.getWarmDelay() + "&7") + (StringUtils.nullCheck(itemMap.getWarmDelay() + "&7") != "NONE" ? "&a second(s)" : "")), event -> {
				if (StringUtils.nullCheck(itemMap.getWarmDelay() + "&7") != "NONE") {
					itemMap.setWarmDelay(0);
					commandPane(player, itemMap);
				} else {
					warmPane(player, itemMap);
				}
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			commandPane.addButton(new Button(fillerPaneBItem), 7);
			commandPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		commandPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an action to a command.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void actionPane(final Player player, final ItemMap itemMap) {
		Interface clickPane = new Interface(false, 5, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			clickPane.addButton(new Button(fillerPaneGItem), 2);
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_DOOR" : (ServerUtils.hasSpecificUpdate("1_8") ? "324" : "64")), 1, false, "&e&lInteract", "&7", "&7*Commands that will execute only", "&7when left and right clicking.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_ALL)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_ALL);
			}));
			clickPane.addButton(new Button(fillerPaneGItem));
			clickPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&e&lInventory", "&7", "&7*Commands that will execute only", "&7when cursor clicking the item", "&7with the players inventory open.", 
					"&7", "&9&lCommands: &a" + listCommands(itemMap, Action.INVENTORY_ALL)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_ALL);
			}));
			clickPane.addButton(new Button(fillerPaneGItem));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PISTON" : "PISTON_BASE"), 1, false, "&e&lPhysical", "&7", "&7*Commands that will execute", "&7when held in the player hand", "&7and they interact with a object", "&7such as a pressure plate.", "&7", 
					"&9&lCommands: &a" + listCommands(itemMap, Action.PHYSICAL)), event -> {
				commandListPane(player, itemMap, Action.PHYSICAL);
			}));
			clickPane.addButton(new Button(fillerPaneGItem), 2);
			clickPane.addButton(new Button(ItemHandler.getItem("DIAMOND_HELMET", 1, false, "&e&lOn-Equip", "&7", "&7*Commands that will execute only", "&7when the item is placed", "&7in an armor slot.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_EQUIP)), event -> {
				commandListPane(player, itemMap, Action.ON_EQUIP);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("IRON_HELMET", 1, false, "&e&lUn-Equip", "&7", "&7*Commands that will execute only", "&7when the item is removed", "&7from an armor slot.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.UN_EQUIP)), event -> {
				commandListPane(player, itemMap, Action.UN_EQUIP);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("TORCH", 1, false, "&e&lOn-Hold", "&7", "&7*Commands that will execute only", "&7when holding the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_HOLD)), event -> {
				commandListPane(player, itemMap, Action.ON_HOLD);
			}));
			clickPane.addButton(new Button(fillerPaneGItem));
			clickPane.addButton(new Button(ItemHandler.getItem("ARROW", 1, false, "&e&lOn-Fire", "&7", "&7*Commands that will execute only", "&7when an arrow or bow is fired.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_FIRE)), event -> {
				commandListPane(player, itemMap, Action.ON_FIRE);
			}));
			clickPane.addButton(new Button(fillerPaneGItem));
			clickPane.addButton(new Button(ItemHandler.getItem("POTION", 1, false, "&e&lOn-Consume", "&7", "&7*Commands that will execute only", "&7when you consume an the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_CONSUME)), event -> {
				commandListPane(player, itemMap, Action.ON_CONSUME);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&e&lOn-Receive", "&7", "&7*Commands that will execute only", "&7when you are given the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_RECEIVE)), event -> {
				commandListPane(player, itemMap, Action.ON_RECEIVE);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "SKELETON_SKULL" : "397"), 1, false, "&e&lOn-Death", "&7", "&7*Commands that will execute only", "&7when die with the", "&7item in your inventory.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_DEATH)), event -> {
				commandListPane(player, itemMap, Action.ON_DEATH);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GLASS" : "20"), 1, false, "&e&lInteract-Air", "&7", "&7*Commands that will execute only", "&7when left and right", "&7clicking the air.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_AIR)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_AIR);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIGHT_BLUE_STAINED_GLASS" : "95:3"), 1, false, "&e&lInteract-Air-Left", "&7", "&7*Commands that will execute only", "&7when left clicking the air.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_LEFT_AIR)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_LEFT_AIR);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS" : "95:6"), 1, false, "&e&lInteract-Air-Right", "&7", "&7*Commands that will execute only", "&7when right clicking the air.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_RIGHT_AIR)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_RIGHT_AIR);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, false, "&e&lInteract-Block", "&7", "&7*Commands that will execute only", "&7when left and right", "&7clicking a block.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_BLOCK)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_BLOCK);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "STONE" : "1"), 1, false, "&e&lInteract-Block-Left", "&7", "&7*Commands that will execute only", "&7when left clicking a block.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_LEFT_BLOCK)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_LEFT_BLOCK);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COBBLESTONE" : "4"), 1, false, "&e&lInteract-Block-Right", "&7", "&7*Commands that will execute only", "&7when right clicking a block.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_RIGHT_BLOCK)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_RIGHT_BLOCK);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "IRON_DOOR" : "330"), 1, false, "&e&lInteract-Left", "&7", "&7*Commands that will execute only", "&7when left clicking.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_LEFT_ALL)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_LEFT_ALL);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_DOOR" : (ServerUtils.hasSpecificUpdate("1_8") ? "324" : "64")), 1, false, "&e&lInteract-Right", "&7", "&7*Commands that will execute only", "&7when right clicking.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INTERACT_RIGHT_ALL)), event -> {
				commandListPane(player, itemMap, Action.INTERACT_RIGHT_ALL);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&e&lInventory-Swap-Cursor", "&7", "&7*Commands that will execute only", "&7when cursor swapping with another item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_SWAP_CURSOR)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_SWAP_CURSOR);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "SNOWBALL" : "SNOW_BALL"), 8, false, "&e&lInventory-Middle", "&7", "&7*Commands that will execute only", "&7when cursor middle clicking the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_MIDDLE)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_MIDDLE);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1"), 1, false, "&e&lInventory-Creative", "&7", "&7*Commands that will execute only", "&7when cursor clicking the item in creative mode.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_CREATIVE)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_CREATIVE);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("ENDER_CHEST", 1, false, "&e&lInventory-Left", "&7", "&7*Commands that will execute only", "&7when cursor left clicking the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_LEFT)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_LEFT);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&e&lInventory-Right", "&7", "&7*Commands that will execute only", "&7when cursor right clicking the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_RIGHT)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_RIGHT);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "STONE_SLAB" : "44"), 2, false, "&e&lInventory-Shift-Left", "&7", "&7*Commands that will execute only", "&7when cursor shift left clicking the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_SHIFT_LEFT)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_SHIFT_LEFT);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COBBLESTONE_SLAB" : "44:3"), 2, false, "&e&lInventory-Shift-Right", "&7", "&7*Commands that will execute only", "&7when cursor shift right clicking the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.INVENTORY_SHIFT_RIGHT)), event -> {
				commandListPane(player, itemMap, Action.INVENTORY_SHIFT_RIGHT);
			}));
			clickPane.addButton(new Button(fillerPaneGItem));
			clickPane.addButton(new Button(ItemHandler.getItem("LAVA_BUCKET", 1, false, "&e&lOn-Damage", "&7", "&7*Commands that will execute only", "&7when the player damages an", "&7entity or is damaged by an", "&7entity with the item in", "&7their inventory.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_DAMAGE)), event -> {
				commandListPane(player, itemMap, Action.ON_DAMAGE);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("DIAMOND_SWORD", 1, false, "&e&lOn-Hit", "&7", "&7*Commands that will execute only", "&7when the player damages an", "&7entity while holding the item.", "&7", "&9&lCommands: &a" + 
			listCommands(itemMap, Action.ON_HIT)), event -> {
				commandListPane(player, itemMap, Action.ON_HIT);
			}));
			clickPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap)));
			clickPane.addButton(new Button(fillerPaneBItem), 7);
			clickPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap)));
		});
		clickPane.open(player);
	}
	
   /**
    * Gets the command for the specified action.
    * 
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action that the command should contain.
    * @return The raw String command.
    */
	private static String listCommands(final ItemMap itemMap, final Action action) {
		String commands = "";
		String commandReturn = "NONE";
		for (ItemCommand command: itemMap.getCommands()) {
			if (command.matchAction(action)) {
				commands += command.getRawCommand() + " /n ";
			}
		}
		if (StringUtils.nullCheck(commands) != "NONE") {
			commandReturn = commands;
		}
		return commandReturn;
	}
	
   /**
    * Modifies an existing ItemCommand or adds the new ItemCommand to the ItemMap.
    * 
    * @param itemMap - The ItemMap currently being modified.
    * @param itemCommand - The itemCommand to be modified or added.
    * @param newCommand - If this is a new command being added.
    */
	private static void modifyCommands(final ItemMap itemMap, final ItemCommand itemCommand, final boolean newCommand) {
		List < ItemCommand > arrayCommands = new ArrayList < ItemCommand > ();
		for (ItemCommand command: itemMap.getCommands()) { arrayCommands.add(command); }
		if (newCommand) { arrayCommands.add(itemCommand); } 
		else { arrayCommands.remove(itemCommand); }
		final ItemCommand[] commands = new ItemCommand[arrayCommands.size()];
		for (int i = 0; i < arrayCommands.size(); ++i) { commands[i] = arrayCommands.get(i); }
		itemMap.setCommands(commands);
	}
	
   /**
    * Gets the number of commands for the action type.
    * 
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action to be matched.
    */
	private static int getCommandSize(final ItemMap itemMap, final Action action) {
		int l = 0;
		for (ItemCommand command: itemMap.getCommands()) {
			if (command.matchAction(action)) {
				l++;
			}
		}
		return l;
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items list of commands.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action to be matched.
    */
	private static void commandListPane(final Player player, final ItemMap itemMap, final Action action) {
		Interface commandListPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			commandListPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the click type menu."), event -> {
				actionPane(player, itemMap);
			}));
			commandListPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&e&lNew Line", "&7", "&7*Add a new command to be executed", "&7by &9&l" + action.name()), event -> {
				executorPane(player, itemMap, action);
			}));
			ItemCommand[] commandList = itemMap.getCommands();
			int l = 1;
			for (ItemCommand command: commandList) {
				if (command.matchAction(action)) {
					final int k = l;
					commandListPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&f" + command.getRawCommand(), "&7", "&7*Click to &lmodify &7this command.", "&9&lOrder Number: &a" + k), event -> {
						modifyCommandsPane(player, itemMap, action, command, k);
					}));
					l++;
				}
			}
		});
		commandListPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items list of commands.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action to be matched.
    * @param command - The ItemCommand instance being modified.
    * @param orderNumber - The current number that dictates the ItemCommands "place in line".
    */
	private static void orderPane(final Player player, final ItemMap itemMap, final Action action, final ItemCommand command, final int orderNumber) {
		Interface orderPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			orderPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the command modify menu."), event -> {
				modifyCommandsPane(player, itemMap, action, command, orderNumber);
			}));
			for (int i = 1; i <= getCommandSize(itemMap, action); i++) {
				final int k = i;
				orderPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIGHT_BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:3"), k, false, "&9&lOrder Number: &a&l" + k, "&7", "&7*Click to set the order", "&7number of the command."), event -> {
					List < ItemCommand > arrayCommands = new ArrayList < ItemCommand > ();
					int l = 0;
					for (ItemCommand Command: itemMap.getCommands()) {
						if (Command.matchAction(action)) {
							if ((l + 1) == k) {
								arrayCommands.add(command);
							}
							l++;
						}
						if (!Command.equals(command)) {
							arrayCommands.add(Command);
						}
					}
					final ItemCommand[] commands = new ItemCommand[arrayCommands.size()];
					for (int j = 0; j < arrayCommands.size(); ++j) {
						commands[j] = arrayCommands.get(j);
					}
					itemMap.setCommands(commands);
					commandListPane(player, itemMap, action);
				}));
			}
		});
		orderPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for creating a new command for an item.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action to be matched.
    * @param command - The ItemCommand instance being modified.
    * @param orderNumber - The current number that dictates the ItemCommands "place in line".
    */
	private static void modifyCommandsPane(final Player player, final ItemMap itemMap, final Action action, final ItemCommand command, final int orderNumber) {
		Interface modPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modPane.addButton(new Button(fillerPaneGItem), 4);
			modPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&f" + command.getRawCommand(), "&7", "&7*You are modifying this command.", "&9&lOrder Number: &a" + orderNumber)));
			modPane.addButton(new Button(fillerPaneGItem), 4);
			modPane.addButton(new Button(fillerPaneGItem));
			modPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "REPEATER" : "356"), 1, false, "&fIdentifier", "&7", "&7*Set a custom identifier", "&7for this command line.", "&7", "&cNOTE: &7This is in order to set", "&7a random command list sequence.", 
					"&7Only use this if", "&7the commands sequence is", "&7set to &aRANDOM_LIST&7.", "&7", "&9&lIDENTIFIER: &a" + StringUtils.nullCheck(command.getSection())), event -> {
						if (StringUtils.nullCheck(command.getSection()) != "NONE") {
							ItemCommand[] commands = itemMap.getCommands();
							for (ItemCommand Command: commands) {
								if (Command.equals(command)) {
									Command.setSection(null);
								}
							}
							itemMap.setCommands(commands);
							command.setSection(null);
							modifyCommandsPane(player, itemMap, action, command, orderNumber);
						} else {
							player.closeInventory();
							String[] placeHolders = LanguageAPI.getLang(false).newString();
							placeHolders[16] = "COMMAND IDENTIFIER";
							placeHolders[15] = "winner";
							LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
							LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
						}
					}, event -> {
						ItemCommand[] commands = itemMap.getCommands();
						for (ItemCommand Command: commands) {
							if (Command.equals(command)) {
								Command.setSection(ChatColor.stripColor(event.getMessage()));
							}
						}
						itemMap.setCommands(commands);
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "COMMAND IDENTIFIER";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
						commandListPane(event.getPlayer(), itemMap, action);
					}));
			modPane.addButton(new Button(fillerPaneGItem));
			modPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&fModify", "&7", "&7*Sets the command to", "&7another text entry."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "MODIFIED COMMAND";
				placeHolders[15] = "gamemode creative";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				ItemCommand[] commands = itemMap.getCommands();
				for (ItemCommand Command: commands) {
					if (Command.equals(command)) {
						Command.setCommand(ChatColor.stripColor(event.getMessage()));
					}
				}
				itemMap.setCommands(commands);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "MODIFIED COMMAND";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			modPane.addButton(new Button(fillerPaneGItem));
			modPane.addButton(new Button(ItemHandler.getItem("STICK", 1, false, "&fOrder", "&7", "&7*Changes the order of execution", "&7for this command line.", "&7", "&7This will simply set the order", "&7number and push the", 
					"&7other commands down by one."), event -> {
				orderPane(player, itemMap, action, command, orderNumber);
			}));
			modPane.addButton(new Button(fillerPaneGItem));
			modPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&fDelete", "&7", "&7*Click to &cdelete &7this command."), event -> {
				modifyCommands(itemMap, command, false);
				commandListPane(player, itemMap, action);
			}));
			modPane.addButton(new Button(fillerPaneGItem));
			modPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the command lines menu."), event -> commandListPane(player, itemMap, action)));
			modPane.addButton(new Button(fillerPaneBItem), 7);
			modPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the command lines menu."), event -> commandListPane(player, itemMap, action)));
		});
		modPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command executor.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param action - THe action to be matched,
    */
	private static void executorPane(final Player player, final ItemMap itemMap, final Action action) {
		Interface executorPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			executorPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GUNPOWDER" : "289"), 1, false, "&f")));
			executorPane.addButton(new Button(ItemHandler.getItem("BOOK", 1, false, "&e&lPlayer", "&7", "&7*Executes the command", "&7as the player."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "PLAYER COMMAND";placeHolders[15] = "spawn";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				modifyCommands(itemMap, ItemCommand.fromString("player: " + ChatColor.stripColor(event.getMessage()), action, itemMap, 0L, null), true);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "PLAYER COMMAND";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			executorPane.addButton(new Button(ItemHandler.getItem("BOOK", 1, true, "&e&lOp", "&7", "&7*Executes the command as if the", "&7player has /op (admin permissions)."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "OP COMMAND";
				placeHolders[15] = "broadcast I am &cADMIN!";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				modifyCommands(itemMap, ItemCommand.fromString("op: " + ChatColor.stripColor(event.getMessage()), action, itemMap, 0L, null), true);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "COMMAND LINE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			executorPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&e&lConsole", "&7", "&7*Executes the command", "&7in the console window."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "CONSOLE COMMAND";
				placeHolders[15] = "gamemode creative %player%";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				modifyCommands(itemMap, ItemCommand.fromString("console: " + ChatColor.stripColor(event.getMessage()), action, itemMap, 0L, null), true);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "OP COMMAND";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			executorPane.addButton(new Button(ItemHandler.getItem("HOPPER", 1, false, "&e&lServer", "&7", "&7*Switches the player to", "&7the defined server name.", "&7", "&7&lNote: &7This is the name", 
					"&7defined in the BungeeCord config."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SERVER SWITCH";
				placeHolders[15] = "survival";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				modifyCommands(itemMap, ItemCommand.fromString("server: " + ChatColor.stripColor(event.getMessage()), action, itemMap, 0L, null), true);
				String[] placeHolders = LanguageAPI.getLang(false).newString();placeHolders[16] = "SERVER SWITCH";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			executorPane.addButton(new Button(ItemHandler.getItem("OBSIDIAN", 1, false, "&e&lBungee", "&7", "&7*Executes a BungeeCord specific command."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "BUNGEE COMMAND";
				placeHolders[15] = "survival";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				modifyCommands(itemMap, ItemCommand.fromString("bungee: " + ChatColor.stripColor(event.getMessage()), action, itemMap, 0L, null), true);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "BUNGEE COMMAND";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			executorPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&e&lMessage", "&7", "&7*Sends the player a custom message."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "MESSAGE";
				placeHolders[15] = "&eWelcome to the Server!";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				modifyCommands(itemMap, ItemCommand.fromString("message: " + ChatColor.stripColor(event.getMessage()), action, itemMap, 0L, null), true);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "MESSAGE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			executorPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "REPEATER" : "356"), 1, false, "&e&lSwap-Item", "&7", "&7*Swaps the item to another defined item."), event -> swapPane(player, itemMap, action)));
			executorPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&e&lDelay", "&7", "&7*Adds a delay between command lines."), event -> delayPane(player, itemMap, action)));
			executorPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the command lines menu."), event -> commandListPane(player, itemMap, action)));
			executorPane.addButton(new Button(fillerPaneBItem), 7);
			executorPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the command lines menu."), event -> commandListPane(player, itemMap, action)));
		});
		executorPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the commands swap-item.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action to be matched.
    */
	private static void swapPane(final Player player, final ItemMap itemMap, final Action action) {
		Interface swapPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			swapPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the executors menu."), event -> {
				executorPane(player, itemMap, action);
			}));
			for (ItemMap item : ItemUtilities.getUtilities().copyItems()) {
				if (item.getNodeLocation() != itemMap.getNodeLocation()) {
					if (itemMap.isAnimated() || itemMap.isDynamic()) { setModifyMenu(true, player); itemMap.getAnimationHandler().get(player).setMenu(true, 1); }
					swapPane.addButton(new Button(ItemHandler.addLore(item.getTempItem(), "&7", "&6---------------------------", "&7*Click to set as a swap-item.", "&9&lNode: &a" + item.getConfigName(), "&7"), event -> { 
					modifyCommands(itemMap, ItemCommand.fromString("swap-item: " + item.getConfigName(), action, itemMap, 0L, null), true);
					commandListPane(player, itemMap, action); }));
				}
			}
		});
		swapPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command delay duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param action - The action to be matched.
    */
	private static void delayPane(final Player player, final ItemMap itemMap, final Action action) {
		Interface delayPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			delayPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the executors menu."), event -> {
				executorPane(player, itemMap, action);
			}));
			delayPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Cooldown", "&7", "&7*Click to set a custom", "&7delay for the next command."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "DELAY";
				placeHolders[15] = "180";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					modifyCommands(itemMap, ItemCommand.fromString("delay: " + Integer.parseInt(ChatColor.stripColor(event.getMessage())), action, itemMap, Integer.parseInt(ChatColor.stripColor(event.getMessage())), null), true);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "DELAY";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				commandListPane(event.getPlayer(), itemMap, action);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				delayPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIGHT_GRAY_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:8"), k, false, "&9&lDelay: &a&l" + k + " Tick(s)", "&7", "&7*Click to set the", "&7delay of the next command."), event -> {
					modifyCommands(itemMap, ItemCommand.fromString("delay: " + k, action, itemMap, k, null), true);
					commandListPane(player, itemMap, action);
				}));
			}
		});
		delayPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command cooldown duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void cooldownPane(final Player player, final ItemMap itemMap) {
		Interface cooldownPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			cooldownPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> {
				commandPane(player, itemMap);
			}));
			cooldownPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Cooldown", "&7", "&7*Click to set a custom commands-cooldown", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "COMMAND COOLDOWN";
				placeHolders[15] = "180";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setCommandCooldown(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "COMMAND COOLDOWN";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				commandPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				cooldownPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Second(s)", "&7", "&7*Click to set the", "&7commands-cooldown of the item."), event -> {
					itemMap.setCommandCooldown(k);
					commandPane(player, itemMap);
				}));
			}
		});
		cooldownPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command warmup duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void warmPane(final Player player, final ItemMap itemMap) {
		Interface warmPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			warmPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> {
				commandPane(player, itemMap);
			}));
			warmPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Warmup", "&7", "&7*Click to set a custom commands-warmup", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "COMMAND WARMUP";
				placeHolders[15] = "12";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setWarmDelay(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "COMMAND WARMUP";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				commandPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				warmPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lWarming: &a&l" + k + " Second(s)", "&7", "&7*Click to set the", "&7commands-warmup of the item."), event -> {
					itemMap.setWarmDelay(k);
					commandPane(player, itemMap);
				}));
			}
		});
		warmPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command cost.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void costPane(final Player player, final ItemMap itemMap) {
		Interface costPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			costPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> {
				commandPane(player, itemMap);
			}));
			costPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Cost", "&7", "&7*Click to set a custom commands-cost", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "COMMAND COST";
				placeHolders[15] = "340";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setCommandCost(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "COMMAND COST";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				commandPane(event.getPlayer(), itemMap);
			}));
			for (int i = 0; i <= 64; i++) {
				final int k = i;
				costPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), (k == 0 ? 1 : k), false, "&9&lCost: &a$&l" + k, "&7", "&7*Click to set the", "&7commands-cost of the item."), event -> {
					itemMap.setCommandCost(k);
					commandPane(player, itemMap);
				}));
			}
		});
		costPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for an items command item currency.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void receivePane(final Player player, final ItemMap itemMap) {
		Interface receivePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			receivePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> {
				commandPane(player, itemMap);
			}));
			receivePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Receive", "&7", "&7*Click to set a custom commands-receive", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "COMMAND RECEIVE";
				placeHolders[15] = "10";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setCommandReceive(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "COMMAND RECEIVE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				commandPane(event.getPlayer(), itemMap);
			}));
			for (int i = 0; i <= 64; i++) {
				final int k = i;
				receivePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), (k == 0 ? 1 : k), false, "&9&lReceive: &a#&l" + k, "&7", "&7*Click to set the", "&7commands-receive of the item."), event -> {
					itemMap.setCommandReceive(k);
					commandPane(player, itemMap);
				}));
			}
		});
		receivePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command sequence.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void sequencePane(final Player player, final ItemMap itemMap, final int stage) {
		Interface sequencePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage == 4) {
				sequencePane.addButton(new Button(fillerPaneGItem));
			} 
			sequencePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&a&lSequential", "&7", "&7*Executes the command lines", "&7in order from top to bottom."), event -> {
				if (stage == 4) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands-sequence", "SEQUENTIAL"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> activeCommands(player));
				} else {
					itemMap.setCommandSequence(CommandSequence.SEQUENTIAL);
					commandPane(player, itemMap);
				}
			}));
			sequencePane.addButton(new Button(fillerPaneGItem));
			sequencePane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, false, "&a&lRandom Single", "&7", "&7*Executes one of the command lines", "&7randomly with equal values."), event -> {
				if (stage == 4) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands-sequence", "RANDOM_SINGLE"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> activeCommands(player));
				} else {
					itemMap.setCommandSequence(CommandSequence.RANDOM_SINGLE);
					commandPane(player, itemMap);
				}
			}));
			sequencePane.addButton(new Button(fillerPaneGItem));
			sequencePane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&a&lRandom List", "&7", "&7*Randomly selects from a list", "&7of commands to execute."), event -> {
				if (stage == 4) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands-sequence", "RANDOM_LIST"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> activeCommands(player));
				} else {
					itemMap.setCommandSequence(CommandSequence.RANDOM_LIST);
					commandPane(player, itemMap);
				}
			}));
			sequencePane.addButton(new Button(fillerPaneGItem));
			sequencePane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&a&lRandom", "&7", "&7*Executes each command line in a", "&7random order with equal values."), event -> {
				if (stage == 4) {
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands-sequence", "RANDOM"); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> activeCommands(player));
				} else {
					itemMap.setCommandSequence(CommandSequence.RANDOM);
					commandPane(player, itemMap);
				}
			}));
			sequencePane.addButton(new Button(fillerPaneGItem));
			if (stage != 4) {
				sequencePane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&a&lRemain", "&7", "&7*Executes each command only if", "&7the item exists in the player", "&7inventory at the time of executing", "&7a delayed command line.", "&7The commands will be sent in", "&7order from top to bottom."), event -> {
					itemMap.setCommandSequence(CommandSequence.REMAIN);
					commandPane(player, itemMap);
				}));
			}
			if (stage == 4) {
				sequencePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> activeCommands(player)));
			} else {
				sequencePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap)));
			}
			sequencePane.addButton(new Button(fillerPaneBItem), 7);
			if (stage == 4) {
				sequencePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> activeCommands(player)));
			} else {
				sequencePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap)));
			}
		});
		sequencePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command sound.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void soundPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface soundPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
				if (stage != 3) {
					soundPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the teleport menu."), event -> teleportPane(player, itemMap, stage)));
				} else { 
					soundPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap))); 
				}
			
			for (Sound sound: Sound.values()) {
				if (stage != 3) {
					soundPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "MUSIC_DISC_MELLOHI" : "2262"), 1, false, "&f" + sound.name(), "&7", "&7*Click to set the", "&7teleport-sound of the item."), event -> {
						itemMap.setTeleportSound(sound.name());
						soundVolumePane(player, itemMap, stage);
					}));
				} else {
					soundPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "MUSIC_DISC_MELLOHI" : "2262"), 1, false, "&f" + sound.name(), "&7", "&7*Click to set the", "&7commands-sound of the item."), event -> {
						itemMap.setCommandSound(sound);
						soundVolumePane(player, itemMap, stage);
					}));
				}
			}
		});
		soundPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an item commands sound volume.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void soundVolumePane(final Player player, final ItemMap itemMap, final int stage) {
		Interface soundPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage != 3) {
				soundPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the teleport menu."), event -> teleportPane(player, itemMap, stage)));
			} else { 
				soundPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap))); 
			}
			soundPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Volume", "&7", "&7*Click to set a custom sound volume value."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SOUND VOLUME";
				placeHolders[15] = "1.4";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isDouble(ChatColor.stripColor(event.getMessage()))) {
					if (stage != 3) {
						itemMap.setTeleportVolume(Double.parseDouble(ChatColor.stripColor(event.getMessage())));
					} else {
						itemMap.setCommandVolume(Double.parseDouble(ChatColor.stripColor(event.getMessage())));
					}
					soundPitchPane(player, itemMap, stage);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SOUND VOLUME";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					soundVolumePane(event.getPlayer(), itemMap, stage);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				soundPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GREEN_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:13"), k, false, "&9&lVolume: &a&l" + k, "&7", "&7*Click to set the sound volume."), event -> {
					if (stage != 3) {
						itemMap.setTeleportVolume((double) k);
					} else {
						itemMap.setCommandVolume((double) k);
					}
					soundPitchPane(player, itemMap, stage);
				}));
			}
		});
		soundPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an item commands sound pitch.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void soundPitchPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface soundPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage != 3) {
				soundPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the teleport menu."), event -> teleportPane(player, itemMap, stage)));
			} else { 
				soundPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> commandPane(player, itemMap))); 
			}
			soundPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Pitch", "&7", "&7*Click to set a custom sound pitch", "&7value for the command sound."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SOUND PITCH";
				placeHolders[15] = "0.8";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isDouble(ChatColor.stripColor(event.getMessage()))) {
					if (stage != 3) {
						itemMap.setTeleportPitch(Double.parseDouble(ChatColor.stripColor(event.getMessage())));
						teleportPane(player, itemMap, stage);
					} else {
						itemMap.setCommandPitch(Double.parseDouble(ChatColor.stripColor(event.getMessage())));
						commandPane(player, itemMap);
					}
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SOUND PITCH";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					soundPitchPane(event.getPlayer(), itemMap, stage);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				soundPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lPitch: &a&l" + k, "&7", "&7*Click to set the sound pitch", "&7for the command sound."), event -> {
					if (stage != 3) {
						itemMap.setTeleportPitch((double) k);
						teleportPane(player, itemMap, stage);
					} else {
						itemMap.setCommandPitch((double) k);
						commandPane(player, itemMap);
					}
				}));
			}
		});
		soundPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items command particle.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void particlePane(final Player player, final ItemMap itemMap, final int stage) {
		Interface particlePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage != 3) {
				particlePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the teleport menu."), event -> {
					teleportPane(player, itemMap, stage);
				}));
			} else {
				particlePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item commands menu."), event -> {
					commandPane(player, itemMap);
				}));
			}
			if (stage != 3) { } 
			else {
				particlePane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&fFIREWORK_FAKE", "&7", "&7*Click to set the lifetime", "&7commands-particle of the item."), event -> lifePane(player, itemMap, "FIREWORK", 1)));
			}
			if (ServerUtils.hasSpecificUpdate("1_9")) {
				for (org.bukkit.Particle particle: org.bukkit.Particle.values()) {
					if (stage != 3) {
						particlePane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&f" + particle.name(), "&7", "&7*Click to set the", "&7teleport-effect of the item."), event -> { 
							itemMap.setTeleportEffect(particle.name());
							teleportPane(player, itemMap, stage); 
						}));
					} else {
						particlePane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&f" + particle.name(), "&7", "&7*Click to set the", "&7commands-particle of the item."), event -> lifePane(player, itemMap, particle.name(), 0)));
					}
				}
			} else {
				for (org.bukkit.Effect effect: org.bukkit.Effect.values()) {
					if (stage != 3) {
						particlePane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&f" + effect.name(), "&7", "&7*Click to set the", "&7teleport-effect of the item."), event -> { 
							itemMap.setTeleportEffect(effect.name());
							teleportPane(player, itemMap, stage); 
						}));
					} else {
						particlePane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&f" + effect.name(), "&7", "&7*Click to set the", "&7commands-particle of the item."), event -> lifePane(player, itemMap, effect.name(), 0)));
					}
				}
			}
		});
		particlePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the life time of the commands firework particle.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void lifePane(final Player player, final ItemMap itemMap, final String particle, final int stage) {
		Interface lifePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			lifePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the particle menu."), event -> {
				particlePane(player, itemMap, 3);
			}));
			lifePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom LifeTime", "&7", "&7*Click to set a lifetime (duration)", "&7value for particle effect."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "PARTICLE LIFETIME";
				placeHolders[15] = "170";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					if (stage == 0) {
						itemMap.setCommandParticle(particle + ":" + ChatColor.stripColor(event.getMessage()));
					} else {
						explosionPane(player, itemMap, particle, Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					}
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "PARTICLE LIFETIME";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					particlePane(event.getPlayer(), itemMap, 3);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				lifePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CYAN_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:9"), k, false, "&9&lLifeTime: &a&l" + k + " Tick(s)", "&7", "&7*Click to set the lifetime", "&7(duration) of the particle effect."), event -> {
					if (stage == 0) {
						itemMap.setCommandParticle(particle + ":" + k);
						commandPane(player, itemMap);
					} else {
						explosionPane(player, itemMap, particle, k);
					}
				}));
			}
		});
		lifePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the commands firework explosion particle.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void explosionPane(final Player player, final ItemMap itemMap, final String particle, final int lifetime) {
		Interface patternPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			patternPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the particle menu."), event -> {
				particlePane(player, itemMap, 3);
			}));
			for (Type explosion: Type.values()) {
				patternPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&f" + explosion.name(), "&7", "&7*Click to set the pattern", "&7of the firework explosion effect."), 
						event -> colorParticlePane(player, itemMap, particle, lifetime, explosion, null)));
			}
		});
		patternPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the commands color particle.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void colorParticlePane(final Player player, final ItemMap itemMap, final String particle, final int lifetime, final Type explosion, final DyeColor color1) {
		Interface colorPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			colorPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the particle menu."), event -> {
				particlePane(player, itemMap, 3);
			}));
			for (DyeColor color: DyeColor.values()) {
				colorPane.addButton(new Button(ItemHandler.getItem("GRAY_DYE", 1, false, "&f" + color.name(), "&7", "&7*Click to set the " + (color1 != null ? "&c&lend color" : "&9&lstart color"), "&7of the firework explosion effect."), event -> {
					if (color1 != null) {
						itemMap.setCommandParticle(particle + ":" + color1.name() + ":" + color.name() + ":" + explosion.name() + ":" + lifetime);
						commandPane(player, itemMap);
					} else {
						colorParticlePane(player, itemMap, particle, lifetime, explosion, color);
					}
				}));
			}
		});
		colorPane.open(player);
	}
	
//  ============================================================================================================================================================================================================================================================
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items enchantment.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void enchantPane(final Player player, final ItemMap itemMap) {
		Interface enchantPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			enchantPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				creatingPane(player, itemMap);
			}));
			for (Enchantment enchant: Enchantment.values()) {
				if (ItemHandler.getEnchantName(enchant) != null) { 
					boolean containsKey = (itemMap.getEnchantments() != null) ? itemMap.getEnchantments().containsKey(ItemHandler.getEnchantName(enchant).toUpperCase()) : false;
					ItemStack enchantItem = ItemHandler.getItem((containsKey ? "ENCHANTED_BOOK" : "BOOK"), 1, false, "&f" + ItemHandler.getEnchantName(enchant).toUpperCase(), "&7", 
							"&7*Click to add this enchantment", "&7to the custom item.", "&7", "&9&lENABLED: &a" + (containsKey + "").toUpperCase(), (containsKey ? "&7" : ""), 
							(containsKey ? "&9&lLEVEL: &a" + itemMap.getEnchantments().get(ItemHandler.getEnchantName(enchant).toUpperCase()) : ""));
					enchantPane.addButton(new Button(enchantItem, event -> {
						if (containsKey) {
							Map < String, Integer > enchantments = itemMap.getEnchantments();
							enchantments.remove(ItemHandler.getEnchantName(enchant).toUpperCase());
							itemMap.setEnchantments(enchantments);
							enchantPane(player, itemMap);
						} else {
							enchantLevelPane(player, itemMap, enchant);
						}
					}));
				}
			}
		});
		enchantPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an echantment level.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void enchantLevelPane(final Player player, final ItemMap itemMap, final Enchantment enchant) {
		Interface enchantLevelPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			enchantLevelPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the enchant selection menu."), event -> {
				enchantPane(player, itemMap);
			}));
			enchantLevelPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Count", "&7", "&7*Click to set a custom damage", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ENCHANT LEVEL";
				placeHolders[15] = "86";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					Map < String, Integer > enchantments = (itemMap.getEnchantments() != null) ? itemMap.getEnchantments() : new HashMap < String, Integer >();
					enchantments.put(ItemHandler.getEnchantName(enchant).toUpperCase(), Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					itemMap.setEnchantments(enchantments);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "ENCHANT LEVEL";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				enchantPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				enchantLevelPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lLevel: &a&l" + k, "&7", "&7*Click to set the", "&7level of the item enchantment.", "&7", "&7This will be &l" + 
				ItemHandler.getEnchantName(enchant).toUpperCase() + ":" + k), event -> {
					Map < String, Integer > enchantments = (itemMap.getEnchantments() != null) ? itemMap.getEnchantments() : new HashMap < String, Integer >();
					enchantments.put(ItemHandler.getEnchantName(enchant).toUpperCase(), k);
					itemMap.setEnchantments(enchantments);
					enchantPane(player, itemMap);
				}));
			}
		});
		enchantLevelPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items itemflags.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void flagPane(final Player player, final ItemMap itemMap) {
		Interface flagPane = new Interface(true, 5, GUIName, player);
		flagPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
			setItemFlags(itemMap);
			creatingPane(player, itemMap);
		}));
		SchedulerUtils.runAsync(() -> {
			flagPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, itemMap.isOpBypass(), "&a&l&nAllowOpBypass", "&7", 
					"&a&lTrue&f:&7 Allows players who are OP to", "&7bypass any itemflags that add", "&7restrictions for this item.", "&7",
					"&c&lFalse&f:&7 Players who are OP will be", "&7restricted by itemflags that add", "&7restrictions for this item.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isOpBypass() + "").toUpperCase()), event -> {
				if (itemMap.isOpBypass()) {
					itemMap.setOpBypass(false);
				} else {
					itemMap.setOpBypass(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem(itemMap.isCreativeBypass() ? (ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1") : "GOLDEN_APPLE", 1, itemMap.isCreativeBypass(), "&a&l&nCreativeBypass", "&7", 
					"&a&lTrue&f:&7 Allows players who are in Creative", "&7to bypass any itemflags that add", "&7restrictions for this item.", "&7",
					"&c&lFalse&f:&7 Players who are in Creative will", "&7be restricted by itemflags that add", "&7restrictions for this item.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isCreativeBypass() + "").toUpperCase()), event -> {
				if (itemMap.isCreativeBypass()) {
					itemMap.setCreativeBypass(false);
				} else {
					itemMap.setCreativeBypass(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LAPIS_LAZULI" : "351:4"), 1, itemMap.isGlowing(), "&a&l&nGlowing", "&7", 
					"&a&lTrue&f:&7 The item will glow as if it was enchanted!", "&7",
					"&c&lFalse&f:&7 The item will not glow.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isGlowing() + "").toUpperCase()), event -> {
				if (itemMap.isGlowing()) {
					itemMap.setGlowing(false);
				} else {
					itemMap.setGlowing(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "DIAMOND_SHOVEL" : "277"), 7, itemMap.isStackable(), "&a&l&nStackable", "&7", 
					"&a&lTrue&f:&7 The item will be stackable with itself!", "&7",
					"&c&lFalse&f:&7 The item stack only if it did in vanilla.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isStackable() + "").toUpperCase()), event -> {
				if (itemMap.isStackable()) {
					itemMap.setStackable(false);
				} else {
					itemMap.setStackable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "POPPY" : "38"), 1, itemMap.isInventoryClose(), "&a&l&nInventory Close", "&7", 
					"&a&lTrue&f:&7 Closes the players current", "&7inventory when clicking the item.", "&7",
					"&c&lFalse&f:&7 The current inventory will not", "&7be closed when clicking the item.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isInventoryClose() + "").toUpperCase()), event -> {
				if (itemMap.isInventoryClose()) {
					itemMap.setCloseInventory(false);
				} else {
					itemMap.setCloseInventory(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, itemMap.isAutoRemove(), "&a&l&nAuto Remove", "&7", 
					"&a&lTrue&f:&7 Automatically removes the", "&7item from the players inventory", "&7when entering or joining a", "&7world that is not defined", "&7under the enabled-worlds.", "&7",
					"&c&lFalse&f:&7 The player will keep the", "&7item when entering or joining", "&7an undefined world.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isAutoRemove() + "").toUpperCase()), event -> {
				if (itemMap.isAutoRemove()) {
					itemMap.setAutoRemove(false);
				} else {
					itemMap.setAutoRemove(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, itemMap.isOverwritable(), "&a&l&nOverwrite", "&7", 
					"&a&lTrue&f: &7Allows the item to overwrite", "&7any existing items in the defined slot.", "&7", 
					"&c&lFalse&f:&7 The item will not overwrite other items.", "&7When the slot is full it", "&7will fail to give the item, unless", "&7the give-next or move-next flag is set to &a&lTrue&7.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isOverwritable() + "").toUpperCase()), event -> {
				if (itemMap.isOverwritable()) {
					itemMap.setOverwritable(false);
				} else {
					itemMap.setOverwritable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("CACTUS", 1, itemMap.isDisposable(), "&a&l&nDisposable", "&7", 
					"&a&lTrue&f:&7 If the item has a command", "&7defined, running the command", "&7will remove x1 of the item.", "&7",
					"&c&lFalse&f:&7 Running item commands will", "&7not lower the items count.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isDisposable() + "").toUpperCase()), event -> {
				if (itemMap.isDisposable()) {
					itemMap.setDisposable(false);
				} else {
					itemMap.setDisposable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WOODEN_SWORD" : "268"), 1, itemMap.isVanilla(), "&a&l&nVanilla", "&7", 
					"&a&lTrue&f:&7 The item will be given as a default no-name item.", 
					"&cNOTE: &7Itemflags and commands will NOT work", "&7unless the vanilla-status or vanilla-control", "&7itemflags are defined.", "&7",
					"&c&lFalse&f:&7 The item will be given", "&7as an custom item, allowing all", "&7ItemJoin properties to continue working.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isVanilla() + "").toUpperCase()), event -> {
				if (itemMap.isVanilla()) {
					itemMap.setVanilla(false);
				} else {
					itemMap.setVanilla(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("LEATHER_HELMET", 1, itemMap.isVanillaStatus(), "&a&l&nVanilla Status", "&7", 
					"&a&lTrue&f: &7Allows the Vanilla itemflag to retain", "&7ItemJoin properties without", "&7making it only a ItemJoin specific item.", 
					"&cNOTE: &7Useful for trying to implement", "&7ItemJoin items into other plugins.", "&7", 
					"&c&lFalse&f:&7 The item will be given", "&7as a custom item, allowing all", "&7ItemJoin properties to continue working.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isVanillaStatus() + "").toUpperCase()), event -> {
				if (itemMap.isVanillaStatus()) {
					itemMap.setVanillaStatus(false);
				} else {
					itemMap.setVanillaStatus(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WOODEN_PICKAXE" : "270"), 1, itemMap.isVanillaControl(), "&a&l&nVanilla Control", "&7", 
					"&a&lTrue&f: &7Allows the Vanilla itemflag to retain", "&7the use of commands and itemflags.", "&7", 
					"&c&lFalse&f:&7 The item will be given", "&7as an custom item, allowing all", "&7ItemJoin properties to continue working.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isVanillaControl() + "").toUpperCase()), event -> {
				if (itemMap.isVanillaControl()) {
					itemMap.setVanillaControl(false);
				} else {
					itemMap.setVanillaControl(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, itemMap.isIpLimted(), "&a&l&nIP Limit", "&7", 
					"&a&lTrue&f:&7 The item will be tied to the players IP.", "&7No other players using the same IP will receive the item.", "&7Useful to prevent item duplication.", "&7", 
					"&c&lFalse&f:&7 The item will not be tied to a players IP.", "&7Other player accounts using the same IP will receive the item.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isIpLimted() + "").toUpperCase()), event -> {
				if (itemMap.isIpLimted()) {
					itemMap.setIpLimited(false);
				} else {
					itemMap.setIpLimited(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem(itemMap.isUnbreakable() ? "ENCHANTED_BOOK" : "BOOK", 1, itemMap.isUnbreakable(), "&a&l&nUnbreakable", "&7", 
					"&a&lTrue&f:&7 Allows the item to be unbreakable or INDESTRUCTIBLE!", "&7",
					"&c&lFalse&f:&7 The item will be damageable when being used.", "&7", "&7This flag only takes effect on items which have durability.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isUnbreakable() + "").toUpperCase()), event -> {
				if (itemMap.isUnbreakable()) {
					itemMap.setUnbreakable(false);
				} else {
					itemMap.setUnbreakable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "FILLED_MAP" : "358"), 1, itemMap.isFlagsInfo(), "&a&l&nHide Flags", "&7", 
					"&a&lTrue&f: &7Hides all information tags from the item", "&7such as firework colors, damage values, enchants, etc.", "&7", 
					"&c&lFalse&f:&7 The item will have information tags visible.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isFlagsInfo() + "").toUpperCase()), event -> {
				if (itemMap.isFlagsInfo()) {
					itemMap.setFlagsInfo(false);
				} else {
					itemMap.setFlagsInfo(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENDER_EYE" : "381"), 1, itemMap.isAttributesInfo(), "&a&l&nHide Attributes", "&7", 
					"&a&lTrue&f: &7Hides all attribute tags from the item", "&7such damage values, attack speed, hit points, etc.", "&7Typically this is the information that", "&7starts with (When in Main Hand:).", "&7", 
					"&c&lFalse&f:&7 The item will have information tags visible.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isAttributesInfo() + "").toUpperCase()), event -> {
				if (itemMap.isAttributesInfo()) {
					itemMap.setAttributesInfo(false);
				} else {
					itemMap.setAttributesInfo(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("IRON_SWORD", 1, itemMap.isDurabilityBar(), "&a&l&nHide Durability", "&7", 
					"&a&lTrue&f:&7 The durability bar of the damageable ", "&7item will be hidden.", "&cNOTE: &7Items with this flag will still break,", "&7unless the unbreakable flag is set to &a&lTrue&7.", "&7",
					"&c&lFalse&f:&7 The durability bar of the", "&7damageable item will be shown as normal.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isDurabilityBar() + "").toUpperCase()), event -> {
				if (itemMap.isDurabilityBar()) {
					itemMap.setDurabilityBar(false);
				} else {
					itemMap.setDurabilityBar(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("COBBLESTONE", 1, itemMap.isPlaceable(), "&a&l&nPlacement", "&7", 
					"&a&lTrue&f: &7Prevents the item from being", "&7placed on the ground,", "&7in any item-frames, and entities.", "&7",
					"&c&lFalse&f: &7Item will be able to be placed.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isPlaceable() + "").toUpperCase()), event -> {
				if (itemMap.isPlaceable()) {
					itemMap.setPlaceable(false);
				} else {
					itemMap.setPlaceable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("BEDROCK", 1, itemMap.isMovement(), "&a&l&nInventory Modify", "&7", 
					"&a&lTrue&f: &7Prevents the item from being", "&7moved or switched to other slots", "&7and blocks placement in item-frames.", "&7",	
					"&c&lFalse&f:&7 Allows the item to be moved", "&7freely inside the players inventory.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isMovement() + "").toUpperCase()), event -> {
				if (itemMap.isMovement()) {
					itemMap.setMovement(false);
				} else {
					itemMap.setMovement(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("DIAMOND_HELMET", 1, itemMap.isEquip(), "&a&l&nCancel Equip", "&7", 
					"&a&lTrue&f: &7Prevents the item from being", "&7moved or switched to armor slots.", "&7",	
					"&c&lFalse&f:&7 Allows the item to be moved", "&7freely inside the players inventory.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isEquip() + "").toUpperCase()), event -> {
				if (itemMap.isEquip()) {
					itemMap.setEquip(false);
				} else {
					itemMap.setEquip(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, itemMap.isDynamic(), "&a&l&nDynamic", "&7", 
					"&a&lTrue&f: &7Allows the item to dynamically", "&7update every 100 ticks", "&7Useful for updating placeholders.", "&7",
					"&c&lFalse&f: &7Item will not update its name, lore, etc.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isDynamic() + "").toUpperCase()), event -> {
				if (itemMap.isDynamic()) {
					itemMap.setDynamic(false);
				} else {
					itemMap.setDynamic(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("EGG", 1, itemMap.isAnimated(), "&a&l&nAnimate", "&7", 
					"&a&lTrue&f: &7Allows the item to animate between", "&7its different iterations defined", "&7under the animations tab.", "&7",
					"&c&lFalse&f: &7Item will not animate.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isAnimated() + "").toUpperCase()), event -> {
				if (itemMap.isAnimated()) {
					itemMap.setAnimate(false);
				} else {
					itemMap.setAnimate(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CHEST_MINECART" : "342"), 1, itemMap.isItemStore(), "&a&l&nItem Store", "&7",
					"&a&lTrue&f:&7 Prevents the storage of the item in any containers.", "&7Such as chests, armor stands, anvils, etc.", "&7",
					"&c&lFalse&f:&7 The item can be stored in containers.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isItemStore() + "").toUpperCase()), event -> {
				if (itemMap.isItemStore()) {
					itemMap.setItemStore(false);
				} else {
					itemMap.setItemStore(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_DOOR" : (ServerUtils.hasSpecificUpdate("1_8") ? "324" : "64")), 1, itemMap.isCountLock(), "&a&l&nCount Lock", "&7", 
					"&a&lTrue&f:&7 The item can be used indefinitely.", "&7Useful to give a player infinite apples.", "&cNOTE: &7This will overwrite the disposable flag.", "&7",
					"&c&lFalse&f:&7 The item will be removed from the inventory on use.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isCountLock() + "").toUpperCase()), event -> {
				if (itemMap.isCountLock()) {
					itemMap.setCountLock(false);
				} else {
					itemMap.setCountLock(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, itemMap.isDeathKeepable(), "&a&l&nDeath Keep", "&7", 
					"&a&lTrue&f:&7 On death, the item will remain", "&7in players inventory on respawn.", "&7",
					"&c&lFalse&f:&7 On death, the item will be dropped", "&7at the death location as normal.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isDeathKeepable() + "").toUpperCase()), event -> {
				if (itemMap.isDeathKeepable()) {
					itemMap.setDeathKeepable(false);
				} else {
					itemMap.setDeathKeepable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("BONE", 1, itemMap.isDeathDroppable(), "&a&l&nDeath Drops", "&7", 
					"&a&lTrue&f:&7 On death, the item will be removed", "&7from the players inventory.", "&7",
					"&c&lFalse&f:&7 On death, the item will be dropped", "&7at the death location as normal.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isDeathDroppable() + "").toUpperCase()), event -> {
				if (itemMap.isDeathDroppable()) {
					itemMap.setDeathDroppable(false);
				} else {
					itemMap.setDeathDroppable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("HOPPER", 1, itemMap.isSelfDroppable(), "&a&l&nSelf Drops", "&7", 
					"&a&lTrue&f: &7Prevents the item from being dropped", "&7by the player, returns it back to their inventory.", "&7",
					"&c&lFalse&f: &7Allows the item to be dropped.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isSelfDroppable() + "").toUpperCase()), event -> {
				if (itemMap.isSelfDroppable()) {
					itemMap.setSelfDroppable(false);
				} else {
					itemMap.setSelfDroppable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("FURNACE", 1, itemMap.isItemModify(), "&a&l&nItem Modifiable", "&7", 
					"&a&lTrue&f: &7Blocks the item from being", "&7repaired or enchanted in-game.", "&7",
					"&c&lFalse&f: &7Allows items to", "&7be repaired and enchanted.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isItemModify() + "").toUpperCase()), event -> {
				if (itemMap.isItemModify()) {
					itemMap.setItemModify(false);
				} else {
					itemMap.setItemModify(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("ANVIL", 1, itemMap.isItemRepairable(), "&a&l&nItem Repairable", "&7", 
					"&a&lTrue&f: &7Blocks the item from being", "&7used in an anvil or repaired.", "&7",
					"&c&lFalse&f: &7Allows the item to be repaired.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isItemRepairable() + "").toUpperCase()), event -> {
				if (itemMap.isItemRepairable()) {
					itemMap.setItemRepairable(false);
				} else {
					itemMap.setItemRepairable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CRAFTING_TABLE" : "58"), 1, itemMap.isItemCraftable(), "&a&l&nItem Craftable", "&7", 
					"&a&lTrue&f: &7Blocks the item from being", "&7used in a crafting recipe.", "&7",
					"&c&lFalse&f: &7Item will be usable in", "&7a crafting recipe.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isItemCraftable() + "").toUpperCase()), event -> {
				if (itemMap.isItemCraftable()) {
					itemMap.setItemCraftable(false);
				} else {
					itemMap.setItemCraftable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("BOW", 1, itemMap.isCancelEvents(), "&a&l&nCancel Events", "&7", 
					"&a&lTrue&f: &7Prevents almost any event from executing", "&7when right-clicking the item.", "&7",
					"&c&lFalse&f: &7Allows item events to be executed freely.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isCancelEvents() + "").toUpperCase()), event -> {
				if (itemMap.isCancelEvents()) {
					itemMap.setCancelEvents(false);
				} else {
					itemMap.setCancelEvents(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WHEAT_SEEDS" : "295"), 1, itemMap.isAlwaysGive(), "&a&l&nAlways Give", "&7", 
					"&a&lTrue&f: &7Gives the item every time the player", "&7performs one of the triggers actions.", "&7regardless of already having the item.", "&7",
					"&cNOTE: &7Don't use this if you want only ONE instance of the item.", "&7",
					"&c&lFalse&f: &7Normal item restrictions will apply.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isAlwaysGive() + "").toUpperCase()), event -> {
				if (itemMap.isAlwaysGive()) {
					itemMap.setAlwaysGive(false);
				} else {
					itemMap.setAlwaysGive(true);
				}
				flagPane(player, itemMap);
			}));
			if (itemMap.getMaterial().toString().contains("TIPPED_ARROW") || itemMap.getMaterial().toString().contains("ARROW")) {
				flagPane.addButton(new Button(ItemHandler.getItem("ENDER_PEARL", 1, itemMap.isTeleport(), "&a&l&nTeleport", "&7", 
						"&a&lTrue&f: &7Teleports the Player to the location", "&7that the arrow landed.", 
						"&cNOTE: &7This only works if the arrow is fired by a Bow.",
						"&9&lENABLED: &a" + (itemMap.isTeleport() + "").toUpperCase()), event -> {
					if (itemMap.isTeleport()) {
						itemMap.setTeleport(false);
					} else {
						itemMap.setTeleport(true);
					}
					flagPane(player, itemMap);
				}));
			} else { flagPane.addButton(new Button(fillerPaneBItem)); }
			flagPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTING_TABLE" : "116"), 1, itemMap.isItemChangable(), "&a&l&nAllow Modifications", "&7", 
					"&a&lTrue&f: &7Allows the players to modify the item", "&7while retaining all properties.", "&7",
					"&c&lFalse&f: &7Item will not be modifiable.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isItemChangable() + "").toUpperCase()), event -> {
				if (itemMap.isItemChangable()) {
					itemMap.setItemChangable(false);
				} else {
					itemMap.setItemChangable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("ITEM_FRAME", 1, itemMap.isGiveNext(), "&a&l&nGive Next", "&7", 
					"&a&lTrue&f: &7Gives the item to the next available slot", "&7only if the defined slot already has an existing item.", 
					"&cNOTE: &7The overwrite flag will not work.", "&7",
					"&c&lFalse&f:&7 The item will be only given in the defined slot.", "&7If an item is already in the slot the", "&7item wont be given, unless the overwrite", "&7flag is set to &l&aTrue&7.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isGiveNext() + "").toUpperCase()), event -> {
				if (itemMap.isGiveNext()) {
					itemMap.setGiveNext(false);
				} else {
					itemMap.setGiveNext(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("MINECART", 1, itemMap.isMoveNext(), "&a&l&nMove Next", "&7", 
					"&a&lTrue&f: &7Moves the existing item to the next available slot", "&7only if the defined slot already has an existing item.", 
					"&cNOTE: &7The overwrite flag will not work.", "&7",
					"&c&lFalse&f: &7The item will be only given in the defined slot.", "&7If an item is already in the slot the", "&7item wont be given, unless the overwrite", "&7flag is set to &l&aTrue&7.", "&7", 
					"&9&lENABLED: &a" + (itemMap.isMoveNext() + "").toUpperCase()), event -> {
				if (itemMap.isMoveNext()) {
					itemMap.setMoveNext(false);
				} else {
					itemMap.setMoveNext(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("DIAMOND_SWORD", 1, itemMap.isDropFull(), "&a&l&nDrop Full", "&7", 
					"&a&lTrue&f: &7Drops the item on the ground if", "&7the players inventory is full.", "&7",
					"&c&lFalse&f: &7Fails to give the item", "&7if the players inventory is full.", "&7", 
					"&9&lENABLED: &a" +  (itemMap.isDropFull() + "").toUpperCase()), event -> {
				if (itemMap.isDropFull()) {
					itemMap.setDropFull(false);
				} else {
					itemMap.setDropFull(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, itemMap.isSelectable(), "&a&l&nSelectable", "&7", 
					"&a&lTrue&f: &7Prevents the item from being", "&7held in the players hand.", "&7",
					"&c&lFalse&f: &7Allows the item to be selected.", "&7", 
					"&9&lENABLED: &a" +  (itemMap.isSelectable() + "").toUpperCase()), event -> {
				if (itemMap.isSelectable()) {
					itemMap.setSelectable(false);
				} else {
					itemMap.setSelectable(true);
				}
				flagPane(player, itemMap);
			}));
			flagPane.addButton(new Button(fillerPaneBItem), 35);
		});
		flagPane.open(player);
	}
	
   /**
    * Sets the ItemFlags to the ItemMap.
    * 
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void setItemFlags(final ItemMap itemMap) {
		String itemflags = "";
		if (itemMap.isVanilla()) { itemflags += "VANILLA, "; }
		if (itemMap.isVanillaStatus()) { itemflags += "VANILLA-STATUS, "; }
		if (itemMap.isVanillaControl()) { itemflags += "VANILLA-CONTROL, "; }
		if (itemMap.isIpLimted()) { itemflags += "IP-LIMIT, "; }
		if (itemMap.isUnbreakable()) { itemflags += "UNBREAKABLE, "; }
		if (itemMap.isAttributesInfo()) { itemflags += "HIDE-ATTRIBUTES, "; }
		if (itemMap.isFlagsInfo()) { itemflags += "HIDE-FLAGS, "; }
		if (itemMap.isDurabilityBar()) { itemflags += "HIDE-DURABILITY, "; }
		if (itemMap.isPlaceable()) { itemflags += "PLACEMENT, "; }
		if (itemMap.isEquip()) { itemflags += "CANCEL-EQUIP, "; }
		if (itemMap.isMovement()) { itemflags += "INVENTORY-MODIFY, "; }
		if (itemMap.isInventoryClose()) { itemflags += "INVENTORY-CLOSE, "; }
		if (itemMap.isDynamic()) { itemflags += "DYNAMIC, "; }
		if (itemMap.isAnimated()) { itemflags += "ANIMATE, "; }
		if (itemMap.isGlowing()) { itemflags += "GLOWING, "; }
		if (itemMap.isStackable()) { itemflags += "STACKABLE, "; }
		if (itemMap.isSelectable()) { itemflags += "SELECTABLE, "; }
		if (itemMap.isItemStore()) { itemflags += "ITEM-STORE, "; }
		if (itemMap.isCancelEvents()) { itemflags += "CANCEL-EVENTS, "; }
		if (itemMap.isCountLock()) { itemflags += "COUNT-LOCK, "; }
		if (itemMap.isDeathKeepable()) { itemflags += "DEATH-KEEP, "; }
		if (itemMap.isDeathDroppable()) { itemflags += "DEATH-DROPS, "; }
		if (itemMap.isSelfDroppable()) { itemflags += "SELF-DROPS, "; }
		if (itemMap.isDisposable()) { itemflags += "DISPOSABLE, "; }
		if (itemMap.isItemModify()) { itemflags += "ITEM-MODIFIABLE, "; }
		if (itemMap.isItemRepairable()) { itemflags += "ITEM-REPAIRABLE, "; }
		if (itemMap.isItemCraftable()) { itemflags += "ITEM-CRAFTABLE, "; }
		if (itemMap.isAlwaysGive()) { itemflags += "ALWAYS-GIVE, "; }
		if (itemMap.isItemChangable()) { itemflags += "ITEM-CHANGABLE, "; }
		if (itemMap.isTeleport()) { itemflags += "TELEPORT, "; }
		if (itemMap.isGiveNext()) { itemflags += "GIVE-NEXT, "; }
		if (itemMap.isMoveNext()) { itemflags += "MOVE-NEXT, "; }
		if (itemMap.isDropFull()) { itemflags += "DROP-FULL, "; }
		if (itemMap.isOverwritable()) { itemflags += "OVERWRITE, "; }
		if (itemMap.isOpBypass()) { itemflags += "ALLOWOPBYPASS, "; }
		if (itemMap.isAutoRemove()) { itemflags += "AUTO-REMOVE, "; }
		if (itemMap.isCreativeBypass()) { itemflags += "CREATIVEBYPASS, "; }
		if (itemflags.endsWith(", ")) { itemflags = itemflags.substring(0, itemflags.length() - 2); }
		itemMap.setItemFlags(itemflags);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items triggers.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void triggerPane(final Player player, final ItemMap itemMap) {
		Interface triggerPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			triggerPane.addButton(new Button(fillerPaneBItem), 3);
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "FILLED_MAP" : "MAP"), 1, itemMap.isOnlyFirstJoin(), "&e&l&nFirst Join", "&7", "&7*Gives the item when the", "&7player logs into the server", 
					"&7for the first time only.", "&7This will overwrite any triggers", "&7such as respawn, and world-switch.", "&9&lENABLED: &a" + (itemMap.isOnlyFirstJoin() + "").toUpperCase()), event -> {
				if (itemMap.isOnlyFirstJoin()) {
					itemMap.setOnlyFirstJoin(false);
				} else {
					itemMap.setOnlyFirstJoin(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("STONE_SWORD", 1, itemMap.isOnlyFirstWorld(), "&e&l&nFirst World", "&7", "&7*Gives the item when the", "&7player enters each of the defined", "&7worlds for the first time.", "&7", 
					"&7This flag overwrites any triggers", "&7such as respawn, and join.", "&9&lENABLED: &a" + (itemMap.isOnlyFirstWorld() + "").toUpperCase()), event -> {
				if (itemMap.isOnlyFirstWorld()) {
					itemMap.setOnlyFirstWorld(false);
				} else {
					itemMap.setOnlyFirstWorld(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem(ServerUtils.hasSpecificUpdate("1_13") ? "TOTEM_OF_UNDYING" : "322:1", 1, itemMap.isOnlyFirstLife(), "&e&l&nFirst Life", "&7", "&7*Gives the item when the", "&7player logs into the server", 
					"&7for the first time only,", "&7but will give the item", "&7EVERY TIME on player RESPAWN.", "&7This flag overwrites any triggers", "&7such as respawn, and join.", "&9&lENABLED: &a" + (itemMap.isOnlyFirstWorld() + "").toUpperCase()), event -> {
				if (itemMap.isOnlyFirstWorld()) {
					itemMap.setOnlyFirstWorld(false);
				} else {
					itemMap.setOnlyFirstWorld(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(fillerPaneBItem), 3);
			triggerPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, itemMap.isGiveOnDisabled(), "&c&l&nDISABLED", "&7", "&7*Prevents the item from given", "&7through the use of triggers.", "&7", "&7Useful to only get the item", 
					"&7using &l/itemjoin get <item>", "&9&lENABLED: &a" + (itemMap.isGiveOnDisabled() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnDisabled()) {
					itemMap.setGiveOnDisabled(false);
				} else {
					itemMap.setGiveOnJoin(false);
					itemMap.setOnlyFirstJoin(false);
					itemMap.setOnlyFirstWorld(false);
					itemMap.setOnlyFirstLife(false);
					itemMap.setGiveOnRespawn(false);
					itemMap.setGiveOnWorldSwitch(false);
					itemMap.setUseOnLimitSwitch(false);
					itemMap.setGiveOnRegionEnter(false);
					itemMap.setGiveOnRegionLeave(false);
					itemMap.setGiveOnRegionAccess(false);
					itemMap.setGiveOnRegionEgress(false);
					itemMap.setGiveOnDisabled(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_SIGN" : "323"), 1, itemMap.isGiveOnJoin(), "&e&l&nJoin", "&7", "&7*Gives the item when the", "&7player logs into the server.", 
					"&9&lENABLED: &a" + (itemMap.isGiveOnJoin() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnJoin()) {
					itemMap.setGiveOnJoin(false);
				} else {
					itemMap.setGiveOnJoin(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, itemMap.isGiveOnRespawn(), "&e&l&nRespawn", "&7", "&7*Gives the item when the", "&7player respawns from a death event.", "&9&lENABLED: &a" + 
			(itemMap.isGiveOnRespawn() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnRespawn()) {
					itemMap.setGiveOnRespawn(false);
				} else {
					itemMap.setGiveOnRespawn(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("STONE_BUTTON", 1, itemMap.isGiveOnWorldSwitch(), "&e&l&nWorld Switch", "&7", "&7*Gives the item when the", "&7player teleports to one", "&7of the specified worlds.", 
					"&9&lENABLED: &a" + (itemMap.isGiveOnWorldSwitch() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnWorldSwitch()) {
					itemMap.setGiveOnWorldSwitch(false);
				} else {
					itemMap.setGiveOnWorldSwitch(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("LEVER", 1, itemMap.isUseOnLimitSwitch(), "&e&l&nGamemode Switch", "&7", "&7*Gives the item when the", "&7player changes gamemodes to any", "&7of the defined limit-modes.", 
					"&9&lENABLED: &a" + (itemMap.isUseOnLimitSwitch() + "").toUpperCase()), event -> {
				if (itemMap.isUseOnLimitSwitch()) {
					itemMap.setUseOnLimitSwitch(false);
				} else {
					itemMap.setUseOnLimitSwitch(true);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("MINECART", 1, itemMap.isGiveOnRegionEnter(), "&e&l&nRegion Enter", "&7", "&7*Gives the item when the", "&7player enters any of the enabled-regions.", "&9&lENABLED: &a" +
			(itemMap.isGiveOnRegionEnter() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnRegionEnter()) {
					itemMap.setGiveOnRegionEnter(false);
				} else {
					itemMap.setGiveOnRegionEnter(true);
					itemMap.setGiveOnRegionAccess(false);
					itemMap.setGiveOnRegionEgress(false);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "HOPPER_MINECART" : "408"), 1, itemMap.isGiveOnRegionLeave(), "&e&l&nRegion Leave", "&7", "&7*Removes the item when the", "&7player leaves any of the enabled-regions.", "&9&lENABLED: &a" +
			(itemMap.isGiveOnRegionLeave() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnRegionLeave()) {
					itemMap.setGiveOnRegionLeave(false);
				} else {
					itemMap.setGiveOnRegionLeave(true);
					itemMap.setGiveOnRegionAccess(false);
					itemMap.setGiveOnRegionEgress(false);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "TNT_MINECART" : "407"), 1, itemMap.isGiveOnRegionAccess(), "&e&l&nRegion Access", "&7", "&7*Gives the item when the", "&7player enters any of the enabled-regions", "&7and removes the item when leaving", "&7any of the enabled-regions.", "&9&lENABLED: &a" +
			(itemMap.isGiveOnRegionAccess() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnRegionAccess()) {
					itemMap.setGiveOnRegionAccess(false);
				} else {
					itemMap.setGiveOnRegionAccess(true);
					itemMap.setGiveOnRegionEnter(false);
					itemMap.setGiveOnRegionLeave(false);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CHEST_MINECART" : "342"), 1, itemMap.isGiveOnRegionEgress(), "&e&l&nRegion Engress", "&7", "&7*Removes the item when the", "&7player enters any of the enabled-regions", "&7and gives the item when leaving", "&7any of the enabled-regions.", "&9&lENABLED: &a" +
			(itemMap.isGiveOnRegionEgress() + "").toUpperCase()), event -> {
				if (itemMap.isGiveOnRegionEgress()) {
					itemMap.setGiveOnRegionEgress(false);
				} else {
					itemMap.setGiveOnRegionEgress(true);
					itemMap.setGiveOnRegionEnter(false);
					itemMap.setGiveOnRegionLeave(false);
				}
				triggerPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu"), event -> {
				setTriggers(itemMap);creatingPane(player, itemMap);
			}));
			triggerPane.addButton(new Button(fillerPaneBItem), 7);
			triggerPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu"), event -> {
				setTriggers(itemMap);creatingPane(player, itemMap);
			}));
		});
		triggerPane.open(player);
	}
	
   /**
    * Sets the Triggers to the ItemMap.
    * 
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void setTriggers(final ItemMap itemMap) {
		String triggers = "";
		if (itemMap.isGiveOnDisabled()) { triggers += "DISABLED, "; }
		if (itemMap.isGiveOnJoin() && !itemMap.isOnlyFirstJoin() && !itemMap.isOnlyFirstWorld()) { triggers += "JOIN, "; }
		if (itemMap.isOnlyFirstJoin()) { triggers += "FIRST-JOIN, "; }
		if (itemMap.isOnlyFirstWorld()) { triggers += "FIRST-WORLD, "; }
		if (itemMap.isOnlyFirstLife()) { triggers += "FIRST-LIFE, "; }
		if (itemMap.isGiveOnRespawn() && !itemMap.isOnlyFirstJoin() && !itemMap.isOnlyFirstWorld()) { triggers += "RESPAWN, "; }
		if (itemMap.isGiveOnWorldSwitch() && !itemMap.isOnlyFirstWorld()) { triggers += "WORLD-SWITCH, "; }
		if (itemMap.isUseOnLimitSwitch()) { triggers += "GAMEMODE-SWITCH, "; }
		if (itemMap.isGiveOnRegionEnter()) { triggers += "REGION-ENTER, "; }
		if (itemMap.isGiveOnRegionLeave()) { triggers += "REGION-LEAVE, "; }
		if (itemMap.isGiveOnRegionAccess()) { triggers += "REGION-ACCESS, "; }
		if (itemMap.isGiveOnRegionEgress()) { triggers += "REGION-EGRESS, "; }
		if (triggers.endsWith(", ")) { triggers = triggers.substring(0, triggers.length() - 2); }
		itemMap.setTriggers(triggers);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items worlds.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param stage - The type of selection Pane.
    */
	private static void worldPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface worldPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage == 4) {
				worldPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> {
					activeCommands(player);
				}));
			} else {
				worldPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
					creatingPane(player, itemMap);
				}));
			}
			List < String > listWorlds = (stage == 4 ? new ArrayList<String>(): (stage == 0 ? itemMap.getDisabledWorlds() : itemMap.getEnabledWorlds()));
			if (stage == 4) {
				for (String world : ConfigHandler.getConfig().getFile("config.yml").getString("Active-Commands.enabled-worlds").replace(" ", "").split(",")) {
					listWorlds.add(world);
				}
			}
			worldPane.addButton(new Button(ItemHandler.getItem("OBSIDIAN", 1, (stage == 4 ? (StringUtils.containsValue(listWorlds, "ALL") || StringUtils.containsValue(listWorlds, "GLOBAL")) : itemMap.containsWorld("ALL", (stage == 0 ? true : false))), "&a&l&nGLOBAL", "&7", "&7*Click to " + 
					(stage == 0 ? "disable" : "enable") + " the", "&7custom item in &lALL WORLDS.", (stage == 0 ? "&9&lDISABLED:" : "&9&lENABLED:") + " &a" + 
					(stage == 4 ? (StringUtils.containsValue(listWorlds, "ALL") || StringUtils.containsValue(listWorlds, "GLOBAL")) : (itemMap.containsWorld("ALL", (stage == 0 ? true : false))) + "")), event -> {
				if ((stage == 4 && (StringUtils.containsValue(listWorlds, "ALL") || StringUtils.containsValue(listWorlds, "GLOBAL"))) || (stage != 4 && itemMap.containsWorld("ALL", (stage == 0 ? true : false)))) {
					listWorlds.remove("GLOBAL");
					listWorlds.remove("ALL");
				} else {
					listWorlds.add("GLOBAL");
				}
				if (stage == 4) {
						File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Active-Commands.enabled-worlds", (listWorlds.isEmpty() ? "DISABLED" : "GLOBAL")); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> worldPane(player, itemMap, stage));
				} else if (stage == 0) {
					itemMap.setDisabledWorlds(listWorlds);
					worldPane(player, itemMap, stage);
				} else {
					itemMap.setEnabledWorlds(listWorlds);
					worldPane(player, itemMap, stage);
				}
			}));
			for (World world: Bukkit.getServer().getWorlds()) {
				String worldMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2");
				if (world.getEnvironment().equals(Environment.NETHER)) {
					worldMaterial = "NETHERRACK";
				} else if (world.getEnvironment().equals(Environment.THE_END)) {
					worldMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "END_STONE" : "121");
				}
				worldPane.addButton(new Button(ItemHandler.getItem(worldMaterial, 1, (stage == 4 ? StringUtils.containsValue(listWorlds, world.getName()) : itemMap.containsWorld(world.getName(), (stage == 0 ? true : false))), 
						"&f&l" + world.getName(), "&7", "&7*Click to " + (stage == 0 ? "disable" : "enable") + " the", "&7custom item in this world.", 
						(stage == 0 ? "&9&lDISABLED:" : "&9&lENABLED:") + " &a" + (stage == 4 ? StringUtils.containsValue(listWorlds, world.getName()) : (itemMap.containsWorld(world.getName(), (stage == 0 ? true : false))) + "")), event -> {
					if ((stage == 4 && StringUtils.containsValue(listWorlds, world.getName())) || (stage != 4 && itemMap.containsWorld(world.getName(), (stage == 0 ? true : false)))) {
						listWorlds.remove(world.getName());
					} else {
						listWorlds.add(world.getName());
					}
					if (stage == 4) {
						if (listWorlds.isEmpty()) {
							listWorlds.add("DISABLED");
						} else if (StringUtils.containsValue(listWorlds, "DISABLED") || StringUtils.containsValue(listWorlds, "DISABLE")) {
							listWorlds.remove("DISABLED");
						}
						String worldList = "";
						for (String worldString : listWorlds) {
							worldList += worldString + ", ";
						}
						if (!worldList.isEmpty()) {
							worldList = worldList.substring(0, worldList.length() - 2);
						}
						File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
						FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
						dataFile.set("Active-Commands.enabled-worlds", worldList); 	
						ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
						ConfigHandler.getConfig().softReload();
						SchedulerUtils.runLater(2L, () -> worldPane(player, itemMap, stage));
					} else if (stage == 0) {
						itemMap.setDisabledWorlds(listWorlds);
						worldPane(player, itemMap, stage);
					} else {
						itemMap.setEnabledWorlds(listWorlds);
						worldPane(player, itemMap, stage);
					}
				}));
			}
		});
		worldPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items regions.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void regionPane(final Player player, final ItemMap itemMap) {
		Interface regionPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			regionPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				creatingPane(player, itemMap);
			}));
			List < String > enabledRegions = itemMap.getEnabledRegions();
			regionPane.addButton(new Button(ItemHandler.getItem("OBSIDIAN", 1, itemMap.containsRegion("UNDEFINED"), "&c&l&nUNDEFINED", "&7", "&7*Click to enable the", "&7custom item in &lALL REGIONS.", "&9&lENABLED: &a" + 
			(itemMap.containsRegion("UNDEFINED") + "").toUpperCase()), event -> {
				if (itemMap.containsRegion("UNDEFINED")) {
					enabledRegions.remove("UNDEFINED");
				} else {
					enabledRegions.add("UNDEFINED");
				}
				itemMap.setEnabledRegions(enabledRegions);regionPane(player, itemMap);
			}));
			for (World world: Bukkit.getServer().getWorlds()) {
				for (String region: DependAPI.getDepends(false).getGuard().getRegions(world).keySet()) {
					String regionMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2");
					if (world.getEnvironment().equals(Environment.NETHER)) {
						regionMaterial = "NETHERRACK";
					} else if (world.getEnvironment().equals(Environment.THE_END)) {
						regionMaterial = (ServerUtils.hasSpecificUpdate("1_13") ? "END_STONE" : "121");
					}
					regionPane.addButton(new Button(ItemHandler.getItem(regionMaterial, 1, itemMap.containsRegion(region), "&f&l" + region, "&7", "&a&lWORLD: &f" + world.getName(), "&7", "&7*Click to enable the", 
							"&7custom item in this region.", "&9&lENABLED: &a" + (itemMap.containsRegion(region) + "").toUpperCase()), event -> {
						if (itemMap.containsRegion(region)) {
							enabledRegions.remove(region);
						} else {
							enabledRegions.add(region);
						}
						itemMap.setEnabledRegions(enabledRegions);regionPane(player, itemMap);
					}));
				}
			}
		});
		regionPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying an items lore.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void lorePane(final Player player, final ItemMap itemMap) {
		Interface lorePane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			lorePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			lorePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&eNew Lore Line", "&7", "&7*Add a new lore line", "&7to the item lore."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "LORE LINE";
				placeHolders[15] = "&bThis is a new lore line.";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "LORE LINE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				List<String> lore = new ArrayList<String>(); 
				if (itemMap.getCustomLore() != null) {
					lore = itemMap.getCustomLore(); 
					lore.add(ChatColor.stripColor(event.getMessage())); 
					itemMap.setCustomLore(lore); 
				} else { 
					lore.add(ChatColor.stripColor(event.getMessage())); 
					itemMap.setCustomLore(lore);
				}
				lorePane(player, itemMap);
			}));
			if (itemMap.getCustomLore() != null && !itemMap.getCustomLore().isEmpty()) {
				for (int i = 1; i <= itemMap.getCustomLore().size(); i++) {
					final int k = i;
					lorePane.addButton(new Button(ItemHandler.getItem("WRITABLE_BOOK", 1, false, "&fLore " + k, "&7", "&7*Click modify this lore line.", "&9&lLore: &a" + itemMap.getCustomLore().get(k - 1)), event -> modifyLoreLinePane(player, itemMap, k - 1)));
				}
			}
		});
		lorePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying a specific lore line.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifyLoreLinePane(final Player player, final ItemMap itemMap, final int position) {
		Interface modifyLorePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modifyLorePane.addButton(new Button(fillerPaneGItem), 3);
			modifyLorePane.addButton(new Button(ItemHandler.getItem("WRITABLE_BOOK", 1, false, "&e&l&nModify", "&7", "&7*Change the lore line.", "&9&lLore: &a" + itemMap.getCustomLore().get(position)), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "LORE LINE";
				placeHolders[15] = "&bThis is a new lore line.";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				List <  String> lore = itemMap.getCustomLore();
				lore.set(position, ChatColor.stripColor(event.getMessage()));
				itemMap.setCustomLore(lore);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "LORE LINE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				modifyLoreLinePane(event.getPlayer(), itemMap, position);
			}));
			modifyLorePane.addButton(new Button(fillerPaneGItem));
			modifyLorePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this lore line."), event -> {
				List < String > lore = itemMap.getCustomLore();
				lore.remove(position);
				itemMap.setCustomLore(lore);
				lorePane(player, itemMap);
			}));
			modifyLorePane.addButton(new Button(fillerPaneGItem), 3);
			modifyLorePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> lorePane(player, itemMap)));
			modifyLorePane.addButton(new Button(fillerPaneBItem), 7);
			modifyLorePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> lorePane(player, itemMap)));
		});
		modifyLorePane.open(player);
	}
	
//  ============================================== //
//           Animation Definition Menus            //
//  ============================================== //
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated material.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void animateMaterialPane(final Player player, final ItemMap itemMap) {
		Interface animateMaterialPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			animateMaterialPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animation menu."), event -> {
				if (!itemMap.getDynamicMaterials().isEmpty()) {
					itemMap.setAnimate(true);
					if (ItemHandler.cutDelay(itemMap.getDynamicMaterials().get(0)).contains(":")) {
						String[] material = ItemHandler.cutDelay(itemMap.getDynamicMaterials().get(0)).split(":");
						itemMap.setMaterial(ItemHandler.getMaterial(material[0], null));
						itemMap.setDataValue((short)Integer.parseInt(material[1]));
					} else {
						itemMap.setMaterial(ItemHandler.getMaterial(ItemHandler.cutDelay(itemMap.getDynamicMaterials().get(0)), null));
					}
				}
				animationPane(player, itemMap);
			}));
			animateMaterialPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&eNew Material", "&7", "&7*Add a new material", "&7to be animated between."), event -> selectMaterialPane(player, itemMap, 0, true)));
			for (int i = 1; i <= itemMap.getDynamicMaterials().size(); i++) {
				final int k = i;
				animateMaterialPane.addButton(new Button(ItemHandler.getItem(ItemHandler.cutDelay(itemMap.getDynamicMaterials().get(k - 1)), 1, false, "&fMaterial " + k, "&7", "&7*Click modify this animated material.", 
						"&9&lAnimation Ticks: &a" + StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicMaterials().get(k - 1)))), event -> modifyMaterialPane(player, itemMap, k - 1)));
			}
		});
		animateMaterialPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying aniamted material.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void selectMaterialPane(final Player player, final ItemMap itemMap, final int position, final boolean isNew) {
		Interface selectMaterialPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			selectMaterialPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated material menu."), event -> {
				animateMaterialPane(player, itemMap);
			}));
			selectMaterialPane.addButton(new Button(ItemHandler.getItem("STICK", 1, true, "&b&lBukkit Material", "&7", "&7*If you know the name", "&7of the BUKKIT material type", "&7simply click and type it."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "BUKKIT MATERIAL";
				placeHolders[15] = "IRON_SWORD";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null) != null) {
					if (isNew) {
						durationMaterialPane(player, itemMap, position, isNew, ChatColor.stripColor(event.getMessage()).toUpperCase());
					} else {
						List < String > mats = itemMap.getDynamicMaterials();
						mats.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(mats.get(position))) + ">" + ChatColor.stripColor(event.getMessage()).toUpperCase());
						itemMap.setDynamicMaterials(mats);
						modifyMaterialPane(player, itemMap, position);
					}
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "BUKKIT MATERIAL";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noMaterial", player, placeHolders);
					selectMaterialPane(player, itemMap, position, isNew);
				}
			}));
				Inventory inventoryCheck = Bukkit.getServer().createInventory(null, 9, GUIName);
				for (Material material: Material.values()) {
				if (!material.name().contains("LEGACY") && material.name() != "AIR" && safeMaterial(ItemHandler.getItem(material.toString(), 1, false, "", ""), inventoryCheck)) {
					if (!ServerUtils.hasSpecificUpdate("1_13") && LegacyAPI.getDataValue(material) != 0) {
						for (int i = 0; i <= LegacyAPI.getDataValue(material); i++) {
							if (!material.toString().equalsIgnoreCase("STEP") || material.toString().equalsIgnoreCase("STEP") && i != 2) {
								final int dataValue = i;
								selectMaterialPane.addButton(new Button(ItemHandler.getItem(material.toString() + ":" + dataValue, 1, false, "", "&7", "&7*Click to set the", "&7material of the item."), event -> {
									if (isNew) {
										if (dataValue != 0) { durationMaterialPane(player, itemMap, position, isNew, material.name() + ":" + dataValue); }
										else { durationMaterialPane(player, itemMap, position, isNew, material.name()); }
									} else {
										List < String > mats = itemMap.getDynamicMaterials();
										if (dataValue != 0) { mats.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(mats.get(position))) + ">" + material.name() + ":" + dataValue); }
										else { mats.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(mats.get(position))) + ">" + material.name()); }
										itemMap.setDynamicMaterials(mats);
										modifyMaterialPane(player, itemMap, position);
									}
								}));
							}
						}
					} else {
						selectMaterialPane.addButton(new Button(ItemHandler.getItem(material.toString(), 1, false, "", "&7", "&7*Click to set the", "&7material of the item."), event -> {
							if (isNew) {
								durationMaterialPane(player, itemMap, position, isNew, material.name());
							} else {
								List < String > mats = itemMap.getDynamicMaterials();
								mats.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(mats.get(position))) + ">" + material.name());
								itemMap.setDynamicMaterials(mats);
								modifyMaterialPane(player, itemMap, position);
							}
						}));
					}
				}
			}
			inventoryCheck.clear();
		});
		selectMaterialPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated material duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void durationMaterialPane(final Player player, final ItemMap itemMap, final int position, final boolean isNew, final String value) {
		Interface durationPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			durationPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated menu."), event -> animateMaterialPane(player, itemMap)));
			durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Duration", "&7", "&7*Click to set a custom duration", "&7value for the animation."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATION DURATION";
				placeHolders[15] = "110";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "ANIMATION DURATION";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					List < String > mats = itemMap.getDynamicMaterials();
					if (isNew) {
						if (itemMap.getDynamicMaterials().isEmpty()) {
							mats.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + itemMap.getMaterial());
						}
						mats.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + value);
					} else {
						mats.set(position, "<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + ItemHandler.cutDelay(mats.get(position)));
					}
					itemMap.setDynamicMaterials(mats);
					if (isNew) {
						animateMaterialPane(player, itemMap);
					} else {
						modifyMaterialPane(player, itemMap, position);
					}
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					durationMaterialPane(player, itemMap, position, isNew, value);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Ticks(s)", "&7", "&7*Click to set the", "&7duration of the animation."), event -> {
					List < String > mats = itemMap.getDynamicMaterials();
					if (isNew) {
						if (itemMap.getDynamicMaterials().isEmpty()) {
							mats.add("<delay:" + k + ">" + itemMap.getMaterial());
						}
						mats.add("<delay:" + k + ">" + value);
					} else {
						mats.set(position, "<delay:" + k + ">" + ItemHandler.cutDelay(mats.get(position)));
					}
					itemMap.setDynamicMaterials(mats);
					if (isNew) {
						animateMaterialPane(player, itemMap);
					} else {
						modifyMaterialPane(player, itemMap, position);
					}
				}));
			}
		});
		durationPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated material.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifyMaterialPane(final Player player, final ItemMap itemMap, final int position) {
		Interface modifyMaterialPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modifyMaterialPane.addButton(new Button(fillerPaneGItem), 3);
			modifyMaterialPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&a&l&nMaterial", "&7", "&7*Change the animated material type.", "&9&lMaterial: &a" + ItemHandler.cutDelay(itemMap.getDynamicMaterials().get(position))),
					event -> selectMaterialPane(player, itemMap, position, false)));
			modifyMaterialPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&e&l&nDuration", "&7", "&7*Change the duration of the animation.", "&9&lAnimation Ticks: &a" + 
			StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicMaterials().get(position)))), event -> durationMaterialPane(player, itemMap, position, false, ItemHandler.cutDelay(itemMap.getDynamicMaterials().get(position)))));
			modifyMaterialPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this animated material."), event -> {
				List < String > mats = itemMap.getDynamicMaterials();mats.remove(position);
				itemMap.setDynamicMaterials(mats);
				animateMaterialPane(player, itemMap);
			}));
			modifyMaterialPane.addButton(new Button(fillerPaneGItem), 3);
			modifyMaterialPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated material menu."), event -> animateMaterialPane(player, itemMap)));
			modifyMaterialPane.addButton(new Button(fillerPaneBItem), 7);
			modifyMaterialPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated material menu."), event -> animateMaterialPane(player, itemMap)));
		});
		modifyMaterialPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated names.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void animatedNamePane(final Player player, final ItemMap itemMap) {
		Interface animatedNamePane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			animatedNamePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animation menu."), event -> {
				if (!itemMap.getDynamicNames().isEmpty()) {
					itemMap.setAnimate(true);
					itemMap.setCustomName(ItemHandler.cutDelay(itemMap.getDynamicNames().get(0)));
				}
				animationPane(player, itemMap);
			}));
			animatedNamePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&eNew Name Line", "&7", "&7*Add a new name line", "&7to be animated between."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NAME";
				placeHolders[15] = "&bUltimate Sword";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				durationNamePane(player, itemMap, 0, true, ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NAME";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
			}));
			for (int i = 1; i <= itemMap.getDynamicNames().size(); i++) {
				final int k = i;
				animatedNamePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&fName " + k, "&7", "&7*Click modify this animated name.", "&9&lName: &a" + ItemHandler.cutDelay(itemMap.getDynamicNames().get(k - 1)), 
						"&9&lAnimation Ticks: &a" + StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicNames().get(k - 1)))), event -> modifyNamePane(player, itemMap, k - 1)));
			}
		});	
		animatedNamePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated name duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void durationNamePane(final Player player, final ItemMap itemMap, final int position, final boolean isNew, final String value) {
		Interface durationPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			durationPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated menu."), event -> animatedNamePane(player, itemMap)));
			durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Duration", "&7", "&7*Click to set a custom duration", "&7value for the animation."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATION DURATION";
				placeHolders[15] = "110";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "ANIMATION DURATION";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					List < String > names = itemMap.getDynamicNames();
					if (isNew) {
						if (itemMap.getDynamicNames().isEmpty() && itemMap.getCustomName() != null && !itemMap.getCustomName().isEmpty()) {
							names.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + itemMap.getCustomName());
						}
						names.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + value);
					} else {
						names.set(position, "<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + ItemHandler.cutDelay(names.get(position)));
					}
					itemMap.setDynamicNames(names);
					if (isNew) {
						animatedNamePane(player, itemMap);
					} else {
						modifyNamePane(player, itemMap, position);
					}
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					durationNamePane(player, itemMap, position, isNew, value);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Ticks(s)", "&7", "&7*Click to set the", "&7duration of the animation."), event -> {
					List < String > names = itemMap.getDynamicNames();
					if (isNew) {
						if (itemMap.getDynamicNames().isEmpty() && itemMap.getCustomName() != null && !itemMap.getCustomName().isEmpty()) {
							names.add("<delay:" + k + ">" + itemMap.getCustomName());
						}
						names.add("<delay:" + k + ">" + value);
					} else {
						names.set(position, "<delay:" + k + ">" + ItemHandler.cutDelay(names.get(position)));
					}
					itemMap.setDynamicNames(names);
					if (isNew) {
						animatedNamePane(player, itemMap);
					} else {
						modifyNamePane(player, itemMap, position);
					}
				}));
			}
		});
		durationPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying aniamted names.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifyNamePane(final Player player, final ItemMap itemMap, final int position) {
		Interface modifyNamePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modifyNamePane.addButton(new Button(fillerPaneGItem), 3);
			modifyNamePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&a&l&nName", "&7", "&7*Change the animated name line.", "&9&lName: &a" + ItemHandler.cutDelay(itemMap.getDynamicNames().get(position))), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NAME";
				placeHolders[15] = "&bUltimate Sword";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				List < String > names = itemMap.getDynamicNames();
				names.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(names.get(position))) + ">" + ChatColor.stripColor(event.getMessage()));
				itemMap.setDynamicNames(names)
				;String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NAME";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				modifyNamePane(event.getPlayer(), itemMap, position);
			}));
			modifyNamePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&e&l&nDuration", "&7", "&7*Change the duration of the animation.", "&9&lAnimation Ticks: &a" + 
			StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicNames().get(position)))), event -> durationNamePane(player, itemMap, position, false, ItemHandler.cutDelay(itemMap.getDynamicNames().get(position)))));
			modifyNamePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this animated name."), event -> {
				List < String > names = itemMap.getDynamicNames();
				names.remove(position);
				itemMap.setDynamicNames(names);
				animatedNamePane(player, itemMap);
			}));
			modifyNamePane.addButton(new Button(fillerPaneGItem), 3);
			modifyNamePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated name menu."), event -> animatedNamePane(player, itemMap)));
			modifyNamePane.addButton(new Button(fillerPaneBItem), 7);
			modifyNamePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated name menu."), event -> animatedNamePane(player, itemMap)));
		});
		modifyNamePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated lore.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void animatedLorePane(final Player player, final ItemMap itemMap) {
		Interface animatedLorePane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			animatedLorePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animation menu."), event -> {
				if (!itemMap.getDynamicLores().isEmpty()) {
					itemMap.setAnimate(true);
					itemMap.setCustomLore(ItemHandler.cutDelay(itemMap.getDynamicLores().get(0)));
				}
				animationPane(player, itemMap);
			}));
			animatedLorePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&eNew Lore Line", "&7", "&7*Add a new lore line", "&7to be animated between."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATED LORE";
				placeHolders[15] = "&bThis is line 1, &cThis is line 2, &6This is line 3";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATED LORE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				durationLorePane(event.getPlayer(), itemMap, 0, true, ChatColor.stripColor(event.getMessage()));
			}));
			for (int i = 1; i <= itemMap.getDynamicLores().size(); i++) {
				final int k = i;
				animatedLorePane.addButton(new Button(ItemHandler.getItem("WRITABLE_BOOK", 1, false, "&fLore " + k, "&7", "&7*Click modify this animated lore.", "&9&lLore: &a" + ItemHandler.cutDelay(itemMap.getDynamicLores().get(k - 1)), 
						"&9&lAnimation Ticks: &a" + StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicLores().get(k - 1).get(0)))), event -> modifyLorePane(player, itemMap, k - 1)));
			}
		});
		animatedLorePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated lore duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void durationLorePane(final Player player, final ItemMap itemMap, final int position, final boolean isNew, final String value) {
		Interface durationPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			durationPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated menu."), event -> animatedLorePane(player, itemMap)));
			durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Duration", "&7", "&7*Click to set a custom duration", "&7value for the animation."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATION DURATION";
				placeHolders[15] = "110";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "ANIMATION DURATION";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					List < List < String >> lores = itemMap.getDynamicLores();
					if (isNew) {
						if (itemMap.getDynamicLores().isEmpty() && itemMap.getCustomLore() != null && !itemMap.getCustomLore().isEmpty()) {
							List < String > loreCut = itemMap.getCustomLore();
							loreCut.set(0, "<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + loreCut.get(0));
							lores.add(loreCut);
						}
						lores.add(StringUtils.split("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + value));
					} else {
						List < String > loreCut = ItemHandler.cutDelay(lores.get(position));
						loreCut.set(0, "<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + loreCut.get(0));
						lores.set(position, loreCut);
					}
					itemMap.setDynamicLores(lores);
					if (isNew) {
						animatedLorePane(player, itemMap);
					} else {
						modifyLorePane(player, itemMap, position);
					}
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					durationLorePane(player, itemMap, position, isNew, value);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Ticks(s)", "&7", "&7*Click to set the", "&7duration of the animation."), event -> {
					List < List < String >> lores = itemMap.getDynamicLores();
					if (isNew) {
						if (itemMap.getDynamicLores().isEmpty() && itemMap.getCustomLore() != null && !itemMap.getCustomLore().isEmpty()) {
							List < String > loreCut = itemMap.getCustomLore();
							loreCut.set(0, "<delay:" + k + ">" + loreCut.get(0));
							lores.add(loreCut);
						}
						lores.add(StringUtils.split("<delay:" + k + ">" + value));
					} else {
						List < String > loreCut = ItemHandler.cutDelay(lores.get(position));
						loreCut.set(0, "<delay:" + k + ">" + loreCut.get(0));
						lores.set(position, loreCut);
					}
					itemMap.setDynamicLores(lores);
					if (isNew) {
						animatedLorePane(player, itemMap);
					} else {
						modifyLorePane(player, itemMap, position);
					}
				}));
			}
		});
		durationPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated lore.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifyLorePane(final Player player, final ItemMap itemMap, final int position) {
		Interface modifyLorePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modifyLorePane.addButton(new Button(fillerPaneGItem), 3);
			modifyLorePane.addButton(new Button(ItemHandler.getItem("WRITABLE_BOOK", 1, false, "&a&l&nLore", "&7", "&7*Change the animated lore line.", "&9&lLore: &a" + ItemHandler.cutDelay(itemMap.getDynamicLores().get(position))), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATED LORE";
				placeHolders[15] = "&bThis is line 1, &cThis is line 2, &6This is line 3";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				List < List < String >> lores = itemMap.getDynamicLores();
				lores.set(position, StringUtils.split("<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(lores.get(position).get(0))) + ">" + ChatColor.stripColor(event.getMessage())));
				itemMap.setDynamicLores(lores);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATED LORE";LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				modifyLorePane(event.getPlayer(), itemMap, position);
			}));
			modifyLorePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&e&l&nDuration", "&7", "&7*Change the duration of the animation.", "&9&lAnimation Ticks: &a" + 
			StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicLores().get(position).get(0)))), event -> durationLorePane(player, itemMap, position, false, "")));
			modifyLorePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this animated lore."), event -> {
				List < List < String >> lores = itemMap.getDynamicLores();
				lores.remove(position);
				itemMap.setDynamicLores(lores);
				animatedLorePane(player, itemMap);
			}));
			modifyLorePane.addButton(new Button(fillerPaneGItem), 3);
			modifyLorePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated lore menu."), event -> animatedLorePane(player, itemMap)));
			modifyLorePane.addButton(new Button(fillerPaneBItem), 7);
			modifyLorePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated lore menu."), event -> animatedLorePane(player, itemMap)));
		});
		modifyLorePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying animated skull items.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void animatedSkullPane(final Player player, final ItemMap itemMap, boolean owner) {
		Interface animatedSkullPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (owner) {
				animatedSkullPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animation menu."), event -> {
					if (!itemMap.getDynamicOwners().isEmpty()) {
						itemMap.setAnimate(true);
						itemMap.setSkullTexture("");
						itemMap.setDynamicTextures(new ArrayList < String > ());
						itemMap.setSkull(ItemHandler.cutDelay(itemMap.getDynamicOwners().get(0)));
					}
					animationPane(player, itemMap);
				}));
				animatedSkullPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&eNew Skull Owner", "&7", "&7*Add a new skull owner", "&7to be animated between."), event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL OWNER";
					placeHolders[15] = "RockinChaos";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					durationSkullPane(player, itemMap, 0, true, ChatColor.stripColor(event.getMessage()), owner);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL OWNER";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				}));
				for (int i = 1; i <= itemMap.getDynamicOwners().size(); i++) {
					final int k = i;
					animatedSkullPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_HELMET" : "314"), 1, false, "&fSkull Owner " + k, "&7", "&7*Click modify this animated skull owner.", "&9&lSkull Owner: &a" + 
					ItemHandler.cutDelay(itemMap.getDynamicOwners().get(k - 1)), "&9&lAnimation Ticks: &a" + StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicOwners().get(k - 1)))), event -> modifySkullPane(player, itemMap, k - 1, owner)));
				}
			} else {
				animatedSkullPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animation menu."), event -> {
					if (!itemMap.getDynamicTextures().isEmpty()) {
						itemMap.setAnimate(true);
						itemMap.setSkull("");
						itemMap.setDynamicOwners(new ArrayList < String > ());
						itemMap.setSkullTexture(ItemHandler.cutDelay(itemMap.getDynamicTextures().get(0)));
					}
					animationPane(player, itemMap);
				}));
				animatedSkullPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&eNew Skull Texture", "&7", "&7*Add a new skull texture", "&7to be animated between."), event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL TEXTURE";
					placeHolders[15] = "eyJ0ZXh0dYMGQVlN2FjZmU3OSJ9fX0=";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					durationSkullPane(player, itemMap, 0, true, ChatColor.stripColor(event.getMessage()), owner);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL TEXTURE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				}));
				for (int i = 1; i <= itemMap.getDynamicTextures().size(); i++) {
					final int k = i;
					animatedSkullPane.addButton(new Button(ItemHandler.getItem("STRING", 1, false, "&fSkull Texture " + k, "&7", "&7*Click modify this animated skull texture.", "&9&lSkull Texture: &a" + 
					(ItemHandler.cutDelay(itemMap.getDynamicTextures().get(k - 1)).length() > 40 ? ItemHandler.cutDelay(itemMap.getDynamicTextures().get(k - 1)).substring(0, 40) : ItemHandler.cutDelay(itemMap.getDynamicTextures().get(k - 1))),
					"&9&lAnimation Ticks: &a" + StringUtils.returnInteger(ItemHandler.getDelayFormat(itemMap.getDynamicTextures().get(k - 1)))), event -> modifySkullPane(player, itemMap, k - 1, owner)));
				}
			}
		});
		animatedSkullPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the skull animation duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void durationSkullPane(final Player player, final ItemMap itemMap, final int position, final boolean isNew, final String value, boolean owner) {
		Interface durationPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			durationPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated menu."), event -> animatedSkullPane(player, itemMap, owner)));
			durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Duration", "&7", "&7*Click to set a custom duration", "&7value for the animation."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "ANIMATION DURATION";
				placeHolders[15] = "110";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "ANIMATION DURATION";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					List < String > skulls = itemMap.getDynamicOwners();
					if (!owner) {
						skulls = itemMap.getDynamicTextures();
					}
					if (isNew) {
						if (itemMap.getDynamicOwners().isEmpty() && owner && itemMap.getSkull() != null && !itemMap.getSkull().isEmpty()) {
							skulls.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + itemMap.getSkull());
						} else if (itemMap.getDynamicTextures().isEmpty() && !owner && itemMap.getSkullTexture() != null && !itemMap.getSkullTexture().isEmpty()) {
							skulls.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + itemMap.getSkullTexture());
						}
						skulls.add("<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + value);
					} else {
						skulls.set(position, "<delay:" + Integer.parseInt(ChatColor.stripColor(event.getMessage())) + ">" + ItemHandler.cutDelay(skulls.get(position)));
					}
					if (owner) {
						itemMap.setDynamicOwners(skulls);
					} else {
						itemMap.setDynamicTextures(skulls);
					}
					if (isNew) {
						animatedSkullPane(player, itemMap, owner);
					} else {
						modifySkullPane(player, itemMap, position, owner);
					}
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					durationSkullPane(player, itemMap, position, isNew, value, owner);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Ticks(s)", "&7", "&7*Click to set the", "&7duration of the animation."), event -> {
					List < String > skulls = itemMap.getDynamicOwners();
					if (!owner) {
						skulls = itemMap.getDynamicTextures();
					}
					if (isNew) {
						if (itemMap.getDynamicOwners().isEmpty() && owner && itemMap.getSkull() != null && !itemMap.getSkull().isEmpty()) {
							skulls.add("<delay:" + k + ">" + itemMap.getSkull());
						} else if (itemMap.getDynamicTextures().isEmpty() && !owner && itemMap.getSkullTexture() != null && !itemMap.getSkullTexture().isEmpty()) {
							skulls.add("<delay:" + k + ">" + itemMap.getSkullTexture());
						}
						skulls.add("<delay:" + k + ">" + value);
					} else {
						skulls.set(position, "<delay:" + k + ">" + ItemHandler.cutDelay(skulls.get(position)));
					}
					if (owner) {
						itemMap.setDynamicOwners(skulls);
					} else {
						itemMap.setDynamicTextures(skulls);
					}
					if (isNew) {
						animatedSkullPane(player, itemMap, owner);
					} else {
						modifySkullPane(player, itemMap, position, owner);
					}
				}));
			}
		});
		durationPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the skull owner or skull texture.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifySkullPane(final Player player, final ItemMap itemMap, final int position, boolean owner) {
		Interface modifySkullPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modifySkullPane.addButton(new Button(fillerPaneGItem), 3);
			if (owner) {
				modifySkullPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_HELMET" : "314"), 1, false, "&a&l&nSkull Owner", "&7", "&7*Change the animated skull owner.", "&9&lSkull Owner: &a" + 
			ItemHandler.cutDelay(itemMap.getDynamicOwners().get(position))), event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL OWNER";
					placeHolders[15] = "RockinChaos";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					List < String > skulls = itemMap.getDynamicOwners();
					skulls.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(skulls.get(position))) + ">" + ChatColor.stripColor(event.getMessage()));
					itemMap.setDynamicOwners(skulls);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL OWNER";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					modifySkullPane(event.getPlayer(), itemMap, position, owner);
				}));
			} else {
				modifySkullPane.addButton(new Button(ItemHandler.getItem("STRING", 1, false, "&a&l&nSkull Texture", "&7", "&7*Change the animated skull texture.", "&9&lSkull Texture: &a" + 
			ItemHandler.cutDelay(itemMap.getDynamicTextures().get(position))), event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL TEXTURE";
					placeHolders[15] = "eyJ0ZXh0dYMGQVlN2FjZmU3OSJ9fX0=";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					List < String > skulls = itemMap.getDynamicTextures();
					skulls.set(position, "<delay:" + StringUtils.returnInteger(ItemHandler.getDelayFormat(skulls.get(position))) + ">" + ChatColor.stripColor(event.getMessage()));
					itemMap.setDynamicTextures(skulls);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL TEXTURE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					modifySkullPane(event.getPlayer(), itemMap, position, owner);
				}));
			}
			modifySkullPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "CLOCK" : "347"), 1, false, "&e&l&nDuration", "&7", "&7*Change the duration of the animation.", "&9&lAnimation Ticks: &a" + 
			StringUtils.returnInteger(ItemHandler.getDelayFormat((owner ? itemMap.getDynamicOwners().get(position) : itemMap.getDynamicTextures().get(position))))), 
					event -> durationSkullPane(player, itemMap, position, false, ItemHandler.cutDelay((owner ? itemMap.getDynamicOwners().get(position) : itemMap.getDynamicTextures().get(position))), owner)));
			modifySkullPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this animated skull " + (owner ? "owner." : "texture.")), event -> {
				List < String > skulls = itemMap.getDynamicOwners();
				if (!owner) {
					skulls = itemMap.getDynamicTextures();
				}
				skulls.remove(position);
				if (owner) {
					itemMap.setDynamicOwners(skulls);
				} else {
					itemMap.setDynamicTextures(skulls);
				}
				animatedSkullPane(player, itemMap, owner);
			}));
			modifySkullPane.addButton(new Button(fillerPaneGItem), 3);
			modifySkullPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated skull menu."), event -> animatedSkullPane(player, itemMap, owner)));
			modifySkullPane.addButton(new Button(fillerPaneBItem), 7);
			modifySkullPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the animated skull menu."), event -> animatedSkullPane(player, itemMap, owner)));
		});
		modifySkullPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying item animations.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void animationPane(final Player player, final ItemMap itemMap) {
		Interface animationPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (itemMap.getMaterial().toString().contains("PLAYER_HEAD") || itemMap.getMaterial().toString().contains("SKULL_ITEM")) {
				animationPane.addButton(new Button(fillerPaneGItem), 2);
			} else {
				animationPane.addButton(new Button(fillerPaneGItem), 3);
			}
			animationPane.addButton(new Button(ItemHandler.getItem(itemMap.getMaterial().toString(), 1, false, "&c&l&nMaterial", "&7", "&7*Add additional material types", "&7to have the item change between.", "&9&lAnimated Materials: &a" + 
			(StringUtils.nullCheck(itemMap.getDynamicMaterials() + "") != "NONE" ? "YES" : "NONE")), event -> animateMaterialPane(player, itemMap)));
			animationPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&a&l&nName", "&7", "&7*Add additional custom names", "&7to have the item change between.", "&9&lAnimated Names: &a" + 
			(StringUtils.nullCheck(itemMap.getDynamicNames() + "") != "NONE" ? "YES" : "NONE")), event -> animatedNamePane(player, itemMap)));
			animationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, false, "&b&l&nLore", "&7", "&7*Add additional custom lores", "&7to have the item change between.", "&9&lAnimated Lores: &a" + 
			(StringUtils.nullCheck(itemMap.getDynamicLores() + "") != "NONE" ? "YES" : "NONE")), event -> animatedLorePane(player, itemMap)));
			if (itemMap.getMaterial().toString().contains("PLAYER_HEAD") || itemMap.getMaterial().toString().contains("SKULL_ITEM")) {
				animationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_HELMET" : "314"), 1, false, "&a&lSkull Owner", "&7", "&7*Add additional skull owners", "&7to have the item change between.", "&7", "&7You can only define skull owner", 
						"&7or skull texture, this will", "&7remove any skull textures.", "&9&lAnimated Owners: &a" + (StringUtils.nullCheck(itemMap.getDynamicOwners() + "") != "NONE" ? "YES" : "NONE")), event -> animatedSkullPane(player, itemMap, true)));
				animationPane.addButton(new Button(ItemHandler.getItem("STRING", 1, false, "&b&lSkull Texture", "&7", "&7*Add additional skull textures", "&7to have the item change between.", "&7", "&7You can only define skull texture", 
						"&7or skull owner, this will", "&7remove any skull owners.", "&7", "&7Skull textures can be found", "&7at websites like &aminecraft-heads.com", "&7and the value is listed under", "&7the OTHER section.", 
						"&9&lAnimated Textures: &a" + (StringUtils.nullCheck(itemMap.getDynamicTextures() + "") != "NONE" ? "YES" : "NONE")), event -> animatedSkullPane(player, itemMap, false)));
				animationPane.addButton(new Button(fillerPaneGItem), 2);
			} else {
				animationPane.addButton(new Button(fillerPaneGItem), 3);
			}
			animationPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			animationPane.addButton(new Button(fillerPaneBItem), 7);
			animationPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		animationPane.open(player);
	}

//  ===========================================================================================================================================================================================================================================================
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the Limit Gamemodes.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void limitPane(final Player player, final ItemMap itemMap) {
		Interface limitPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			List < String > limitModes = new ArrayList < String > ();
			if (StringUtils.containsIgnoreCase(itemMap.getLimitModes(), "ADVENTURE")) {
				limitModes.add("ADVENTURE");
			}
			if (StringUtils.containsIgnoreCase(itemMap.getLimitModes(), "SURVIVAL")) {
				limitModes.add("SURVIVAL");
			}
			if (StringUtils.containsIgnoreCase(itemMap.getLimitModes(), "CREATIVE")) {
				limitModes.add("CREATIVE");
			}
			limitPane.addButton(new Button(fillerPaneGItem), 3);
			limitPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "FILLED_MAP" : "MAP"), 1, limitModes.contains("ADVENTURE"), "&a&l&nADVENTURE", "&7", "&7*Limits the item to ADVENTURE mode.", "&9&lENABLED: &a" + 
			(limitModes.contains("ADVENTURE") + "").toUpperCase()), event -> {
				if (limitModes.contains("ADVENTURE")) {
					limitModes.remove("ADVENTURE");
				} else {
					limitModes.add("ADVENTURE");
				}
				itemMap.setLimitModes(limitModes.toString().substring(0, limitModes.toString().length() - 1).substring(1));limitPane(player, itemMap);
			}));
			limitPane.addButton(new Button(ItemHandler.getItem("STONE_SWORD", 1, limitModes.contains("SURVIVAL"), "&b&l&nSURVIVAL", "&7", "&7*Limits the item to SURVIVAL mode.", "&9&lENABLED: &a" + (limitModes.contains("SURVIVAL") + "").toUpperCase()), 
					event -> {
				if (limitModes.contains("SURVIVAL")) {
					limitModes.remove("SURVIVAL");
				} else {
					limitModes.add("SURVIVAL");
				}
				itemMap.setLimitModes(limitModes.toString().substring(0, limitModes.toString().length() - 1).substring(1));limitPane(player, itemMap);
			}));
			limitPane.addButton(new Button(ItemHandler.getItem(limitModes.contains("CREATIVE") ? (ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1") : "GOLDEN_APPLE", 1, false, "&6&l&nCREATIVE", "&7", "&7*Limits the item to CREATIVE mode.", "&9&lENABLED: &a" + 
			(limitModes.contains("CREATIVE") + "").toUpperCase()), event -> {
				if (limitModes.contains("CREATIVE")) {
					limitModes.remove("CREATIVE");
				} else {
					limitModes.add("CREATIVE");
				}
				itemMap.setLimitModes(limitModes.toString().substring(0, limitModes.toString().length() - 1).substring(1));limitPane(player, itemMap);
			}));
			limitPane.addButton(new Button(fillerPaneGItem), 3);
			limitPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			limitPane.addButton(new Button(fillerPaneBItem), 7);
			limitPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		limitPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the item probability.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void probabilityPane(final Player player, final ItemMap itemMap) {
		Interface probabilityPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			probabilityPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				creatingPane(player, itemMap);
			}));
			for (int i = 1; i < 100; i++) {
				final int k = i;
				probabilityPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), 1, false, "&9&lChance: &a&l" + k + "%", "&7", "&7*Click to set the", "&7probability of the item."), event -> {
					itemMap.setProbability(k);creatingPane(player, itemMap);
				}));
			}
		});
		probabilityPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the use-cooldown.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void usePane(final Player player, final ItemMap itemMap) {
		Interface usePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			usePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> {
				creatingPane(player, itemMap);
			}));
			usePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Usage", "&7", "&7*Click to set a custom usage cooldown", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "USAGE COOLDOWN";
				placeHolders[15] = "120";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setInteractCooldown(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "USAGE COOLDOWN";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				creatingPane(event.getPlayer(), itemMap);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				usePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Second(s)", "&7", "&7*Click to set the", "&7use-cooldown of the item."), event -> {
					itemMap.setInteractCooldown(k);
					creatingPane(player, itemMap);
				}));
			}
		});
		usePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the drop chances.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void dropsPane(final Player player, final ItemMap itemMap) {
		Interface dropsPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			String mobs = "";
			String blocks = "";
			for (EntityType entity: itemMap.getMobsDrop().keySet()) { mobs += entity.name() + ", "; }
			for (Material material: itemMap.getBlocksDrop().keySet()) { blocks += material.name() + ", "; }
			dropsPane.addButton(new Button(fillerPaneBItem), 12);
			dropsPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ZOMBIE_SPAWN_EGG" : "383:54"), 1, false, "&b&lMobs Drop", "&7", "&7*Define mobs that are", "&7allowed to drop the item.", (!mobs.isEmpty() ? "&9&lMobs: &a" + mobs.substring(0, mobs.length() - 2) : "")), event -> {
				mobsPane(player, itemMap);
			}));
			dropsPane.addButton(new Button(fillerPaneBItem));
			dropsPane.addButton(new Button(ItemHandler.getItem("DIAMOND_ORE", 1, false, "&b&lBlocks Drop", "&7", "&7*Define blocks that are", "&7allowed to drop the item.", (!blocks.isEmpty() ? "&9&lBlocks: &a" + blocks.substring(0, blocks.length() - 2) : "")), event -> {
				blocksPane(player, itemMap);
			}));
			dropsPane.addButton(new Button(fillerPaneBItem), 3);
			dropsPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			dropsPane.addButton(new Button(fillerPaneBItem), 7);
			dropsPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		dropsPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the mobs drop chances.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void mobsPane(final Player player, final ItemMap itemMap) {
		Interface dropsPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			dropsPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the drop chances menu."), event -> dropsPane(player, itemMap)));
			for (EntityType entity: EntityType.values()) {
				if (itemMap.getMobsDrop().containsKey(entity) && entity.isAlive()) {
					dropsPane.addButton(new Button(ItemHandler.getItem("EGG", 1, (itemMap.getMobsDrop().containsKey(entity)), "&f" + entity.name(), "&7", "&7*Click to add this as", "&7a banner pattern.", 
							(itemMap.getMobsDrop().containsKey(entity) ? "&9&lChance: &a" + itemMap.getMobsDrop().get(entity) : "")), event -> {
						if (itemMap.getMobsDrop().containsKey(entity)) {
							Map<EntityType, Double> mobsDrop = itemMap.getMobsDrop();
							mobsDrop.remove(entity);
							itemMap.setMobsDrop(mobsDrop);
							mobsPane(player, itemMap);
						} else {
							chancePane(player, itemMap, entity, null);
						}
					}));
				}
			}
			for (EntityType entity: EntityType.values()) {
				if (!itemMap.getMobsDrop().containsKey(entity) && entity.isAlive()) {
					dropsPane.addButton(new Button(ItemHandler.getItem("EGG", 1, (itemMap.getMobsDrop().containsKey(entity)), "&f" + entity.name(), "&7", "&7*Click to add this as", "&7a banner pattern.", 
							(itemMap.getMobsDrop().containsKey(entity) ? "&9&lChance: &a" + itemMap.getMobsDrop().get(entity) : "")), event -> {
						if (itemMap.getMobsDrop().containsKey(entity)) {
							Map<EntityType, Double> mobsDrop = itemMap.getMobsDrop();
							mobsDrop.remove(entity);
							itemMap.setMobsDrop(mobsDrop);
							mobsPane(player, itemMap);
						} else {
							chancePane(player, itemMap, entity, null);
						}
					}));
				}
			}
		});
		dropsPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the blocks drop chances.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void blocksPane(final Player player, final ItemMap itemMap) {
		Interface blockPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			blockPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the drop chances menu."), event -> {
				dropsPane(player, itemMap);
			}));
			blockPane.addButton(new Button(ItemHandler.getItem("STICK", 1, true, "&b&lBukkit Material", "&7", "&7*If you know the name", "&7of the BUKKIT material type", "&7simply click and type it."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "BUKKIT MATERIAL";
				placeHolders[15] = "IRON_SWORD";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null) != null) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "BUKKIT MATERIAL";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					chancePane(player, itemMap, null, ItemHandler.getMaterial(ChatColor.stripColor(event.getMessage()), null));
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noMaterial", player, placeHolders);
					blocksPane(player, itemMap);
				}
			}));
			Inventory inventoryCheck = Bukkit.getServer().createInventory(null, 9, GUIName);
			for (Material material: Material.values()) {
				if (material.isBlock() && itemMap.getBlocksDrop().containsKey(material)) {
					if (!material.name().contains("LEGACY") && material.name() != "AIR" && safeMaterial(ItemHandler.getItem(material.toString(), 1, false, "", ""), inventoryCheck)) {
						if (!ServerUtils.hasSpecificUpdate("1_13") && LegacyAPI.getDataValue(material) != 0) {
							for (int i = 0; i <= LegacyAPI.getDataValue(material); i++) {
								if (!material.toString().equalsIgnoreCase("STEP") || material.toString().equalsIgnoreCase("STEP") && i != 2) {
									final int dataValue = i;
									blockPane.addButton(new Button(ItemHandler.getItem(material.toString() + ":" + dataValue, 1, (itemMap.getBlocksDrop().containsKey(material)), "", "&7", "&7*Click to set the material.",
											(itemMap.getBlocksDrop().containsKey(material) ? "&9&lChance: &a" + itemMap.getBlocksDrop().get(material) : "")), event -> {
										if (itemMap.getBlocksDrop().containsKey(material)) {
											Map<Material, Double> blocksDrop = itemMap.getBlocksDrop();
											blocksDrop.remove(material);
											itemMap.setBlocksDrop(blocksDrop);
											blocksPane(player, itemMap);
										} else {
											chancePane(player, itemMap, null, material);
										}
									}));
								}
							}
						} else {
						blockPane.addButton(new Button(ItemHandler.getItem(material.toString(), 1, (itemMap.getBlocksDrop().containsKey(material)), "", "&7", "&7*Click to set the material.",
								(itemMap.getBlocksDrop().containsKey(material) ? "&9&lChance: &a" + itemMap.getBlocksDrop().get(material) : "")), event -> {
							if (itemMap.getBlocksDrop().containsKey(material)) {
								Map<Material, Double> blocksDrop = itemMap.getBlocksDrop();
								blocksDrop.remove(material);
								itemMap.setBlocksDrop(blocksDrop);
								blocksPane(player, itemMap);
							} else {
								chancePane(player, itemMap, null, material);
							}
						}));
						}
					}
				}
			}
			for (Material material: Material.values()) {
				if (material.isBlock() && !itemMap.getBlocksDrop().containsKey(material)) {
					if (!material.name().contains("LEGACY") && material.name() != "AIR" && safeMaterial(ItemHandler.getItem(material.toString(), 1, false, "", ""), inventoryCheck)) {
						if (!ServerUtils.hasSpecificUpdate("1_13") && LegacyAPI.getDataValue(material) != 0) {
							for (int i = 0; i <= LegacyAPI.getDataValue(material); i++) {
								if (!material.toString().equalsIgnoreCase("STEP") || material.toString().equalsIgnoreCase("STEP") && i != 2) {
									final int dataValue = i;
									blockPane.addButton(new Button(ItemHandler.getItem(material.toString() + ":" + dataValue, 1, (itemMap.getBlocksDrop().containsKey(material)), "", "&7", "&7*Click to set the material.",
											(itemMap.getBlocksDrop().containsKey(material) ? "&9&lChance: &a" + itemMap.getBlocksDrop().get(material) : "")), event -> {
										if (itemMap.getBlocksDrop().containsKey(material)) {
											Map<Material, Double> blocksDrop = itemMap.getBlocksDrop();
											blocksDrop.remove(material);
											itemMap.setBlocksDrop(blocksDrop);
											blocksPane(player, itemMap);
										} else {
											chancePane(player, itemMap, null, material);
										}
									}));
								}
							}
						} else {
						blockPane.addButton(new Button(ItemHandler.getItem(material.toString(), 1, (itemMap.getBlocksDrop().containsKey(material)), "", "&7", "&7*Click to set the material.",
								(itemMap.getBlocksDrop().containsKey(material) ? "&9&lChance: &a" + itemMap.getBlocksDrop().get(material) : "")), event -> {
							if (itemMap.getBlocksDrop().containsKey(material)) {
								Map<Material, Double> blocksDrop = itemMap.getBlocksDrop();
								blocksDrop.remove(material);
								itemMap.setBlocksDrop(blocksDrop);
								blocksPane(player, itemMap);
							} else {
								chancePane(player, itemMap, null, material);
							}
						}));
						}
					}
				}
			}
			inventoryCheck.clear();
		});
		blockPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting an items drop chances.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param entity - The Entity selected.
    */
	private static void chancePane(final Player player, final ItemMap itemMap, final EntityType entity, final Material material) {
		Interface chancePane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (entity != null) {
				chancePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the mobs drop menu."), event -> {
					mobsPane(player, itemMap);
				}));
			} else {
				chancePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the blocks drop menu."), event -> {
					blocksPane(player, itemMap);
				}));
			}
			chancePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRAY_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:7"), 1, false, "&e&lCustom Drop Chance", "&7", "&7*Click to set a custom drop chance", "&7value for the item."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "DROP CHANCE";
				placeHolders[15] = "0.001";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isDouble(ChatColor.stripColor(event.getMessage()))) {
					if (entity != null) { 
						Map<EntityType, Double> mobsDrop = itemMap.getMobsDrop();
						mobsDrop.put(entity, Double.parseDouble(ChatColor.stripColor(event.getMessage())));
						itemMap.setMobsDrop(mobsDrop);
					} else {
						Map<Material, Double> blocksDrop = itemMap.getBlocksDrop();
						blocksDrop.put(material, Double.parseDouble(ChatColor.stripColor(event.getMessage())));
						itemMap.setBlocksDrop(blocksDrop);
					}
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "DROP CHANCE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				if (entity != null) { mobsPane(event.getPlayer(), itemMap); }
				else { blocksPane(event.getPlayer(), itemMap); }
			}));
			for (double i = 0.01; i < 1; i += 0.01) {
				final double k = Double.parseDouble(new DecimalFormat("#.##")
						.format(
								Double.parseDouble(Double.toString(i).replace(",", ".")))
						.replace(",", "."));
				chancePane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PURPLE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:10"), 1, false, "&9&lCost: &a$&l" + k, "&7", "&7*Click to set the", "&7drop chance of the item."), event -> {
					if (entity != null) { 
						Map<EntityType, Double> mobsDrop = itemMap.getMobsDrop();
						mobsDrop.put(entity, k);
						itemMap.setMobsDrop(mobsDrop);
						mobsPane(player, itemMap);
					} else {
						Map<Material, Double> blocksDrop = itemMap.getBlocksDrop();
						blocksDrop.put(material, k);
						itemMap.setBlocksDrop(blocksDrop);
						blocksPane(player, itemMap);
					}
				}));
			}
		});
		chancePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the item conditions.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void conditionsPane(final Player player, final ItemMap itemMap) {
		Interface conditionsPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			conditionsPane.addButton(new Button(fillerPaneBItem), 3);
			conditionsPane.addButton(new Button(ItemHandler.getItem("BOOK", 1, false, "&b&l&nCommand&b&l Conditions", "&7", "&7*Condition(s) that must be met", 
					"&7in order to execute item commands.", "&7", "&9&lENABLED: " + String.valueOf((StringUtils.nullCheck(itemMap.getCommandConditions() + "") != "NONE")).toUpperCase()), event -> commandActionPane(player, itemMap)));
			conditionsPane.addButton(new Button(ItemHandler.getItem("CACTUS", 1, false, "&b&l&nDisposable&b&l Conditions", "&7", "&7*Condition(s) that must be met", "&7in order for the disposable", "&7itemflag to function.",
					"&7", "&c&l&nNOTE:&7 The disposable itemflag", "&7must be defined for this", "&7condition to function.",
					"&7", "&9&lENABLED: " + String.valueOf((StringUtils.nullCheck(itemMap.getDisposableConditions() + "") != "NONE")).toUpperCase()), event -> disposableCPane(player, itemMap)));
			conditionsPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&b&l&nTrigger&b&l Conditions", "&7", "&7*Condition(s) that must be met", "&7in order to to receive the", 
					"&7item when performing a trigger.", "&7", "&9&lENABLED: " + String.valueOf((StringUtils.nullCheck(itemMap.getTriggerConditions() + "") != "NONE")).toUpperCase()), event -> triggerCPane(player, itemMap)));
			conditionsPane.addButton(new Button(fillerPaneBItem), 3);
			conditionsPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			conditionsPane.addButton(new Button(fillerPaneBItem), 7);
			conditionsPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		conditionsPane.open(player);
	}

   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the command action conditions.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void commandActionPane(final Player player, final ItemMap itemMap) {
		Interface commandPane = new Interface(false, 5, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			commandPane.addButton(new Button(fillerPaneGItem), 2);
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_DOOR" : (ServerUtils.hasSpecificUpdate("1_8") ? "324" : "64")), 1, false, "&e&lInteract", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_ALL.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_ALL);
			}));
			commandPane.addButton(new Button(fillerPaneGItem));
			commandPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&e&lInventory", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_ALL.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_ALL);
			}));
			commandPane.addButton(new Button(fillerPaneGItem));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PISTON" : "PISTON_BASE"), 1, false, "&e&lPhysical", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.PHYSICAL.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.PHYSICAL);
			}));
			commandPane.addButton(new Button(fillerPaneGItem), 2);
			commandPane.addButton(new Button(ItemHandler.getItem("DIAMOND_HELMET", 1, false, "&e&lOn-Equip", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_EQUIP.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_EQUIP);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("IRON_HELMET", 1, false, "&e&lUn-Equip", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.UN_EQUIP.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.UN_EQUIP);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("TORCH", 1, false, "&e&lOn-Hold", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_HOLD.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_HOLD);
			}));
			commandPane.addButton(new Button(fillerPaneGItem));
			commandPane.addButton(new Button(ItemHandler.getItem("ARROW", 1, false, "&e&lOn-Fire", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_FIRE.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_FIRE);
			}));
			commandPane.addButton(new Button(fillerPaneGItem));
			commandPane.addButton(new Button(ItemHandler.getItem("POTION", 1, false, "&e&lOn-Consume", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_CONSUME.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_CONSUME);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, false, "&e&lOn-Receive", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_RECEIVE.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_RECEIVE);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "SKELETON_SKULL" : "397"), 1, false, "&e&lOn-Death", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_DEATH.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_DEATH);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GLASS" : "20"), 1, false, "&e&lInteract-Air", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_AIR.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_AIR);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIGHT_BLUE_STAINED_GLASS" : "95:3"), 1, false, "&e&lInteract-Air-Left", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_LEFT_AIR.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_LEFT_AIR);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS" : "95:6"), 1, false, "&e&lInteract-Air-Right", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_RIGHT_AIR.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_RIGHT_AIR);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2:4"), 1, false, "&e&lInteract-Block", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_BLOCK.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_BLOCK);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "STONE" : "1"), 1, false, "&e&lInteract-Block-Left", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_LEFT_BLOCK.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_LEFT_BLOCK);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COBBLESTONE" : "4"), 1, false, "&e&lInteract-Block-Right", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_RIGHT_BLOCK.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_RIGHT_BLOCK);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "IRON_DOOR" : "330"), 1, false, "&e&lInteract-Left", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_LEFT_ALL.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_LEFT_ALL);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_DOOR" : (ServerUtils.hasSpecificUpdate("1_8") ? "324" : "64")), 1, false, "&e&lInteract-Right", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INTERACT_RIGHT_ALL.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INTERACT_RIGHT_ALL);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&e&lInventory-Swap-Cursor", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_SWAP_CURSOR.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_SWAP_CURSOR);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "SNOWBALL" : "SNOW_BALL"), 8, false, "&e&lInventory-Middle", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_MIDDLE.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_MIDDLE);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1"), 1, false, "&e&lInventory-Creative", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_CREATIVE.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_CREATIVE);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("ENDER_CHEST", 1, false, "&e&lInventory-Left", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_LEFT.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_LEFT);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&e&lInventory-Right", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_RIGHT.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_RIGHT);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "STONE_SLAB" : "44"), 2, false, "&e&lInventory-Shift-Left", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_SHIFT_LEFT.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_SHIFT_LEFT);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COBBLESTONE_SLAB" : "44:3"), 2, false, "&e&lInventory-Shift-Right", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.INVENTORY_SHIFT_RIGHT.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.INVENTORY_SHIFT_RIGHT);
			}));
			commandPane.addButton(new Button(fillerPaneGItem));
			commandPane.addButton(new Button(ItemHandler.getItem("LAVA_BUCKET", 1, false, "&e&lOn-Damage", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_DAMAGE.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_DAMAGE);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("DIAMOND_SWORD", 1, false, "&e&lOn-Hit", "&7", "&7*Condition(s) that must be met", "&7in order to execute item commands.",
					"&7", "&9&lENABLED: &a" + (StringUtils.nullCheck(itemMap.getCommandConditions().get(Action.ON_HIT.config()) + "") != "NONE" ? "YES" : "NO")), event -> {
				commandCPane(player, itemMap, Action.ON_HIT);
			}));
			commandPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item conditions menu."), event -> conditionsPane(player, itemMap)));
			commandPane.addButton(new Button(fillerPaneBItem), 7);
			commandPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item conditions menu."), event -> conditionsPane(player, itemMap)));
		});
		commandPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the commands conditions.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param commandAction - The command action being referenced.
    */
	private static void commandCPane(final Player player, final ItemMap itemMap, final Action commandAction) {
		Interface conditionsPane = new Interface(true, 2, GUIName, player);
		conditionsPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the command actions menu."), event -> commandActionPane(player, itemMap)));
		SchedulerUtils.runAsync(() -> {
			final String commandIdent = commandAction.config().replace("-", " ").replace(".", "");
			conditionsPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, (StringUtils.nullCheck(itemMap.getCommandMessages().get(commandAction.config())) != "NONE"), "&c&l" + String.valueOf(commandIdent.charAt(0)).toUpperCase() + commandIdent.substring(1) + " Fail Message", "&7", "&7*An optional message to be", "&7sent when the player does not", "&7meet the commands conditions.",
			"&7", "&9&lMESSAGE: &a" + (StringUtils.nullCheck(itemMap.getCommandMessages().get(commandAction.config())) != "NONE" ? itemMap.getCommandMessages().get(commandAction.config()) : "NONE")),
			event -> {
				if (StringUtils.nullCheck(itemMap.getCommandMessages().get(commandAction.config())) != "NONE") {
					Map<String, String> messages = itemMap.getCommandMessages();
					messages.put(commandAction.config(), null);
					itemMap.setCommandMessages(messages);
					commandCPane(player, itemMap, commandAction);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "COMMAND FAIL MESSAGE";
					placeHolders[15] = "&cYou do not meet the conditions to execute this item command.";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "COMMAND FAIL MESSAGE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				Map<String, String> messages = itemMap.getCommandMessages();
				messages.put(commandAction.config(), ChatColor.stripColor(event.getMessage()));
				itemMap.setCommandMessages(messages);
				commandCPane(player, itemMap, commandAction);
			}));
			conditionsPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&b&lAdd Condition", "&7", "&7*Condition(s) that must be met", 
					"&7in order to execute the", "&7" + commandAction.config().replace("-", " ").replace(".", "") + " item commands."), 			
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIRST VALUE";
				placeHolders[15] = "100";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIRST VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				addConditionPane(event.getPlayer(), itemMap, commandAction, commandAction.config(), ChatColor.stripColor(event.getMessage()));
			}));
			if (itemMap.getCommandConditions().get(commandAction.config()) != null) {
				for (String condition: itemMap.getCommandConditions().get(commandAction.config())) {
					conditionsPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&f" + condition, "&7", "&7*Click to remove this condition."), 
					event -> {
						Map<String, List<String>> commands = itemMap.getCommandConditions();
						List < String > conditions = commands.get(commandAction.config());
						conditions.remove(condition);
						commands.put(commandAction.config(), conditions);
						itemMap.setCommandConditions(commands);
						commandCPane(player, itemMap, commandAction);
					}));
				}
			}
		});
		conditionsPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the disposable conditions.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void disposableCPane(final Player player, final ItemMap itemMap) {
		Interface conditionsPane = new Interface(true, 2, GUIName, player);
		conditionsPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item conditions menu."), event -> conditionsPane(player, itemMap)));
		SchedulerUtils.runAsync(() -> {
			conditionsPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, (StringUtils.nullCheck(itemMap.getDisposableMessage()) != "NONE"), "&c&lDisposable Fail Message", "&7", "&7*An optional message to be", "&7sent when the player does not", "&7meet the disposable conditions.",
			"&7", "&9&lMESSAGE: &a" + (StringUtils.nullCheck(itemMap.getDisposableMessage()) != "NONE" ? itemMap.getDisposableMessage() : "NONE")),
			event -> {
				if (StringUtils.nullCheck(itemMap.getDisposableMessage()) != "NONE") {
					itemMap.setDisposableMessage(null);
					disposableCPane(player, itemMap);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "DISPOSABLE FAIL MESSAGE";
					placeHolders[15] = "&cYou do not meet the conditions to dispose of this item.";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				itemMap.setDisposableMessage(ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "DISPOSABLE FAIL MESSAGE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				disposableCPane(event.getPlayer(), itemMap);
			}));
			conditionsPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&b&lAdd Condition", "&7", "&7*Condition(s) that must be met", "&7in order to dispose of the item."), 			
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIRST VALUE";
				placeHolders[15] = "100";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIRST VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				addConditionPane(event.getPlayer(), itemMap, null, "disposable-conditions", ChatColor.stripColor(event.getMessage()));
			}));
			for (String condition: itemMap.getDisposableConditions()) {
				conditionsPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&f" + condition, "&7", "&7*Click to remove this condition."), 
				event -> {
					List < String > conditions = itemMap.getDisposableConditions();
					conditions.remove(condition);
					itemMap.setDisposableConditions(conditions);
					disposableCPane(player, itemMap);
				}));
			}
		});
		conditionsPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the trigger conditions.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void triggerCPane(final Player player, final ItemMap itemMap) {
		Interface conditionsPane = new Interface(true, 2, GUIName, player);
		conditionsPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item conditions menu."), event -> conditionsPane(player, itemMap)));
		SchedulerUtils.runAsync(() -> {
			conditionsPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, (StringUtils.nullCheck(itemMap.getTriggerMessage()) != "NONE"), "&c&lTrigger Fail Message", "&7", "&7*An optional message to be", "&7sent when the player does not", "&7meet the trigger conditions.",
			"&7", "&9&lMESSAGE: &a" + (StringUtils.nullCheck(itemMap.getTriggerMessage()) != "NONE" ? itemMap.getTriggerMessage() : "NONE")),
			event -> {
				if (StringUtils.nullCheck(itemMap.getTriggerMessage()) != "NONE") {
					itemMap.setTriggerMessage(null);
					triggerCPane(player, itemMap);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TRIGGER FAIL MESSAGE";
					placeHolders[15] = "&cYou do not meet the conditions to receive this item.";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				itemMap.setTriggerMessage(ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "TRIGGER FAIL MESSAGE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				triggerCPane(event.getPlayer(), itemMap);
			}));
			conditionsPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&b&lAdd Condition", "&7", "&7*Condition(s) that must be met", "&7in order to receive the item."), 			
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIRST VALUE";
				placeHolders[15] = "100";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIRST VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				addConditionPane(event.getPlayer(), itemMap, null, "trigger-conditions", ChatColor.stripColor(event.getMessage()));
			}));
			for (String condition: itemMap.getTriggerConditions()) {
				conditionsPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&f" + condition, "&7", "&7*Click to remove this condition."), 
				event -> {
					List < String > conditions = itemMap.getTriggerConditions();
					conditions.remove(condition);
					itemMap.setTriggerConditions(conditions);
					triggerCPane(player, itemMap);
				}));
			}
		});
		conditionsPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for adding the item condition.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param condition - The condition currently being modified.
    */
	private static void addConditionPane(final Player player, final ItemMap itemMap, final Action commandAction, final String condition1, final String value1) {
		Interface conditionsPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			conditionsPane.addButton(new Button(fillerPaneBItem));
			conditionsPane.addButton(new Button(ItemHandler.getItem("MINECART", 1, false, "&b&lEQUAL", "&7", "&7*The first value must be", "&7EQUAL to the second value", "&7for the condition to be met."),			
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				placeHolders[15] = "400";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				List < String > conditions = (condition1.equalsIgnoreCase("disposable-conditions") ? itemMap.getDisposableConditions() : condition1.equalsIgnoreCase("trigger-conditions") ? itemMap.getTriggerConditions() : itemMap.getCommandConditions().get(condition1) != null ? itemMap.getCommandConditions().get(condition1) : new ArrayList < String > ());
				conditions.add(value1 + ":" + "EQUAL" + ":" + ChatColor.stripColor(event.getMessage()));
				if (condition1.equalsIgnoreCase("disposable-conditions")) {
					itemMap.setDisposableConditions(conditions);
					disposableCPane(player, itemMap);
				} else if (condition1.equalsIgnoreCase("trigger-conditions")) {
					itemMap.setTriggerConditions(conditions);
					triggerCPane(player, itemMap);
				} else {
					Map<String, List<String>> conditions2 = itemMap.getCommandConditions();
					conditions2.put(condition1.replace("-conditions", ""), conditions);
					itemMap.setCommandConditions(conditions2);
					commandCPane(player, itemMap, commandAction);
				}
			}));
			conditionsPane.addButton(new Button(fillerPaneBItem));
			conditionsPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_FENCE" : "85"), 1, false, "&b&lNOTEQUAL", "&7", "&7*The first value must be", "&7NOTEQUAL to the second value", "&7for the condition to be met."), 
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				placeHolders[15] = "400";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				List < String > conditions = (condition1.equalsIgnoreCase("disposable-conditions") ? itemMap.getDisposableConditions() : condition1.equalsIgnoreCase("trigger-conditions") ? itemMap.getTriggerConditions() : itemMap.getCommandConditions().get(condition1) != null ? itemMap.getCommandConditions().get(condition1) : new ArrayList < String > ());
				conditions.add(value1 + ":" + "NOTEQUAL" + ":" + ChatColor.stripColor(event.getMessage()));
				if (condition1.equalsIgnoreCase("disposable-conditions")) {
					itemMap.setDisposableConditions(conditions);
					disposableCPane(player, itemMap);
				} else if (condition1.equalsIgnoreCase("trigger-conditions")) {
					itemMap.setTriggerConditions(conditions);
					triggerCPane(player, itemMap);
				} else {
					Map<String, List<String>> conditions2 = itemMap.getCommandConditions();
					conditions2.put(condition1.replace("-conditions", ""), conditions);
					itemMap.setCommandConditions(conditions2);
					commandCPane(player, itemMap, commandAction);
				}
			}));
			conditionsPane.addButton(new Button(fillerPaneBItem));
			conditionsPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_STAIRS" : "53"), 1, false, "&b&lOVER", "&7", "&7*The first value must be", "&7OVER the second value", "&7for the condition to be met.", "&7", "&c&l&nNOTE:&7 This only works if both", "&7values referenced are integers."), 
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				placeHolders[15] = "400";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				List < String > conditions = (condition1.equalsIgnoreCase("disposable-conditions") ? itemMap.getDisposableConditions() : condition1.equalsIgnoreCase("trigger-conditions") ? itemMap.getTriggerConditions() : itemMap.getCommandConditions().get(condition1) != null ? itemMap.getCommandConditions().get(condition1) : new ArrayList < String > ());
				conditions.add(value1 + ":" + "OVER" + ":" + ChatColor.stripColor(event.getMessage()));
				if (condition1.equalsIgnoreCase("disposable-conditions")) {
					itemMap.setDisposableConditions(conditions);
					disposableCPane(player, itemMap);
				} else if (condition1.equalsIgnoreCase("trigger-conditions")) {
					itemMap.setTriggerConditions(conditions);
					triggerCPane(player, itemMap);
				} else {
					Map<String, List<String>> conditions2 = itemMap.getCommandConditions();
					conditions2.put(condition1.replace("-conditions", ""), conditions);
					itemMap.setCommandConditions(conditions2);
					commandCPane(player, itemMap, commandAction);
				}
			}));
			conditionsPane.addButton(new Button(fillerPaneBItem));
			conditionsPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "OAK_BOAT" : "333"), 1, false, "&b&lUNDER", "&7", "&7*The first value must be", "&7UNDER to the second value", "&7for the condition to be met.", "&7", "&c&l&nNOTE:&7 This only works if both", "&7values referenced are integers."), 
			event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				placeHolders[15] = "400";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "SECOND VALUE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				List < String > conditions = (condition1.equalsIgnoreCase("disposable-conditions") ? itemMap.getDisposableConditions() : condition1.equalsIgnoreCase("trigger-conditions") ? itemMap.getTriggerConditions() : itemMap.getCommandConditions().get(condition1) != null ? itemMap.getCommandConditions().get(condition1) : new ArrayList < String > ());
				conditions.add(value1 + ":" + "UNDER" + ":" + ChatColor.stripColor(event.getMessage()));
				if (condition1.equalsIgnoreCase("disposable-conditions")) {
					itemMap.setDisposableConditions(conditions);
					disposableCPane(player, itemMap);
				} else if (condition1.equalsIgnoreCase("trigger-conditions")) {
					itemMap.setTriggerConditions(conditions);
					triggerCPane(player, itemMap);
				} else {
					Map<String, List<String>> conditions2 = itemMap.getCommandConditions();
					conditions2.put(condition1.replace("-conditions", ""), conditions);
					itemMap.setCommandConditions(conditions2);
					commandCPane(player, itemMap, commandAction);
				}
			}));
			conditionsPane.addButton(new Button(fillerPaneBItem));
			conditionsPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the " + condition1.replace("-", " ").replace(".", "") + " condition menu."), 
			event -> { 
				if (condition1.equalsIgnoreCase("disposable-conditions")) {
					disposableCPane(player, itemMap);
				} else if (condition1.equalsIgnoreCase("trigger-conditions")) {
					triggerCPane(player, itemMap);
				} else {
					commandCPane(player, itemMap, commandAction);
				}
			}));
			conditionsPane.addButton(new Button(fillerPaneBItem), 7);
			conditionsPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the " + condition1.replace("-", " ").replace(".", "") + " condition menu."), 
			event -> { 
				if (condition1.equalsIgnoreCase("disposable-conditions")) {
					disposableCPane(player, itemMap);
				} else if (condition1.equalsIgnoreCase("trigger-conditions")) {
					triggerCPane(player, itemMap);
				} else {
					commandCPane(player, itemMap, commandAction);
				}
			}));
		});
		conditionsPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying a list of commands.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param stage - The stage to be matched.
    */
	private static void altCommandPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface commandListPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage == 4) {
				commandListPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> {
					activeCommands(player);
				}));
			} else {
				commandListPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the click type menu."), event -> {
					togglePane(player, itemMap);
				}));
			}
			commandListPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&e&lNew Line", "&7", "&7*Add a new command to be executed."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = (stage == 4 ? "ACTIVE COMMAND" : "TOGGLE COMMAND");
				placeHolders[15] = (stage == 4 ? "gamemode creative %player%" : "pvp");
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (stage == 4) {
					final List<String> commands = ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands");
					commands.add(ChatColor.stripColor(event.getMessage()));
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands", commands); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> altCommandPane(player, itemMap, stage));
				} else {
					final List<String> toggleCommands = itemMap.getToggleCommands();
					toggleCommands.add(ChatColor.stripColor(event.getMessage()));
					itemMap.setToggleCommands(toggleCommands);
				}
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = (stage == 4 ? "ACTIVE COMMAND" : "TOGGLE COMMAND");
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				altCommandPane(event.getPlayer(), itemMap, stage);
			}));
			final List<String> commandsList = (stage == 4 ? ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands") : itemMap.getToggleCommands());
			for (String command: commandsList) {
				commandListPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&f" + command, "&7", "&7*Click to &lmodify &7this command."), event -> {
					modifyAltCommandsPane(player, itemMap, command, stage);
				}));
			}
		});
		commandListPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying a command.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param command - The command being modified.
    * @param stage - The stage to be matched.
    */
	private static void modifyAltCommandsPane(final Player player, final ItemMap itemMap, final String command, final int stage) {
		Interface modPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			modPane.addButton(new Button(fillerPaneGItem), 4);
			modPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&f" + command, "&7", "&7*You are modifying this command.")));
			modPane.addButton(new Button(fillerPaneGItem), 7);
			modPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, false, "&fModify", "&7", "&7*Sets the command to", "&7another text entry."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = (stage == 4 ? "MODIFIED ACTIVE COMMAND" : "MODIFIED TOGGLE COMMAND");
				placeHolders[15] = (stage == 4 ? "gamemode survival %player%" : "pvp on");
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (stage == 4) {
					final List<String> commands = ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands");
					commands.remove(command);
					commands.add(ChatColor.stripColor(event.getMessage()));
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands", commands); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> altCommandPane(player, itemMap, stage));
				} else {
					final List<String> toggleCommands = itemMap.getToggleCommands();
					toggleCommands.remove(command);
					toggleCommands.add(ChatColor.stripColor(event.getMessage()));
					itemMap.setToggleCommands(toggleCommands);
				}
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = (stage == 4 ? "MODIFIED ACTIVE COMMAND" : "MODIFIED TOGGLE COMMAND");
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				altCommandPane(player, itemMap, stage);
			}));
			modPane.addButton(new Button(fillerPaneGItem));
			modPane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&fDelete", "&7", "&7*Click to &cdelete &7this command."), event -> {
				if (stage == 4) {
					final List<String> commands = ConfigHandler.getConfig().getFile("config.yml").getStringList("Active-Commands.commands");
					commands.remove(command);
					File fileFolder =  new File (ItemJoin.getInstance().getDataFolder(), "config.yml");
					FileConfiguration dataFile = YamlConfiguration.loadConfiguration(fileFolder);
					dataFile.set("Active-Commands.commands", commands); 	
					ConfigHandler.getConfig().saveFile(dataFile, fileFolder, "config.yml");
					ConfigHandler.getConfig().softReload();
					SchedulerUtils.runLater(2L, () -> altCommandPane(player, itemMap, stage));
				} else {
					final List<String> toggleCommands = itemMap.getToggleCommands();
					toggleCommands.remove(command);
					itemMap.setToggleCommands(toggleCommands);
				}
				altCommandPane(player, itemMap, stage);
			}));
			modPane.addButton(new Button(fillerPaneGItem), 3);
			if (stage == 4) {
				modPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> altCommandPane(player, itemMap, stage)));
			} else {
				modPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the toggle commands menu."), event -> altCommandPane(player, itemMap, stage)));
			}
			modPane.addButton(new Button(fillerPaneBItem), 7);
			if (stage == 4) {
				modPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the active commands menu."), event -> altCommandPane(player, itemMap, stage)));
			} else {
				modPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the oggle commands menu."), event -> altCommandPane(player, itemMap, stage)));
			}
		});
		modPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the custom toggle commands.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void togglePane(final Player player, final ItemMap itemMap) {
		Interface togglePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			togglePane.addButton(new Button(fillerPaneBItem), 2);
			togglePane.addButton(new Button(ItemHandler.getItem("BOOK", 1, false, "&e&lCommands", "&7", "&7*Define specific commands which", "&7players can use to enable or disable", "&7the custom item upon execution."), event -> altCommandPane(player, itemMap, 0)));
			togglePane.addButton(new Button(fillerPaneBItem));
			togglePane.addButton(new Button(ItemHandler.getItem("PAPER", 1, (StringUtils.nullCheck(itemMap.getToggleMessage()) != "NONE"), "&b&lMessage", 
					"&7", "&7*Set a custom message that", "&7will be sent to the player", "&7upon executing a toggle command.", 
					"&9&lMESSAGE: &f" + StringUtils.nullCheck(itemMap.getToggleMessage())), event -> {
				if (StringUtils.nullCheck(itemMap.getToggleMessage()) != "NONE") {
					itemMap.setToggleMessage(null);
					togglePane(player, itemMap);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TOGGLE MESSAGE";
					placeHolders[15] = "&a%item% has been toggled!";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				itemMap.setToggleMessage(ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "TOGGLE MESSAGE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				togglePane(event.getPlayer(), itemMap);
			}));
			togglePane.addButton(new Button(fillerPaneBItem));
			togglePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, (StringUtils.nullCheck(itemMap.getToggleNode()) != "NONE"), 
					"&b&lPermissions", "&7", "&7*Set a custom permissions node", "&7that each player needs in order", 
					"&7to execute the toggle commands.", "&9&lPERMISSIONS: &f" + StringUtils.nullCheck(itemMap.getToggleNode())), event -> {
				if (StringUtils.nullCheck(itemMap.getToggleNode()) != "NONE") {
					itemMap.setTogglePerm(null);
					togglePane(player, itemMap);
				} else {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "TOGGLE PERMISSION";
					placeHolders[15] = "itemjoin.toggle";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}
			}, event -> {
				itemMap.setTogglePerm(ChatColor.stripColor(event.getMessage()));
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "TOGGLE PERMISSION";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				togglePane(event.getPlayer(), itemMap);
			}));
			togglePane.addButton(new Button(fillerPaneBItem), 2);
			togglePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			togglePane.addButton(new Button(fillerPaneBItem), 7);
			togglePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		togglePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the custom recipe.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void recipePane(final Player player, final ItemMap itemMap) {
		Interface recipePane = new Interface(false, 4, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			recipePane.addButton(new Button(fillerPaneBItem), 3);
			for (int i = 0; i < 9; i++) {
				final int k = i;
				String stack = "CHEST";
				ItemStack stack1 = null;
				if (itemMap.getRecipe().size() > i && itemMap.getRecipe().get(i) != 'X') {
					final ItemMap copyMap = ItemUtilities.getUtilities().getItemMap(null, itemMap.getIngredients().get(itemMap.getRecipe().get(i)).toString(), null);
					if (copyMap != null) { stack1 = copyMap.getItemStack(player); }
					else { stack = itemMap.getIngredients().get(itemMap.getRecipe().get(i)).toString(); }
				}
				if (stack1 != null) {
					stack1 = ItemHandler.addLore(stack1, "&9&lDISPLAY: &f" + stack1.getItemMeta().getDisplayName(), "&7", "&7*Create a recipe that can be used.");
					ItemMeta meta = stack1.getItemMeta();
					meta.setDisplayName(StringUtils.translateLayout((itemMap.getRecipe().size() > i ? "&e&l" + itemMap.getRecipe().get(i): "&e&lX"), player));
					stack1.setItemMeta(meta);
					
					recipePane.addButton(new Button(stack1, event -> {
						if ((itemMap.getRecipe().size() > k && itemMap.getRecipe().get(k) != 'X')) { setIngredients(player, itemMap, "AIR", k); } 
						else { ingredientPane(player, itemMap, k); }
					}));
					if (i == 2) {
						recipePane.addButton(new Button(fillerPaneBItem), 6);
					} else if (i == 5) {
						recipePane.addButton(new Button(fillerPaneBItem));
						recipePane.addButton(new Button(headerStack(player, itemMap)));
						recipePane.addButton(new Button(fillerPaneBItem), 4);
					} else if (i == 8) {
						recipePane.addButton(new Button(fillerPaneBItem), 3);
					}
				} else {
					recipePane.addButton(new Button(ItemHandler.getItem(stack, 1, false, 
							(itemMap.getRecipe().size() > i ? "&e&l" + itemMap.getRecipe().get(i): "&e&lX"), "&7", "&7*Create a recipe that can be used."), event -> {
						if ((itemMap.getRecipe().size() > k && itemMap.getRecipe().get(k) != 'X')) { setIngredients(player, itemMap, "AIR", k); } 
						else { ingredientPane(player, itemMap, k); }
					}));
					if (i == 2) {
						recipePane.addButton(new Button(fillerPaneBItem), 6);
					} else if (i == 5) {
						recipePane.addButton(new Button(fillerPaneBItem));
						recipePane.addButton(new Button(headerStack(player, itemMap)));
						recipePane.addButton(new Button(fillerPaneBItem), 4);
					} else if (i == 8) {
						recipePane.addButton(new Button(fillerPaneBItem), 3);
					}
				}
			}
			recipePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			recipePane.addButton(new Button(fillerPaneBItem), 7);
			recipePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		recipePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the custom recipe.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void ingredientPane(final Player player, final ItemMap itemMap, final int k) {
		Interface ingredientPane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			ingredientPane.addButton(new Button(fillerPaneBItem), 3);
			ingredientPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRASS_BLOCK" : "2"), 1, false, "&b&lMaterial", "&7", "&7*Select a material type", "&7to be defined in the recipe."), event -> materialPane(player, itemMap, 3, k)));
			ingredientPane.addButton(new Button(fillerPaneBItem));
			ingredientPane.addButton(new Button(ItemHandler.getItem("CHEST", 1, false, "&b&lCustom Item", "&7", "&7*Select a custom item", "&7to be defined in the recipe."), event -> startModify(player, itemMap, k)));
			ingredientPane.addButton(new Button(fillerPaneBItem), 3);
			ingredientPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the recipe menu."), event -> recipePane(player, itemMap)));
			ingredientPane.addButton(new Button(fillerPaneBItem), 7);
			ingredientPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the recipe menu."), event -> recipePane(player, itemMap)));
		});
		ingredientPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for creating NBT Properties.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void nbtPane(final Player player, final ItemMap itemMap) {
		Interface nbtPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			Map<String, String> properties = itemMap.getNBTValues();
			nbtPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
				nbtPane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, true, "&e&l&nNew Property", "&7", "&7*Add a new NBT Property to the custom item."), event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "NBT PROPERTY";
					placeHolders[15] = "TranslatableDisplayName:&aUltra &cItem";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					if (ChatColor.stripColor(event.getMessage()).contains(":")) {
						String[] propertyParts = ChatColor.stripColor(event.getMessage()).split(":");
						properties.put(propertyParts[0], propertyParts[1]);
					}
					itemMap.setNBTValues(properties);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "NBT PROPERTY";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					nbtPane(event.getPlayer(), itemMap);
				}));
				for (String key : properties.keySet()) {
					nbtPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "COMMAND_BLOCK" : "137"), 1, false, "&f" + key + ":" + properties.get(key), "&7", "&7*Click to modify or delete", "&7this custom NBT Property."), event -> modifyProperty(player, itemMap, key)));
				}
		});
		nbtPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying NBT Propterties.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifyProperty(final Player player, final ItemMap itemMap, final String key) {
		Interface modifyProperty = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			Map<String, String> properties = itemMap.getNBTValues();
			modifyProperty.addButton(new Button(fillerPaneGItem), 3);
			modifyProperty.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&c&l&nModify", "&7", "&7*Modify this NBT Property.", "&7", "&9&lProperty: &a" + "&f" + key + ":" + properties.get(key)), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NBT PROPERTY";
				placeHolders[15] = "TranslatableDisplayName:&aUltra &cItem";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (ChatColor.stripColor(event.getMessage()).contains(":")) {
					properties.remove(key);
					String[] propertyParts = ChatColor.stripColor(event.getMessage()).split(":");
					properties.put(propertyParts[0], propertyParts[1]);
				}
				itemMap.setNBTValues(properties);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "NBT PROPERTY";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				nbtPane(event.getPlayer(), itemMap);
			}));
			modifyProperty.addButton(new Button(fillerPaneGItem));
			modifyProperty.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this custom NBT Property.", "&7", "&9&lProperty: &a" + "&f" + key + ":" + properties.get(key)), event -> {
				properties.remove(key);
				itemMap.setNBTValues(properties);
				nbtPane(player, itemMap);
			}));
			modifyProperty.addButton(new Button(fillerPaneGItem), 3);
			modifyProperty.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the NBT Properties menu."), event -> nbtPane(player, itemMap)));
			modifyProperty.addButton(new Button(fillerPaneBItem), 7);
			modifyProperty.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the NBT Properties menu."), event -> nbtPane(player, itemMap)));
		});
		modifyProperty.open(player);
	}
	
   /**
    * Sets the recipe pattern and ingredients.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    * @param material - The material to be set.
    * @param position - The position in the crafting table being set.
    */
	private static void setIngredients(final Player player, final ItemMap itemMap, final String material, final int position) {
		Map<Character, String> ingredients = itemMap.getIngredients();
		List < Character > recipe = itemMap.getRecipe();
		char character = 'A';
		for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
			if (alphabet != 'X' && !ingredients.containsKey(alphabet)) {
				character = alphabet;
				break;
			}
		}
		for (Character characters: ingredients.keySet()) {
			if (ingredients.get(characters).equals(material)) {
				character = characters;
				break;
			}
		}
		if (!StringUtils.containsIgnoreCase(material, "AIR") && !ingredients.containsValue(material)) {
			ingredients.put(character, material);
		} else if (StringUtils.containsIgnoreCase(material, "AIR")) {
			int count = 0;
			for (Character recipes: recipe) {
				if (recipes.equals(recipe.get(position))) {
					count++;
				}
			}
			if (count == 1) {
				ingredients.remove(recipe.get(position));
			}
		}
		while (position >= recipe.size()) {
			recipe.add('X');
		}
		recipe.set(position, (!StringUtils.containsIgnoreCase(material, "AIR") ? character : 'X'));
		itemMap.setRecipe(recipe);
		itemMap.setIngredients(ingredients);
		recipePane(player, itemMap);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying banner items.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void bannerPane(final Player player, final ItemMap itemMap) {
		Interface bannerPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			bannerPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			for (PatternType pattern: PatternType.values()) {
				String patternString = "NONE";
				if (StringUtils.nullCheck(itemMap.getBannerPatterns().toString()) != "NONE") {
					for (Pattern patterns: itemMap.getBannerPatterns()) {
						if (patterns.getPattern() == pattern) {
							patternString = patterns.getColor() + ":" + patterns.getPattern().name().toUpperCase();
							break;
						}
					}
				}
				final String checkPattern = patternString;
				bannerPane.addButton(new Button(ItemHandler.getItem("PAPER", 1, (checkPattern != "NONE" ? true : false), "&f" + pattern.name(), "&7", "&7*Click to add this as", "&7a banner pattern.", (checkPattern != "NONE" ? 
						"&9&lInformation: &a" + checkPattern : "")), event -> {
					if (checkPattern != "NONE") {
						List < Pattern > patternList = itemMap.getBannerPatterns();
						if (StringUtils.nullCheck(itemMap.getBannerPatterns().toString()) != "NONE") {
							for (Pattern patterns: patternList) {
							if (patterns.getPattern() == pattern) {
									patternList.remove(patterns);
									itemMap.setBannerPatterns(patternList);
									break;
								}
							}
						}
						bannerPane(player, itemMap);
					} else {
						patternPane(player, itemMap, pattern);
					}
				}));
			}
		});
		bannerPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting the Banner Pattern.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void patternPane(final Player player, final ItemMap itemMap, final PatternType pattern) {
		Interface colorPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			colorPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the banner patterns menu."), event -> bannerPane(player, itemMap)));
			for (DyeColor color: DyeColor.values()) {
				colorPane.addButton(new Button(ItemHandler.getItem("GRAY_DYE", 1, false, "&f" + color.name(), "&7", "&7*This will be the color", "&7of your banner pattern."), event -> {
					List < Pattern > patterns = itemMap.getBannerPatterns();patterns.add(new Pattern(color, pattern));itemMap.setBannerPatterns(patterns);bannerPane(player, itemMap);
				}));
			}
		});
		colorPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting the Potion Type.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void potionPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface potionPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage != 1) {
				potionPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			} else {
				potionPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the other settings menu."), event -> otherPane(player, itemMap)));
			}
			for (PotionEffectType potion: PotionEffectType.values()) {
				if (potion != null) {
					String potionString = "NONE";
					if (StringUtils.nullCheck(itemMap.getPotionEffect().toString()) != "NONE") {
						for (PotionEffect potions: itemMap.getPotionEffect()) {
							if (potions.getType() == potion) {
								potionString = potions.getType().getName().toUpperCase() + ":" + potions.getAmplifier() + ":" + (potions.getDuration());
								break;
							}
						}
					}
					final String checkPotion = potionString;
					potionPane.addButton(new Button(ItemHandler.getItem("GLASS_BOTTLE", 1, (checkPotion != "NONE" ? true : false), "&f" + potion.getName(), "&7", "&7*Add this potion effect", "&7to the item.", 
							(checkPotion != "NONE" ? "&9&lInformation: &a" + checkPotion : "")), event -> {
						if (checkPotion != "NONE") {
							List < PotionEffect > potionEffects = itemMap.getPotionEffect();
							if (StringUtils.nullCheck(itemMap.getPotionEffect().toString()) != "NONE") {
								for (PotionEffect potions: potionEffects) {
									if (potions.getType() == potion) {
										potionEffects.remove(potions);
										itemMap.setPotionEffect(potionEffects);
										break;
									}
								}
							}
							potionPane(player, itemMap, stage);
						} else {
							levelPane(player, itemMap, potion, stage);
						}
					}));
				}
			}
		});
		potionPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting the Teleport Arrow.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void teleportPane(final Player player, final ItemMap itemMap, final int stage) {
		Interface teleportPane = new Interface(false, 1, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (stage == 1) {
				teleportPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the other settings menu."), event -> { 
					setItemFlags(itemMap);
					otherPane(player, itemMap); 
				}));
			} else {
				teleportPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> { 
					setItemFlags(itemMap);
					creatingPane(player, itemMap); 
				}));
			}
			teleportPane.addButton(new Button(fillerPaneGItem), 2);
			teleportPane.addButton(new Button(ItemHandler.getItem("BLAZE_POWDER", 1, false, "&b&lTeleport Effect", "&7", "&7*The effect to play at the", "&7arrow landed location when", "&7the player is teleported.", 
					"&9&lTeleport-Effect: &a" + StringUtils.nullCheck(itemMap.getTeleportEffect())), event -> {
				particlePane(player, itemMap, stage);
			}));
			teleportPane.addButton(new Button(ItemHandler.getItem("ENDER_PEARL", 1, itemMap.isTeleport(), "&a&l&nTeleport", "&7", 
					"&a&lTrue&f: &7Teleports the Player to the location", "&7that the arrow landed.", 
					"&cNOTE: &7This only works if the arrow is fired by a Bow.",
					"&9&lENABLED: &a" + String.valueOf(itemMap.isTeleport()).toUpperCase()), event -> {
				if (itemMap.isTeleport()) {
					itemMap.setTeleport(false);
				} else {
					itemMap.setTeleport(true);
				}
				teleportPane(player, itemMap, stage);
			}));
			teleportPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "MUSIC_DISC_MELLOHI" : "2262"), 1, false, "&a&lTeleport Sound", "&7", "&7*The sound to play at the", "&7arrow landed location when", "&7the player is teleported.", 
			"&9&lTeleport-Sound: &a" + StringUtils.nullCheck(itemMap.getTeleportSound()),
			"&9&lVolume: &a" + ((StringUtils.nullCheck(itemMap.getTeleportSound() + "") != "NONE") ? itemMap.getTeleportVolume() : "NONE"),
			"&9&lPitch: &a" + ((StringUtils.nullCheck(itemMap.getTeleportSound() + "") != "NONE") ? itemMap.getTeleportPitch() : "NONE")), event -> {
				soundPane(player, itemMap, stage);
				if (StringUtils.nullCheck(itemMap.getTeleportSound() + "") != "NONE") {
					itemMap.setTeleportSound(null);
					teleportPane(player, itemMap, stage);
				} else {
					soundPane(player, itemMap, stage);
				}
			}));
			teleportPane.addButton(new Button(fillerPaneGItem), 2);
			if (stage == 1) {
				teleportPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the other settings menu."), event -> { 
					setItemFlags(itemMap);
					otherPane(player, itemMap); 
				}));
			} else {
				teleportPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> { 
					setItemFlags(itemMap);
					creatingPane(player, itemMap); 
				}));
			}
		});
		teleportPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the Potion Level.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void levelPane(final Player player, final ItemMap itemMap, final PotionEffectType potion, final int stage) {
		Interface levelPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			levelPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the potion effect menu."), event -> potionPane(player, itemMap, stage)));
			levelPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Level", "&7", "&7*Click to set a custom level (strength)", "&7value for the potion effect.", "&7", "&c&lNote: &7Any duration LONGER than", "&71800 seconds (30 minutes) will", "&7result in an infinite duration."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "EFFECT LEVEL";
				placeHolders[15] = "16";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "EFFECT LEVEL";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					durationPane(event.getPlayer(), itemMap, potion, Integer.parseInt(ChatColor.stripColor(event.getMessage())), stage);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					levelPane(event.getPlayer(), itemMap, potion, stage);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				levelPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:6"), k, false, "&d&lLevel: &a&l" + k + "", "&7", "&7*Click to set the", "&7level (strength) of the potion effect."), event -> {
					itemMap.setInteractCooldown(k);durationPane(player, itemMap, potion, k, stage);
				}));
			}
		});
		levelPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for setting the Potion Duration.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void durationPane(final Player player, final ItemMap itemMap, final PotionEffectType potion, int level, final int stage) {
		Interface durationPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			durationPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the potion effect menu."), event -> potionPane(player, itemMap, stage)));
			durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Duration", "&7", "&7*Click to set a custom duration", "&7value for the potion effect."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "EFFECT DURATION";
				placeHolders[15] = "110";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "EFFECT DURATION";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					potionPane(event.getPlayer(), itemMap, stage);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
					durationPane(event.getPlayer(), itemMap, potion, level, stage);
				}
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				durationPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lDuration: &a&l" + k + " Second(s)", "&7", "&7*Click to set the", "&7duration of the potion effect."), event -> {
					List < PotionEffect > effects = itemMap.getPotionEffect();
					effects.add(new PotionEffect(potion, k, level));
					itemMap.setPotionEffect(effects);potionPane(player, itemMap, stage);
				}));
			}
		});
		durationPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting the Firework Power.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void powerPane(final Player player, final ItemMap itemMap) {
		Interface powerPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			powerPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the special settings menu."), event -> otherPane(player, itemMap)));
			powerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Power", "&7", "&7*Click to set a custom power", "&7value for the firework."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "FIREWORK POWER";
				placeHolders[15] = "96";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage()))) {
					itemMap.setFireworkPower(Integer.parseInt(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "FIREWORK POWER";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				otherPane(player, itemMap);
			}));
			for (int i = 1; i <= 64; i++) {
				final int k = i;
				powerPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "BLUE_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:11"), k, false, "&9&lPower Level: &a&l" + k, "&7", "&7*Click to set the", "&7power level of the firework."), event -> {
					itemMap.setFireworkPower(k);
					otherPane(player, itemMap);
				}));
			}
		});
		powerPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting a Firework Color.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void colorPane(final Player player, final ItemMap itemMap) {
		Interface colorPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			colorPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the special settings menu."), event -> otherPane(player, itemMap)));
			for (DyeColor color: DyeColor.values()) {
				colorPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRAY_DYE" : "351:8"), 1, StringUtils.containsValue(itemMap.getFireworkColor(), color.name()), "&f" + color.name(), 
						"&7", "&7*This will be the color", "&7of your firework charge.", "&9&lENABLED: &a" + (StringUtils.containsValue(itemMap.getFireworkColor(), color.name()) + "").toUpperCase()), event -> {
					List < DyeColor > colors = itemMap.getFireworkColor();
					if (StringUtils.containsIgnoreCase(itemMap.getFireworkColor().toString(), color.name())) {
						colors.remove(color);
					} else {
						colors.add(color);
						itemMap.setFireworkColor(colors);
					}
					colorPane(player, itemMap);
				}));
			}
		});
		colorPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for selecting a Firework Type.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void designPane(final Player player, final ItemMap itemMap) {
		Interface designPane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			designPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the special settings menu."), event -> otherPane(player, itemMap)));
			for (Type type: Type.values()) {
				designPane.addButton(new Button(ItemHandler.getItem("EGG", 1, false, "&f" + type.name(), "&7", "&7*This will be the type (pattern)", "&7of your firework."), event -> {
					itemMap.setFireworkType(type);
					otherPane(player, itemMap);
				}));
			}
		});
		designPane.open(player);
	}
	
//  ============================================== //
//                Book Pages Menus      	       //
//  ============================================== //
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying book items.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void pagePane(final Player player, final ItemMap itemMap) {
		Interface pagePane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			pagePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the special settings menu."), event -> {
				otherPane(player, itemMap);
			}));
			pagePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&e&l&nNew Page", "&7", "&7*Add a new page to the book."), event -> linePane(player, itemMap, true, itemMap.getListPages().size())));
			for (int i = 1; i <= itemMap.getListPages().size(); i++) {
				final int k = i;
				pagePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&b&lPage " + i, "&7", "&7*Click to modify the contents", "&7of this book page."), event -> linePane(player, itemMap, false, k - 1)));
			}
		});
		pagePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying book page lines.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void linePane(final Player player, final ItemMap itemMap, final boolean isNew, final int page) {
		Interface linePane = new Interface(true, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			List < List < String > > pages = itemMap.getListPages();
			linePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the book pages menu."), event -> pagePane(player, itemMap)));
			if (isNew) {
				linePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&e&l&nNew Line", "&7", "&7*Add a new line to the book page.", "&7", "&9&lPage: &a" + (page + 1)), event -> {
					player.closeInventory();
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "PAGE LINE";
					placeHolders[15] = "&eWelcome to the Server!";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
				}, event -> {
					List < String > newPage = new ArrayList < String > ();
					newPage.add(ChatColor.stripColor(event.getMessage()));pages.add(newPage);
					itemMap.setListPages(pages);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "PAGE LINE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					linePane(event.getPlayer(), itemMap, false, page);
				}));
			} else {
				List < String > selectPage = pages.get(page);
				linePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this page from the book.", "&7", "&9&lPage: &a" + (page + 1)), event -> {
					pages.remove(page);
					itemMap.setListPages(pages);
					pagePane(player, itemMap);
				}));
				if (selectPage.size() < 14) {
					linePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, true, "&e&l&nNew Line", "&7", "&7*Add a new line to the book page.", "&7", "&9&lLine: &a" + (selectPage.size() + 1) + "    &9&lPage: &a" + (page + 1)), event -> {
						player.closeInventory();
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "PAGE LINE";
						placeHolders[15] = "&eWelcome to the Server!";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
					}, event -> {
						selectPage.add(ChatColor.stripColor(event.getMessage()));
						pages.set(page, selectPage);
						itemMap.setListPages(pages);
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "PAGE LINE";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
						linePane(event.getPlayer(), itemMap, false, page);
					}));
				}
				for (int i = 1; i <= selectPage.size(); i++) {
					final int k = i;
					linePane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&f" + selectPage.get(k - 1), "&7", "&7*Click to modify or delete", "&7this line in the book page.", "&7", "&9&lLine: &a" + k + 
							"    &9&lPage: &a" + (page + 1)), event -> modifyPagesPane(player, itemMap, k - 1, page)));
				}
			}
		});
		linePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying book pages.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void modifyPagesPane(final Player player, final ItemMap itemMap, final int line, final int page) {
		Interface linePane = new Interface(false, 2, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			List < List < String > > pages = itemMap.getListPages();
			List < String > selectPage = pages.get(page);
			linePane.addButton(new Button(fillerPaneGItem), 3);
			linePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, false, "&c&l&nModify", "&7", "&7*Modify this line in the page.", "&7", "&9&lLine: &a" + (line + 1) + "    &9&lPage: &a" + (page + 1)), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "PAGE LINE";
				placeHolders[15] = "&eWelcome to the Server!";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				selectPage.set(line, ChatColor.stripColor(event.getMessage()));
				pages.set(page, selectPage);
				itemMap.setListPages(pages);
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "PAGE LINE";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				linePane(event.getPlayer(), itemMap, false, page);
			}));
			linePane.addButton(new Button(fillerPaneGItem));
			linePane.addButton(new Button(ItemHandler.getItem("REDSTONE", 1, false, "&c&l&nDelete", "&7", "&7*Delete this line in the page.", "&7", "&9&lLine: &a" + (line + 1) + "    &9&lPage: &a" + (page + 1)), event -> {
				selectPage.remove(selectPage.get(line));
				pages.set(page, selectPage);
				itemMap.setListPages(pages);
				linePane(player, itemMap, false, page);
			}));
			linePane.addButton(new Button(fillerPaneGItem), 3);
			linePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the book lines menu."), event -> linePane(player, itemMap, false, page)));
			linePane.addButton(new Button(fillerPaneBItem), 7);
			linePane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the book lines menu."), event -> linePane(player, itemMap, false, page)));
		});
		linePane.open(player);
	}
	
//  ==========================================================================================================================================================================================================================================================
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying item attributes.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void attributePane(final Player player, final ItemMap itemMap, final boolean isLeather) {
		Interface attributePane = new Interface(true, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			if (isLeather) {
				attributePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the other settings menu."), event -> otherPane(player, itemMap)));
			} else {
				attributePane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			}
			if (ServerUtils.hasSpecificUpdate("1_9")) {
				for (Attribute attribute: Attribute.values()) {
					String checkAttribute = (itemMap.getAttributes().containsKey(attribute.name()) ? (attribute.name() + ":" + itemMap.getAttributes().get(attribute.name())) : "NONE");
					attributePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, itemMap.getAttributes().containsKey(attribute.name()), "&f" + attribute.name(), "&7", "&7*Add this custom attribute to the item.", 
									(checkAttribute != "NONE" ? "&9&lInformation: &a" + checkAttribute : "")), event -> { 
						if (itemMap.getAttributes().containsKey(attribute.name())) {
							Map<String, Double> attributeList = itemMap.getAttributes();
							attributeList.remove(attribute.name());
							attributePane(player, itemMap, isLeather); 
						} else {
							strengthPane(player, itemMap, attribute.name(), isLeather); 
						}
					}));
				}
			} else {
				String[] attributes = new String[] { "GENERIC_ATTACK_DAMAGE", "GENERIC_FOLLOW_RANGE", "GENERIC_MAX_HEALTH", "GENERIC_MOVEMENT_SPEED" };
				for (String attribute: attributes) {
					String checkAttribute = (itemMap.getAttributes().containsKey(attribute) ? (attribute + ":" + itemMap.getAttributes().get(attribute)) : "NONE");
					attributePane.addButton(new Button(ItemHandler.getItem("NAME_TAG", 1, itemMap.getAttributes().containsKey(attribute), "&f" + attribute, "&7", "&7*Add this custom attribute to the item.", 
									(checkAttribute != "NONE" ? "&9&lInformation: &a" + checkAttribute : "")), event -> { 
						if (itemMap.getAttributes().containsKey(attribute)) {
							Map<String, Double> attributeList = itemMap.getAttributes();
							attributeList.remove(attribute);
							attributePane(player, itemMap, isLeather); 
						} else {
							strengthPane(player, itemMap, attribute, isLeather); 
						}
					}));
				}
			}
		});
		attributePane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying item attributes strength.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void strengthPane(final Player player, final ItemMap itemMap, final String attribute, final boolean isLeather) {
		Interface strengthPane = new Interface(true, 6, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			strengthPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the custom attributes menu."), event -> attributePane(player, itemMap, isLeather)));
			strengthPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:4"), 1, false, "&e&lCustom Strength", "&7", "&7*Click to set a custom strength", "&7value for the custom attribute."), event -> {
				player.closeInventory();
				String[] placeHolders = LanguageAPI.getLang(false).newString();
				placeHolders[16] = "STRENGTH";
				placeHolders[15] = "14.0";
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
				LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
			}, event -> {
				if (StringUtils.isInt(ChatColor.stripColor(event.getMessage())) || StringUtils.isDouble(ChatColor.stripColor(event.getMessage()))) {
					Map<String, Double> attributeList = itemMap.getAttributes();
					attributeList.put(attribute, Double.parseDouble(ChatColor.stripColor(event.getMessage())));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "STRENGTH";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
				} else {
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = ChatColor.stripColor(event.getMessage());
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.noInteger", player, placeHolders);
				}
				attributePane(event.getPlayer(), itemMap, isLeather);
			}));
			for (double i = 1; i < 90; i++) {
				final double k = i;
				strengthPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "PINK_STAINED_GLASS_PANE" : "STAINED_GLASS_PANE:6"), 1, false, "&9&lStrength: &a&l" + k, "&7", "&7*Click to set the strength", "&7 of the custom attribute."), event -> { 
					Map<String, Double> attributeList = itemMap.getAttributes();
					attributeList.put(attribute, k);
					attributePane(player, itemMap, isLeather); 
				}));
			}
		});
		strengthPane.open(player);
	}
	
   /**
    * Opens the Pane for the Player.
    * This Pane is for modifying special items.
    * 
    * @param player - The Player to have the Pane opened.
    * @param itemMap - The ItemMap currently being modified.
    */
	private static void otherPane(final Player player, final ItemMap itemMap) {
		Interface otherPane = new Interface(false, 3, GUIName, player);
		SchedulerUtils.runAsync(() -> {
			otherPane.addButton(new Button(fillerPaneGItem), 4);
			otherPane.addButton(new Button(headerStack(player, itemMap)));
			otherPane.addButton(new Button(fillerPaneGItem), 4);
			if (itemMap.getMaterial().toString().contains("WRITTEN_BOOK")) {
				otherPane.addButton(new Button(fillerPaneGItem), 3);
				otherPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, false, "&e&lPages", "&7", "&7*Define custom pages for the book.", 
						"&9&lPages: &a" + (StringUtils.nullCheck(itemMap.getPages() + "") != "NONE" ? "YES" : "NONE")), event -> pagePane(player, itemMap)));
				otherPane.addButton(new Button(fillerPaneGItem));
				otherPane.addButton(new Button(ItemHandler.getItem("FEATHER", 1, false, "&a&lAuthor", "&7", "&7*Define the author of the book.", "&9&lAuthor: &a" + StringUtils.nullCheck(itemMap.getAuthor())), event -> {
					if (StringUtils.nullCheck(itemMap.getAuthor()) != "NONE") {
						itemMap.setAuthor(null);
						otherPane(player, itemMap);
					} else {
						player.closeInventory();
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "AUTHOR";
						placeHolders[15] = "RockinChaos";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
					}
				}, event -> {
					itemMap.setAuthor(ChatColor.stripColor(event.getMessage()));
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "AUTHOR";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					otherPane(event.getPlayer(), itemMap);
				}));
				otherPane.addButton(new Button(fillerPaneGItem), 3);
			} else if (itemMap.getMaterial().toString().contains("PLAYER_HEAD") || itemMap.getMaterial().toString().contains("SKULL_ITEM")) {
				String potionList = "";
				String potionString = "";
				if (StringUtils.nullCheck(itemMap.getPotionEffect().toString()) != "NONE") {
					for (PotionEffect potions: itemMap.getPotionEffect()) {
						potionString += potions.getType().getName().toUpperCase() + ":" + potions.getAmplifier() + ":" + potions.getDuration() + ", ";
					}
					for (String split: StringUtils.softSplit(StringUtils.nullCheck(potionString.substring(0, potionString.length())))) {
						potionList += "&a" + split + " /n ";
					}
				}
				otherPane.addButton(new Button(fillerPaneGItem), 2);
				otherPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GOLDEN_HELMET" : "314"), 1, false, "&b&lSkull Owner", "&7", "&7*Define a skull owner for the", "&7head adding that persons skin.", "&7", "&7You can only define skull owner", 
						"&7or skull texture, this will", "&7remove any skull textures.", "&9&lSkull-Owner: &a" + StringUtils.nullCheck(itemMap.getSkull())), event -> {
					if (itemMap.getDynamicOwners() != null && !itemMap.getDynamicOwners().isEmpty()) {
						animatedSkullPane(player, itemMap, true);
					} else {
						if (StringUtils.nullCheck(itemMap.getSkull()) != "NONE") {
							itemMap.setSkull(null);
							otherPane(player, itemMap);
						} else {
							player.closeInventory();
							String[] placeHolders = LanguageAPI.getLang(false).newString();
							placeHolders[16] = "SKULL OWNER";
							placeHolders[15] = "RockinChaos";
							LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
							LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
						}
					}
				}, event -> {
					itemMap.setSkull(ChatColor.stripColor(event.getMessage()));
					itemMap.setSkullTexture(null);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL OWNER";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					otherPane(event.getPlayer(), itemMap);
				}));
				otherPane.addButton(new Button(fillerPaneGItem));
				otherPane.addButton(new Button(ItemHandler.getItem("STRING", 1, false, "&a&lSkull Texture", "&7", "&7*Add a skull texture for the", "&7head as a custom skin.", "&7", "&7You can only define skull texture", 
						"&7or skull owner, this will", "&7remove any skull owners.", "&7", "&7Skull textures can be found", "&7at websites like &aminecraft-heads.com", "&7and the value is listed under", "&7the OTHER section.", "&9&lSkull-Texture: &a" + 
				(StringUtils.nullCheck(itemMap.getSkullTexture()) != "NONE" ? (itemMap.getSkullTexture().length() > 40 ? itemMap.getSkullTexture().substring(0, 40) : itemMap.getSkullTexture()) : "")), event -> {
					if (itemMap.getDynamicTextures() != null && !itemMap.getDynamicTextures().isEmpty()) {
						animatedSkullPane(player, itemMap, false);
						} else {
						if (StringUtils.nullCheck(itemMap.getSkullTexture()) != "NONE") {
							itemMap.setSkullTexture(null);
							otherPane(player, itemMap);
						} else {
							player.closeInventory();
							String[] placeHolders = LanguageAPI.getLang(false).newString();
							placeHolders[16] = "SKULL TEXTURE";
							placeHolders[15] = "eyJ0ZXh0dYMGQVlN2FjZmU3OSJ9fX0=";
							LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
							LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
						}
					}
				}, event -> {
					itemMap.setSkullTexture(ChatColor.stripColor(event.getMessage()));
					itemMap.setSkull(null);
					String[] placeHolders = LanguageAPI.getLang(false).newString();
					placeHolders[16] = "SKULL TEXTURE";
					LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
					otherPane(event.getPlayer(), itemMap);
				}));
				otherPane.addButton(new Button(fillerPaneGItem));
				otherPane.addButton(new Button(ItemHandler.getItem("POTION", 1, false, "&e&lEffects", "&7", "&7*Add custom effects after", "&7consuming the item.", "&9&lPotion-Effects: &a" + StringUtils.nullCheck(potionList)),
						event -> potionPane(player, itemMap, 1)));
				otherPane.addButton(new Button(fillerPaneGItem), 2);
			} else if (itemMap.getMaterial().toString().contains("TIPPED_ARROW")) {
				String potionList = "";
				String potionString = "";
				if (StringUtils.nullCheck(itemMap.getPotionEffect().toString()) != "NONE") {
					for (PotionEffect potions: itemMap.getPotionEffect()) {
						potionString += potions.getType().getName().toUpperCase() + ":" + potions.getAmplifier() + ":" + potions.getDuration() + ", ";
					}
					for (String split: StringUtils.softSplit(StringUtils.nullCheck(potionString.substring(0, potionString.length())))) {
						potionList += "&a" + split + " /n ";
					}
				}
				otherPane.addButton(new Button(fillerPaneGItem), 3);
				otherPane.addButton(new Button(ItemHandler.getItem("BLAZE_POWDER", 1, false, "&e&lEffects", "&7", "&7*Add custom effects", "&7to the arrow tip.", "&9&lTipped-Effect: &a" + StringUtils.nullCheck(potionList)),
						event -> potionPane(player, itemMap, 1)));
				otherPane.addButton(new Button(fillerPaneGItem));
				otherPane.addButton(new Button(ItemHandler.getItem("ENDER_PEARL", 1, false, "&e&lTeleport", "&7", "&7*Set the arrow to teleport", "&7the player upon landing.", "&9&lEnabled: &a" + String.valueOf(itemMap.isTeleport()).toUpperCase()),
						event -> teleportPane(player, itemMap, 1)));
				otherPane.addButton(new Button(fillerPaneGItem), 3);
			} else if (itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK") || itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK_ROCKET")) {
				String colorList = "";
				if (StringUtils.nullCheck(itemMap.getFireworkColor().toString()) != "NONE") {
					for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getFireworkColor().toString()))) {
						colorList += "&a" + split + " /n ";
					}
				}
				otherPane.addButton(new Button(fillerPaneGItem), 2);
				otherPane.addButton(new Button(ItemHandler.getItem("EGG", 1, false, "&a&lType", "&7", "&7*Set the style of the explosion.", "&9&lType: &a" + StringUtils.nullCheck(itemMap.getFireworkType() + "")), event -> {
					if (StringUtils.nullCheck(itemMap.getFireworkType() + "") != "NONE") {
						itemMap.setFireworkType(null);
						otherPane(player, itemMap);
					} else {
						designPane(player, itemMap);
					}
				}));
				otherPane.addButton(new Button(ItemHandler.getItem("DIAMOND", 1, itemMap.getFireworkFlicker(), "&a&lFlicker", "&7", "&7*Show the flicker effect as", "&7the firework particles dissipate", "&7after the explosion.", 
						"&9&lENABLED: &a" + itemMap.getFireworkFlicker()), event -> {
					if (itemMap.getFireworkFlicker()) {
						itemMap.setFireworkFlicker(false);
					} else {
						itemMap.setFireworkFlicker(true);
					}
					otherPane(player, itemMap);
				}));
				otherPane.addButton(new Button(ItemHandler.getItem("EMERALD", 1, itemMap.getFireworkTrail(), "&a&lTrail", "&7", "&7*Show the trail (smoke) of", "&7the firework when launched.", "&9&lENABLED: &a" + itemMap.getFireworkTrail()), event -> {
					if (itemMap.getFireworkTrail()) {
						itemMap.setFireworkTrail(false);
					} else {
						itemMap.setFireworkTrail(true);
					}
					otherPane(player, itemMap);
				}));
				otherPane.addButton(new Button(ItemHandler.getItem("SUGAR", 1, false, "&a&lPower", "&7", "&7*Set the power (distance)", "&7that the firework travels.", "&9&lPower: &a" + StringUtils.nullCheck(itemMap.getFireworkPower() + "&7")), event -> {
					if (StringUtils.nullCheck(itemMap.getFireworkPower() + "&7") != "NONE") {
						itemMap.setFireworkPower(0);
						otherPane(player, itemMap);
					} else {
						powerPane(player, itemMap);
					}
				}));
				otherPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "LIME_DYE" : "351:10"), 1, false, "&a&lColor(s)", "&7", "&7*Define the individual colors of the", "&7firework effect type.", 
						"&9&lColor(s): &a" + (StringUtils.nullCheck(colorList) != "NONE" ? colorList : "NONE")), event -> colorPane(player, itemMap)));
				otherPane.addButton(new Button(fillerPaneGItem), 2);
			} else if (itemMap.getMaterial().toString().contains("LEATHER_")) {
				Interface colorPane = new Interface(true, 6, GUIName, player);
				colorPane.setReturnButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the special settings menu."), event -> otherPane(player, itemMap)));
				for (DyeColor color: DyeColor.values()) {
					colorPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "GRAY_DYE" : "351:8"), 1, false, "&f" + color.name(), "&7", "&7*This will be the color", "&7of your leather armor."), event -> {
						itemMap.setLeatherColor(color.name());itemMap.setLeatherHex(null);otherPane(player, itemMap);
					}));
				}
				otherPane.addButton(new Button(fillerPaneGItem), 3);
				otherPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "YELLOW_DYE" : "351:11"), 1, false, "&a&lDye", "&7", "&7*Add a custom color to", "&7your leather armor.", "&9&lLeather-Color: &a" +
				(StringUtils.nullCheck(itemMap.getLeatherColor()) != "NONE" ? StringUtils.nullCheck(itemMap.getLeatherColor()) : StringUtils.nullCheck(itemMap.getLeatherHex()))), event -> {
					if (itemMap.getLeatherColor() != null) {
						itemMap.setLeatherColor(null);
						otherPane(player, itemMap);
					} else {
						colorPane.open(player);
					}
				}));
				if (!ItemHandler.getDesignatedSlot(itemMap.getMaterial()).equalsIgnoreCase("noslot")) {
					String attributeList = "";
					String attributeString = "";
					if (StringUtils.nullCheck(itemMap.getAttributes().toString()) != "NONE") {
						for (String attribute: itemMap.getAttributes().keySet()) {
							attributeString += attribute + ":" + itemMap.getAttributes().get(attribute) + ", ";
						}
						for (String split: StringUtils.softSplit(StringUtils.nullCheck(attributeString.substring(0, attributeString.length())))) {
							attributeList += "&a" + split + " /n ";
						}
					}
					otherPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "ENCHANTED_GOLDEN_APPLE" : "322:1"), 1, false, "&a&lAttributes", "&7", "&7*Add a custom attribute to", "&7your armor or weapon.", (StringUtils.nullCheck(attributeList) != "NONE" ? "&9&lAttributes: &a" + attributeList : "")), event -> {
						attributePane(player, itemMap, true);
					}));
				} else { otherPane.addButton(new Button(fillerPaneGItem)); }
				otherPane.addButton(new Button(ItemHandler.getItem((ServerUtils.hasSpecificUpdate("1_13") ? "WRITABLE_BOOK" : "386"), 1, false, "&a&lHex Color", "&7", "&7*Add a custom hex color", "&7to your leather armor.", "&9&lLeather-Color: &a" + 
				(StringUtils.nullCheck(itemMap.getLeatherHex()) != "NONE" ? StringUtils.nullCheck(itemMap.getLeatherHex()) : StringUtils.nullCheck(itemMap.getLeatherColor()))), event -> {
					if (itemMap.getLeatherHex() != null) {
						itemMap.setLeatherHex(null);
						otherPane(player, itemMap);
					} else {
						player.closeInventory();
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "HEX COLOR";
						placeHolders[15] = "#033dfc";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputType", player, placeHolders);
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputExample", player, placeHolders);
					}
				}, event -> {
					if (itemMap.getLeatherHex() == null) {
						itemMap.setLeatherHex(ChatColor.stripColor(event.getMessage()));
						itemMap.setLeatherColor(null);
						String[] placeHolders = LanguageAPI.getLang(false).newString();
						placeHolders[16] = "HEX COLOR";
						LanguageAPI.getLang(false).sendLangMessage("commands.menu.inputSet", player, placeHolders);
						otherPane(event.getPlayer(), itemMap);
					}
				}));
				otherPane.addButton(new Button(fillerPaneGItem), 3);
			}	
			otherPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
			otherPane.addButton(new Button(fillerPaneBItem), 7);
			otherPane.addButton(new Button(ItemHandler.getItem("BARRIER", 1, false, "&c&l&nReturn", "&7", "&7*Returns you to the item definition menu."), event -> creatingPane(player, itemMap)));
		});
		otherPane.open(player);
	}
	
   /**
    * Gets the Header ItemStack.
    * 
    * @param player - The player getting the Header Stack.
    * @param itemMap - The ItemMap to be formatted.
    * @return The formatted Header ItemStack.
    */
	private static ItemStack headerStack(final Player player, final ItemMap itemMap) {
		String slotList = "";
		String slotString = "";
		ItemStack item = new ItemStack(Material.STONE);
		if (StringUtils.nullCheck(itemMap.getMultipleSlots().toString()) != "NONE") {
			for (String slot: itemMap.getMultipleSlots()) {
				slotString += slot + ", ";
			}
			if (slotString.length() >= 2) {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(slotString.substring(0, slotString.length() - 2)))) {
					slotList += "&a" + split + " /n ";
				}
			}
		}
		String itemflagsList = "";
		if (StringUtils.nullCheck(itemMap.getItemFlags()) != "NONE") {
			for (String split: StringUtils.softSplit(itemMap.getItemFlags())) {
				itemflagsList += "&a" + split + " /n ";
			}
		}
		String triggersList = "";
		if (StringUtils.nullCheck(itemMap.getTriggers()) != "NONE") {
			for (String split: StringUtils.softSplit(itemMap.getTriggers())) {
				triggersList += "&a" + split + " /n ";
			}
		}
		String disabledList = "";
		if (StringUtils.nullCheck(itemMap.getDisabledWorlds().toString()) != "NONE") {
			for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getDisabledWorlds().toString()))) {
				disabledList += "&a" + split + " /n ";
			}
		}
		String enabledList = "";
		if (StringUtils.nullCheck(itemMap.getEnabledWorlds().toString()) != "NONE") {
			for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getEnabledWorlds().toString()))) {
				enabledList += "&a" + split + " /n ";
			}
		}
		String regionList = "";
		if (StringUtils.nullCheck(itemMap.getEnabledRegions().toString()) != "NONE") {
			for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getEnabledRegions().toString()))) {
				regionList += "&a" + split + " /n ";
			}
		}
		String enchantList = "";
		if (StringUtils.nullCheck(itemMap.getEnchantments().toString()) != "NONE") {
			for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getEnchantments().toString()))) {
				enchantList += "&a" + split + " /n ";
			}
		}
		String potionList = "";
		String potionString = "";
		if (StringUtils.nullCheck(itemMap.getPotionEffect().toString()) != "NONE") {
			for (PotionEffect potions: itemMap.getPotionEffect()) {
				potionString += potions.getType().getName().toUpperCase() + ":" + potions.getAmplifier() + ":" + potions.getDuration() + ", ";
			}
			if (potionString.length() >= 2) {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(potionString.substring(0, potionString.length() - 2)))) {
					potionList += "&a" + split + " /n ";
				}
			}
		}
		String attributeList = "";
		String attributeString = "";
		if (StringUtils.nullCheck(itemMap.getAttributes().toString()) != "NONE") {
			for (String attribute: itemMap.getAttributes().keySet()) {
				attributeString += attribute + ":" + itemMap.getAttributes().get(attribute) + ", ";
			}
			for (String split: StringUtils.softSplit(StringUtils.nullCheck(attributeString.substring(0, attributeString.length())))) {
				attributeList += "&a" + split + " /n ";
			}
		}
		String patternList = "";
		String patternString = "";
		if (ServerUtils.hasSpecificUpdate("1_8") && StringUtils.nullCheck(itemMap.getBannerPatterns().toString()) != "NONE") {
			for (Pattern patterns: itemMap.getBannerPatterns()) {
				patternString += patterns.getColor() + ":" + patterns.getPattern().name().toUpperCase() + ", ";
			}
			if (patternString.length() >= 2) {
				for (String split: StringUtils.softSplit(StringUtils.nullCheck(patternString.substring(0, patternString.length() - 2)))) {
					patternList += "&a" + split + " /n ";
				}
			}
		}
		String colorList = "";
		if (StringUtils.nullCheck(itemMap.getFireworkColor().toString()) != "NONE") {
			for (String split: StringUtils.softSplit(StringUtils.nullCheck(itemMap.getFireworkColor().toString()))) {
				colorList += "&a" + split + " /n ";
			}
		}
		boolean useCommands = true;
		if (itemMap.getCommands().length == 1) {
			for (ItemCommand command : itemMap.getCommands()) {
				if (command.getRawCommand().equalsIgnoreCase("default: ")) {
					useCommands = false;
				}
			}
		} else if (itemMap.getCommands().length == 0) { useCommands = false; }
		boolean useToggle = itemMap.getToggleCommands() != null && !itemMap.getToggleCommands().isEmpty();
		String mobs = "";
		for (EntityType entity: itemMap.getMobsDrop().keySet()) { mobs += entity.name() + ", "; }
		String blocks = "";
		for (Material material: itemMap.getBlocksDrop().keySet()) { blocks += material.name() + ", "; }
		try {
			item = ItemHandler.getItem(itemMap.getMaterial().toString() + ((itemMap.getDataValue() != null && itemMap.getDataValue() != 0) ? ":" + itemMap.getDataValue() : ""), 1, false, "&7*&6&l&nItem Information", "&7", "&9&lNode: &a" + itemMap.getConfigName(), "&9&lMaterial: &a" 
			+ itemMap.getMaterial().toString() + ((itemMap.getDataValue() != null && itemMap.getDataValue() != 0) ? ":" + itemMap.getDataValue() : ""), 
					(itemMap.getMultipleSlots() != null && !itemMap.getMultipleSlots().isEmpty() ? "&9&lSlot(s): &a" + slotList : "&9&lSlot: &a" + itemMap.getSlot().toUpperCase()), (itemMap.getCount() != 1 && itemMap.getCount() != 0) ? "&9&lCount: &a" + itemMap.getCount() : "", 
					((StringUtils.nullCheck(itemMap.getCustomName()) != "NONE" && !ItemHandler.getMaterialName(itemMap.getTempItem()).equalsIgnoreCase(itemMap.getCustomName())) ? "&9&lName: &a" + itemMap.getCustomName() : ""), (StringUtils.nullCheck(itemMap.getCustomLore().toString()) != "NONE" ? "&9&lLore: &a" + (StringUtils.nullCheck(itemMap.getCustomLore().toString()).replace(",,", ",").replace(", ,", ",").length() > 40 ? StringUtils.nullCheck(itemMap.getCustomLore().toString()).replace(",,", ",").replace(", ,", ",").substring(0, 40) : StringUtils.nullCheck(itemMap.getCustomLore().toString()).replace(",,", ",").replace(", ,", ",")) : ""), 
					(StringUtils.nullCheck(itemMap.getDurability() + "&7") != "NONE" ? "&9&lDurability: &a" + itemMap.getDurability() : ""), (StringUtils.nullCheck(itemMap.getData() + "&7") != "NONE" ? "&9&lTexture Data: &a" + itemMap.getData() : ""), (useCommands ? "&9&lCommands: &aYES" : ""), (useToggle ? "&9&lTogglable: &aYES" : ""),
					(StringUtils.nullCheck(itemMap.getItemCost() + "") != "NONE" ? "&9&lCommands-Item: &a" + itemMap.getItemCost() : ""), (StringUtils.nullCheck(itemMap.getCommandCost() + "&7") != "NONE" ? "&9&lCommands-Cost: &a" + itemMap.getCommandCost() : ""), 
					(StringUtils.nullCheck(itemMap.getCommandReceive() + "&7") != "NONE" ? "&9&lCommands-Receive: &a" + itemMap.getCommandReceive() : ""),
					(StringUtils.nullCheck(itemMap.getCommandSequence() + "") != "NONE" ? "&9&lCommands-Sequence: &a" + itemMap.getCommandSequence() : ""), (StringUtils.nullCheck(itemMap.getCommandCooldown() + "&7") != "NONE" ? "&9&lCommands-Cooldown: &a" + itemMap.getCommandCooldown() + " second(s)" : ""), 
					(StringUtils.nullCheck(itemMap.getCooldownMessage()) != "NONE" ? "&9&lCooldown-Message: &a" + itemMap.getCooldownMessage() : ""), (StringUtils.nullCheck(itemMap.getCommandSound() + "") != "NONE" ? "&9&lCommands-Sound: &a" + itemMap.getCommandSound() : ""), 
					(StringUtils.nullCheck(itemMap.getCommandParticle() + "") != "NONE" ? "&9&lCommands-Particle: &a" + itemMap.getCommandParticle() : ""), (StringUtils.nullCheck(itemMap.getEnchantments().toString()) != "NONE" ? "&9&lEnchantments: &a" + enchantList : ""), 
					(StringUtils.nullCheck(itemMap.getItemFlags()) != "NONE" ? "&9&lItemflags: &a" + itemflagsList : ""), (StringUtils.nullCheck(itemMap.getTriggers()) != "NONE" ? "&9&lTriggers: &a" + triggersList : ""), 
					(StringUtils.nullCheck(itemMap.getPermissionNode()) != "NONE" ? "&9&lPermission Node: &a" + itemMap.getPermissionNode() : ""), 
					(StringUtils.nullCheck(itemMap.getDisabledWorlds().toString()) != "NONE" ? "&9&lDisabled Worlds: &a" + disabledList : ""), (StringUtils.nullCheck(itemMap.getEnabledWorlds().toString()) != "NONE" ? "&9&lEnabled Worlds: &a" + enabledList : ""), 
					(StringUtils.nullCheck(itemMap.getEnabledRegions().toString()) != "NONE" ? "&9&lEnabled Regions: &a" + regionList : ""), (!itemMap.getDynamicMaterials().isEmpty() ? "&9&lMaterial Animations: &aYES" : ""), 
					(!itemMap.getDynamicNames().isEmpty() ? "&9&lName Animations: &aYES" : ""), (!itemMap.getDynamicLores().isEmpty() ? "&9&lLore Animations: &aYES" : ""), 
					(!itemMap.getDynamicOwners().isEmpty() || !itemMap.getDynamicTextures().isEmpty() ? "&9&lSkull Animations: &aYES" : ""), (StringUtils.nullCheck(itemMap.getLimitModes()) != "NONE" ? "&9&lLimit-Modes: &a" + itemMap.getLimitModes() : ""), 
					(StringUtils.nullCheck(itemMap.getProbability() + "&a%") != "NONE" ? "&9&lProbability: &a" + itemMap.getProbability() + "%" : ""), 
					(StringUtils.nullCheck(itemMap.getInteractCooldown() + "&7") != "NONE" ? "&9&lUse-Cooldown: &a" + itemMap.getInteractCooldown() : ""), 
					(StringUtils.nullCheck(itemMap.getLeatherColor()) != "NONE" ? "&9&lLeather Color: &a" + itemMap.getLeatherColor() : ""), (StringUtils.nullCheck(itemMap.getLeatherHex()) != "NONE" ? "&9&lLeather Color: &a" + itemMap.getLeatherHex() : ""),
					(StringUtils.nullCheck(itemMap.getMapImage()) != "NONE" ? "&9&lMap-Image: &a" + itemMap.getMapImage() : ""), (StringUtils.nullCheck(itemMap.getChargeColor() + "") != "NONE" ? "&9&lCharge Color: &a" + itemMap.getChargeColor() : ""),
					(StringUtils.nullCheck(patternList) != "NONE" ? "&9&lBanner Meta: &a" + patternList : ""), (StringUtils.nullCheck(potionList) != "NONE" ? "&9&lPotion-Effects: &a" + potionList : ""), (itemMap.getIngredients() != null && !itemMap.getIngredients().isEmpty() ? "&9&lRecipe: &aYES" : ""),
					(!mobs.isEmpty() ? "&9&lMobs Drop: &a" + mobs.substring(0, mobs.length() - 2) : ""), (!blocks.isEmpty() ? "&9&lBlocks Drop: &a" + blocks.substring(0, blocks.length() - 2) : ""), 
					(StringUtils.nullCheck(itemMap.getCommandConditions() + "") != "NONE" ? "&9&lCommand Conditions: &aYES" : ""), (StringUtils.nullCheck(itemMap.getDisposableConditions() + "") != "NONE" ? "&9&lDisposable Conditions: &aYES" : ""), 
					(StringUtils.nullCheck(itemMap.getTriggerConditions() + "") != "NONE" ? "&9&lTrigger Conditions: &aYES" : ""),
					(StringUtils.nullCheck(itemMap.getNBTValues() + "") != "NONE" ? "&9&lNBT Properties: &aYES" : ""), (StringUtils.nullCheck(itemMap.getContents() + "") != "NONE" ? "&9&lContents: &aYES" : ""),
					(StringUtils.nullCheck(attributeList) != "NONE" ? "&9&lAttributes: &a" + attributeList : ""), (StringUtils.nullCheck(itemMap.getPages() + "") != "NONE" ? "&9&lBook Pages: &aYES" : ""),
					(StringUtils.nullCheck(itemMap.getAuthor()) != "NONE" ? "&9&lBook Author: &a" + itemMap.getAuthor() : ""), (StringUtils.nullCheck(itemMap.getSkull()) != "NONE" ? "&9&lSkull-Owner: &a" + itemMap.getSkull() : ""), 
					(StringUtils.nullCheck(itemMap.getSkullTexture()) != "NONE" ? "&9&lSkull-Texture: &a" + (itemMap.getSkullTexture().length() > 40 ? itemMap.getSkullTexture().substring(0, 40) : itemMap.getSkullTexture()) : ""), 
					(StringUtils.nullCheck(itemMap.getFireworkType() + "") != "NONE" ? "&9&lFirework Type: &a" + itemMap.getFireworkType().name() : ""), 
					(StringUtils.nullCheck(itemMap.getFireworkPower() + "&7") != "NONE" ? "&9&lFirework Power: &a" + itemMap.getFireworkPower() : ""), (StringUtils.nullCheck(colorList) != "NONE" ? "&9&lFirework Color(s): &a" + colorList : ""), 
					(itemMap.getFireworkTrail() ? "&9&lFirework Trail: &aENABLED" : ""), (itemMap.getFireworkFlicker() ? "&9&lFirework Flicker: &aENABLED" : ""));
		} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
		if (ItemHandler.isSkull(itemMap.getMaterial())) {
			ItemMeta itemMeta = item.getItemMeta();
			if (itemMap.getSkull() != null) {
				itemMeta = ItemHandler.setSkullOwner(itemMeta, StringUtils.translateLayout(itemMap.getSkull(), player));
			} else if (itemMap.getSkullTexture() != null && !itemMap.isHeadDatabase()) {
				try {
					if (ServerUtils.hasSpecificUpdate("1_8")) {
						GameProfile gameProfile = new GameProfile(UUID.randomUUID(), null);
						gameProfile.getProperties().put("textures", new Property("textures", new String(itemMap.getSkullTexture())));
						Field declaredField = itemMeta.getClass().getDeclaredField("profile");
						declaredField.setAccessible(true);
						declaredField.set(itemMeta, gameProfile);
					}
				} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			} else if (itemMap.isHeadDatabase() && itemMap.getSkullTexture() != null) {
				HeadDatabaseAPI api = new HeadDatabaseAPI();
				ItemStack sk = api.getItemHead(itemMap.getSkullTexture());
				item = (sk != null ? sk : item.clone());
			}
			item.setItemMeta(itemMeta);
		}
		return item;
	}
	
   /**
    * Checks if the ItemMap is a special item.
    * 
    * @param itemMap - The ItemMap to be checked.
    * @return If the ItemMap is a "special" item.
    */
	private static boolean specialItem(final ItemMap itemMap) {
		if (itemMap.getMaterial().toString().contains("WRITTEN_BOOK") || itemMap.getMaterial().toString().contains("PLAYER_HEAD") || itemMap.getMaterial().toString().contains("SKULL_ITEM") 
				|| itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK") || itemMap.getMaterial().toString().equalsIgnoreCase("FIREWORK_ROCKET") 
				|| itemMap.getMaterial().toString().contains("TIPPED_ARROW") || itemMap.getMaterial().toString().contains("LEATHER_") || !ItemHandler.getDesignatedSlot(itemMap.getMaterial()).equalsIgnoreCase("noslot")) {
			return true;
		}
		return false;
	}
	
//  ==============================================================================================================================================================================================================================================================
	
   /**
    * Attemps to close all online players inventories, 
    * if they are found to have the plugin UI open.
    * 
    */
	public static void closeMenu() {
		PlayerHandler.forOnlinePlayers(player -> { 
			if (isOpen(player) || modifyMenu(player)) {
				player.closeInventory();
			}
		});
	}
	
   /**
    * Sets the Player to the Modify Menu.
    * 
    * @param bool - If the Player is in the Menu.
    * @param player - The Player to be set to the Modify Menu.
    */
	public static void setModifyMenu(final boolean bool, final Player player) {
		try {
			SchedulerUtils.runAsync(() -> {
				if (bool) { modifyMenu.add(PlayerHandler.getPlayerID(player)); } 
				else { modifyMenu.remove(PlayerHandler.getPlayerID(player)); }
			});
		} catch (ArrayIndexOutOfBoundsException e) { }
	}
	
   /**
    * Checks if the Player is in the Modify Menu.
    * 
    * @param player - The Player to be checked.
    * @return If the Player is in the Modify Menu.
    */
	public static boolean modifyMenu(final Player player) {
		return modifyMenu.contains(PlayerHandler.getPlayerID(player));
	}
	
   /**
    * Checks if the Player has the GUI Menu open.
    * 
    * @param player - The Player to be checked.
    * @return If the GUI Menu is open.
    */
	public static boolean isOpen(final Player player) {
		if (GUIName == null) { GUIName = ServerUtils.hasSpecificUpdate("1_9") ? StringUtils.colorFormat("&7           &0&n ItemJoin Menu") : StringUtils.colorFormat("&7           &0&n ItemJoin Menu"); }
		if (GUIName != null && player != null && player.getOpenInventory().getTitle().toString().equalsIgnoreCase(StringUtils.colorFormat(GUIName))) {
			return true;
		}
		return false;
	}
} public class StringUtils {
	
   /**
    * Checks if the condition is met.
    * 
    * @param condition - The condition to be compared against the value.
    * @param operand - The operation to be performed when comparing the condition to the value.
    * @param value - The value being compared against the condition.
    * @return If the condition has operand against value.
    */
	public static boolean conditionMet(final String condition, final String operand, final String value) {
		if (operand == null) { return false; }
		if (operand.equalsIgnoreCase("EQUAL") && ((condition != null && value != null && condition.equalsIgnoreCase(value)) || (condition == null && value == null))) {
			return true;
		} else if (operand.equalsIgnoreCase("NOTEQUAL") && ((condition != null && value != null && !condition.equalsIgnoreCase(value)) || ((condition == null && value != null) || (condition != null && value == null)))) {
			return true;
		} else if (operand.equalsIgnoreCase("OVER") && condition != null && value != null && isInt(condition) && isInt(value) && Integer.parseInt(condition) > Integer.parseInt(value)) {
			return true;
		} else if (operand.equalsIgnoreCase("UNDER") && condition != null && value != null && isInt(condition) && isInt(value) && Integer.parseInt(condition) < Integer.parseInt(value)) {
			return true;
		}
		return false;
	}
    
   /**
    * Checks if string1 contains string2.
    * 
    * @param string1 - The String to be checked if it contains string2.
    * @param string2 - The String that should be inside string1.
    * @return If string1 contains string2.
    */
	public static boolean containsIgnoreCase(final String string1, final String string2) {
		if (string1 != null && string2 != null && string1.toLowerCase().contains(string2.toLowerCase())) {
			return true;
		}
		return false;
	}
	
   /**
    * Checks if string1 contains string2.
    * 
    * @param string1 - The String to be checked if it contains string2.
    * @param string2 - The String that should be inside string1.
    * @param argument - The argument to be split between the string.
    * @return If string1 contains string2.
    */
	public static boolean splitIgnoreCase(final String string1, final String string2, final String argument) {
		String[] parts = string1.split(argument);
		boolean splitParts = string1.contains(argument);
		for (int i = 0; i < (splitParts ? parts.length : 1); i++) {
			if ((splitParts && parts[i] != null && string2 != null && parts[i].toLowerCase().replace(" ", "").equalsIgnoreCase(string2.replace(" ", "").toLowerCase()))
			|| (!splitParts && string1 != null && string2 != null && string1.toLowerCase().equalsIgnoreCase(string2.toLowerCase()))) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Checks if the List contains the String.
    * 
    * @param list - The List to be checked if it contains the String.
    * @param str - The String that should be inside the List.
    * @return If the List contained the String.
    */
	public static boolean containsValue(final List<?> list, final String str) {
		boolean bool = false;
		for (Object l : list) { if (l.toString().equalsIgnoreCase(str)) { bool = true; break; } }
		return bool;
	}
	
   /**
    * Splits the String with proper formatting and ordering.
    * 
    * @param str - The String to be Split.
    * @return The newly formatted String[].
    */
	public static String[] softSplit(final String str) {
		if (str.split(", ").length < 3) { return str.split("` "); }
		String splitTest = ""; int index = 1;
	    for (String sd : str.split(", ")) { if (index == 3) { splitTest += sd + "` "; index = 1; } else { splitTest += sd + ", "; index++; } }
	    if (splitTest.endsWith(", ")) { splitTest = splitTest.substring(0, splitTest.length() - 2); }
	    return splitTest.split("` ");
	}
	
   /**
    * Splits the String to a List.
    * 
    * @param str - The String to be Split.
    * @return The split String as a List.
    */
	public static List<String> split(final String str) {
		List<String> splitList = new ArrayList<String>();
		for (String split : str.split(", ")) {
			splitList.add(split);
		}
		return splitList;
	}
	
   /**
    * Replaces the last occurence of the regex.
    * 
    * @param str - The String to be checked.
    * @param sub1 - The occurence to be removed.
    * @param sub2 - The occurence to placed.
    * @return The newly replaced String.
    */
	public static String replaceLast(final String str, final String sub1, final String sub2) {
	    int pos = str.lastIndexOf(sub1); 
	    if (pos > -1) { 
	       return str.substring(0, pos) + sub2 + str.substring(pos + sub1.length(), str.length()); 
	    } else {
	       return str;
	    }
	}
	
   /**
    * Gets the items.yml path for the auto generated item and its corresponding Integer.
    * 
    * @param i - The Integer to be set as the item path.
    * @return The Integer to be set as the auto generated item path.
    */
	public static int getPath(final int i) {
		if (ConfigHandler.getConfig().getFile("items.yml").getString("items.item_" + i) != null) {
			return getPath(i + 1);
		}
		return i;
	}
	
   /**
    * Color Encodes a String so that it is completely hidden in color codes,
    * this will be invisible to a normal eye and will not display any text.
    * 
    * @param str - The String to be Color Encoded.
    * @return The Color Encoded String.
    */
	public static ItemStack colorEncode(final ItemStack itemStack, final String endData) {
		if (ServerUtils.hasSpecificUpdate("1_14")) {
			final ItemMeta itemMeta = itemStack.getItemMeta();
			final org.bukkit.NamespacedKey key = new org.bukkit.NamespacedKey(ItemJoin.getInstance(), "Item_Data");
			itemMeta.getPersistentDataContainer().set(key, org.bukkit.persistence.PersistentDataType.STRING, endData);
			itemStack.setItemMeta(itemMeta);
			return itemStack;
		} else {
			final String encodedData = LegacyAPI.colorEncode("ItemJoin" + endData);
			final ItemMeta itemMeta = itemStack.getItemMeta();
			itemMeta.setDisplayName(encodedData);
			itemStack.setItemMeta(itemMeta);
			return itemStack;
		}
	}

   /**
    * Decodes a Color Encoded String.
    * 
    * @param str - The String to be Color Decoded.
    * @return The Color Decoded String.
    */
	public static String colorDecode(final ItemStack itemStack) {
		if (ServerUtils.hasSpecificUpdate("1_14")) {
			final ItemMeta itemMeta = itemStack.getItemMeta();
			final org.bukkit.NamespacedKey key = new org.bukkit.NamespacedKey(ItemJoin.getInstance(), "Item_Data");
			final org.bukkit.persistence.PersistentDataContainer container = itemMeta.getPersistentDataContainer();
			if (container.has(key, org.bukkit.persistence.PersistentDataType.STRING)) {
			    return container.get(key, org.bukkit.persistence.PersistentDataType.STRING);
			}
		} else {
			return LegacyAPI.colorDecode(itemStack.getItemMeta().getDisplayName());
		}
		return null;
	}
	
   /**
    * Gets the Color from the provided HexColor.
    * 
    * @param hexString - The HexColor to be converted to Color.
    * @return The Color found from the HexColor.
    */
	public static Color getColorFromHexColor(final String hexString) {
		int hex = Integer.decode("#" + hexString.replace("#", ""));
		int r = (hex & 0xFF0000) >> 16;
		int g = (hex & 0xFF00) >> 8;
		int b = (hex & 0xFF);
		Color bukkitColor = Color.fromRGB(r, g, b);
		return bukkitColor;
	}
	
   /**
    * Gets the number of characters in the String.
    * 
    * @param str - The String to be checked.
    * @return The number of characters in the String..
    */
	public static int countCharacters(final String str) {
		int count = 0;
		for (int i = 0; i < str.length(); i++) {
			if (Character.isLetter(str.charAt(i)))
				count++;
			}
		return count;
	}
	
   /**
    * Checks if the specified String is an Integer Value.
    * 
    * @param str - The String to be checked.
    * @return If the String is an Integer Value.
    */
	public static boolean isInt(final String str) {
		try {
			Integer.parseInt(str);
		} catch (NumberFormatException e) { return false; }
		return true;
	}
	
   /**
    * Checks if the specified String is an Double Value.
    * 
    * @param str - The String to be checked.
    * @return If the String is an Double Value.
    */
	public static boolean isDouble(final String str) {
		try {
			Double.parseDouble(str);
		} catch (NumberFormatException e) { return false; }
		return true;
	}
	
   /**
    * Gets the first found Integer from the specified String.
    * 
    * @param str - The String to be checked.
    * @return The first found Integer.
    */
	public static Integer returnInteger(final String str) {
		if (str == null) { return null; }
		else {
			char[] characters = str.toCharArray();
			Integer value = null;
			boolean isPrevDigit = false;
			for (int i = 0; i < characters.length; i++) {
				if (isPrevDigit == false) {
					if (Character.isDigit(characters[i])) {
						isPrevDigit = true;
						value = Character.getNumericValue(characters[i]);
					}
				} else { if (Character.isDigit(characters[i])) { value = (value * 10) + Character.getNumericValue(characters[i]); } else { break; } }
			}
			return value;
		}
	}
	
   /**
    * Gives all custom items to the specified player.sadsadasds
    * 
    * @param player - that will recieve the items.
    */
	public static UUID UUIDConversion(String uuidString) {
		UUID uuid = null;
		if (uuidString != null && !uuidString.isEmpty()) {
			uuidString = uuidString.replace("-", "");
			uuid = new UUID( 
					new BigInteger(uuidString.substring(0, 16), 16).longValue(),
			        new BigInteger(uuidString.substring(16), 16).longValue());
		}
		return uuid;
	}
	
   /**
    * Converts a BufferedReader to a String output.
    * 
    * @param reader - the BufferedReader to be converted.
    * @return The resulting appended String.
    */
	public static String toString(final BufferedReader reader) throws IOException {
		final StringBuilder result = new StringBuilder();
		String line = null; while ((line = reader.readLine()) != null) { result.append(line); }
		return result.toString();
	}
	
   /**
    * Encodes the Texture String to Base64.
    * 
    * @param str - The String to be encoded.
    * @return The Texture Base64 encoded String.
    */
	public static String toTexture64(String url) {
		url = ItemHandler.cutDelay(url.replace("url-", ""));
		if (!StringUtils.containsIgnoreCase(url, "minecraft.net") && !StringUtils.containsIgnoreCase(url, "http") && !StringUtils.containsIgnoreCase(url, "https")) { 
			url = "https://textures.minecraft.net/texture/" + url; 
		}
		URI actualUrl = null;
		try {
			actualUrl = new URI(url);
		} catch (URISyntaxException e) {
			ServerUtils.logSevere("{Utils} Unable to reach the url " + url + " for a skull-texture.");
			ServerUtils.logSevere("{Utils} " + e.getReason());
		} 
		if (actualUrl != null) {
			url = "{\"textures\":{\"SKIN\":{\"url\":\"" + actualUrl.toString() + "\"}}}";
		}
		return Base64.getEncoder().encodeToString(url.getBytes());
	}
	
   /**
    * Encodes the Player UUID as a texture String.
    * 
    * @param player - The Player to be referenced.
    * @param configName - The node name of the item.
    * @param skullTexture - The skullTexture being fetched.
    * @return The Player UUID texture String.
    */
	public static String toTextureUUID(final Player player, final String configName, final String skullTexture) {
		if (StringUtils.containsIgnoreCase(skullTexture, "uuid")) {
			String https = ("https://sessionserver.mojang.com/session/minecraft/profile/" + StringUtils.translateLayout(skullTexture, player).replace("uuid-", "").replace("uuid", ""));
			try {
				final URL url = new URL(https);
				final BufferedReader read = new BufferedReader(new InputStreamReader(url.openStream()));
			    final StringBuffer stringBuilder = new StringBuffer();
			    String valueResult;
			    while ((valueResult = read.readLine()) != null) {
			    	if (StringUtils.containsIgnoreCase(valueResult, "value")) {
			    		stringBuilder.append(valueResult);
			    	}
			    } {
					Matcher m = Pattern.compile("\"([^\"]*)\"").matcher(stringBuilder);
					while (m.find()) {
						final String stringValue = m.group(1);
						if (!StringUtils.containsIgnoreCase(stringValue, "value")) {
							valueResult = stringValue;
						}
					} 
				}
				return valueResult;
			} catch (IOException e) {
				ServerUtils.logSevere("{ItemMap} Unable to connect to " + https);
				ServerUtils.logSevere("{ItemMap} " + e.getMessage());
				ServerUtils.logSevere("{ItemMap} The item " + configName + " will NOT have its skull-texture set!");
			}
		}
		return (skullTexture == null || skullTexture.isEmpty() ? skullTexture : skullTexture.replace("uuid-", "").replace("uuid", ""));
	}
	
   /**
    * Encrypts the String to Base64.
    * 
    * @param str - The String to be encrypted.
    * @return The Base64 encoded String.
    */
	public static String encrypt(final String str) {
		try {
			return Base64.getEncoder().encodeToString(str.getBytes("UTF-8"));
		} catch (Exception e) {
			ServerUtils.logDebug("{Utils} Failure to encrypt sensitive text!");
			ServerUtils.sendDebugTrace(e);
		}
		return null;
	}
	
   /**
    * Decrypts the encoded Base64 String.
    * 
    * @param str - The String to be decrypted.
    * @return The decrypted String.
    */
	public static String decrypt(final String str) {
		try {
			return new String(Base64.getDecoder().decode(str), "UTF-8");
		} catch (Exception e) {
			ServerUtils.logDebug("{Utils} Failure to decrypt sensitive text!");
			ServerUtils.sendDebugTrace(e);
		}
		return null;
	}
 
   /**
    * Gets a random Integer between the upper and lower limits.
    * 
    * @param lower - The lower limit.
    * @param upper - The upper limit.
    * @return The randomly selected Integer between the limits.
    */
	public static int getRandom(final int lower, final int upper) {
		return new Random().nextInt((upper - lower) + 1) + lower;
	}
	
   /**
    * Randomly selects an Entry from a ArrayList.
    * 
    * @param map - The ArrayList to have a entry selected.
    * @return The randomly selected entry.
    */
	public static Object randomEntry(final ArrayList<?> list) {
		Random rand = new Random();
		return list.get(rand.nextInt(list.size()));
	}
	
   /**
    * Checks if the String contains the location.
    * 
    * @param location - The location that the String should contain.
    * @param str - The String to be checked.
    * @return 
    */
	public static boolean containsLocation(final String location, final String str) {
		if (str.equalsIgnoreCase("ALL") || str.equalsIgnoreCase("GLOBAL") 
			|| str.equalsIgnoreCase("ENABLED") || str.equalsIgnoreCase("TRUE")) {
			return true;
		} else {
			for (String eventLoc: str.split(",")) {
				if (eventLoc.equalsIgnoreCase(location)) {
					return true;
				}
			}
		}
		return false;
	}
	
   /**
    * Gets the Crafting Slot ID Value.
    * 
    * @param str - The String to be checked.
    * @return The Crafting Slot Value.
    */
	public static int getSlotConversion(final String str) {
		if (str.equalsIgnoreCase("CRAFTING[0]")) {
			return 0;
		} else if (str.equalsIgnoreCase("CRAFTING[1]")) {
			return 1;
		} else if (str.equalsIgnoreCase("CRAFTING[2]")) {
			return 2;
		} else if (str.equalsIgnoreCase("CRAFTING[3]")) {
			return 3;
		} else if (str.equalsIgnoreCase("CRAFTING[4]")) {
			return 4;
		}
		return -1;
	}
	
   /**
    * Gets the Armor Slot ID.
    * 
    * @param slot - The slot to be checked.
    * @param integer - If the return value should be a String or Integer value.
    * @return The Armor Slot ID.
    */
	public static String getArmorSlot(final String slot, final boolean integer) {
		if (!integer) {
			if (slot.equalsIgnoreCase("39")) { return "HELMET"; }
			else if (slot.equalsIgnoreCase("38")) { return "CHESTPLATE"; }
			else if (slot.equalsIgnoreCase("37")) { return "LEGGINGS"; }
			else if (slot.equalsIgnoreCase("36")) { return "BOOTS"; }
			return slot;
		} else {
			if (slot.equalsIgnoreCase("HELMET") || slot.equalsIgnoreCase("HEAD")) { return "39"; }
			else if (slot.equalsIgnoreCase("CHESTPLATE")) { return "38"; }
			else if (slot.equalsIgnoreCase("LEGGINGS")) { return "37"; }
			else if (slot.equalsIgnoreCase("BOOTS")) { return "36"; }
			return slot;
		}
	}
   
   /**
    * Checks if the specified Listener is Registered.
    * 
    * @param listener - The name of the Listener to be checked.
    * @return If the Listener is Registered.
    */
	public static boolean isRegistered(final String listener) {
		boolean returnValue = false;
        ArrayList<RegisteredListener> rls = HandlerList.getRegisteredListeners(ItemJoin.getInstance());
        for(RegisteredListener rl: rls) {
        	if (rl.getListener().getClass().getSimpleName().equalsIgnoreCase(listener)) {
        		returnValue = true; break;
        	}
        }
		return returnValue;
	}
	
   /**
    * Checks if the input is NULL, and returns either NONE for NULL / EMPTY,
    * or the properly formatted list as a String.
    * 
    * @param input - The String to be checked.
    * @return The newly formatted String.
    */
	public static String nullCheck(String input) {
		if (input == null || input.equalsIgnoreCase("NULL") || input.contains("[]") || input.contains("{}") || input.equals("0&7") || input.equals("-1&a%") || input.equals("") || input.equals(" ")) {
			return "NONE";
		}
		if (input.startsWith("[") && input.endsWith("]")) {
			input = input.substring(0, input.length() - 1).substring(1);
		}
		if (input.startsWith("{") && input.endsWith("}")) {
			input = input.replace("{", "").replace("}", "").replace("=", ":");
		}
		return input;
	}
	
   /**
    * Translated the specified String by formatting its hex color codes.
    * 
    * @param str - The String to have its Color Codes properly Converted to Mojang Hex Colors.
    * @return The translated string.
    */
    public static String translateHexColorCodes(final String str) {
    	final char COLOR_CHAR = ChatColor.COLOR_CHAR;
    	Matcher matcher = Pattern.compile("&#([A-Fa-f0-9]{6})").matcher(str);
    	StringBuffer buffer = new StringBuffer(str.length() + 4 * 8);
    	while (matcher.find()) {
    		String group = matcher.group(1);
    		matcher.appendReplacement(buffer, COLOR_CHAR + "x" + COLOR_CHAR + group.charAt(0) + COLOR_CHAR + group.charAt(1) + COLOR_CHAR + group.charAt(2) + COLOR_CHAR + group.charAt(3) + COLOR_CHAR + group.charAt(4) + COLOR_CHAR + group.charAt(5));
    	}
    	return matcher.appendTail(buffer).toString();
    }
	
   /**
    * Formats any color codes found in the String to Bukkit Colors so the
    * text will be colorfully formatted.
    * 
    * @param str - The String to have its Color Codes properly Converted to Bukkit Colors.
    * @return The newly formatted String.
    */
	public static String colorFormat(final String str) {
		return ChatColor.translateAlternateColorCodes('&', translateHexColorCodes(str));
	}
	
   /**
    * Translates the specified String by foramtting its color codes and replacing placeholders.
    * 
    * @param str - The String being translated.
    * @param player - The Player having their String translated.
    * @param placeHolder - The placeholders to be replaced into the String.
    * @return The newly translated String.
    */
	public static String translateLayout(String str, final Player player, final String...placeHolder) {
		String playerName = "EXEMPT";
		if (player != null && DependAPI.getDepends(false).nickEnabled()) {
			try {
				de.domedd.betternick.api.nickedplayer.NickedPlayer np = new de.domedd.betternick.api.nickedplayer.NickedPlayer(player);
				if (np.isNicked()) {
					playerName = np.getRealName();
				} else { playerName = player.getName(); }
			} catch (NoClassDefFoundError e) {
				try {
					if (BetterNick.getApi().isPlayerNicked(player)) {
						playerName = BetterNick.getApi().getRealName(player);
					} else { playerName = player.getName(); }	
				} catch (NullPointerException e2) { playerName = player.getName(); }
			}
		} else if (player != null && DependAPI.getDepends(false).nickAPIEnabled()) {
			if (xyz.haoshoku.nick.api.NickAPI.isNicked(player)) {
				playerName = xyz.haoshoku.nick.api.NickAPI.getOriginalName(player);
			} else { playerName = player.getName(); }
		} else if (player != null) { playerName = player.getName(); }
		if (playerName != null && player != null && !(player instanceof ConsoleCommandSender)) {
			try { str = str.replace("%player%", playerName); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { str = str.replace("%player_uuid%", player.getUniqueId().toString()); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { str = str.replace("%mob_kills%", String.valueOf(player.getStatistic(Statistic.MOB_KILLS))); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { str = str.replace("%player_kills%", String.valueOf(player.getStatistic(Statistic.PLAYER_KILLS))); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { str = str.replace("%player_deaths%", String.valueOf(player.getStatistic(Statistic.DEATHS))); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { str = str.replace("%player_food%", String.valueOf(player.getFoodLevel())); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { 
				final double health = (ServerUtils.hasSpecificUpdate("1_8") ? player.getHealth() : (double)player.getClass().getMethod("getHealth", double.class).invoke(player));
				str = str.replace("%player_health%", String.valueOf(health)); 
			} catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { str = str.replace("%player_location%", player.getLocation().getBlockX() + ", " + player.getLocation().getBlockY() + ", " + player.getLocation().getBlockZ()); } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { if (placeHolder != null && placeHolder.length >= 1 && placeHolder[0] != null) { str = str.replace("%player_hit%", placeHolder[0]); } } catch (Exception e) { ServerUtils.sendDebugTrace(e); }
			try { if (Bukkit.isPrimaryThread()) { str = str.replace("%player_interact%", PlayerHandler.getNearbyPlayer(player, 3)); } } catch (Exception e) { ServerUtils.sendDebugTrace(e); } }
			if (player == null) { try { str = str.replace("%player%", "CONSOLE"); } catch (Exception e) { ServerUtils.sendDebugTrace(e); } }
			str = ChatColor.translateAlternateColorCodes('&', translateHexColorCodes(str));
		if (DependAPI.getDepends(false).placeHolderEnabled()) {
			try { try { return PlaceholderAPI.setPlaceholders(player, str); } 
			catch (NoSuchFieldError e) { ServerUtils.logWarn("An error has occured when setting the PlaceHolder " + e.getMessage() + ", if this issue persits contact the developer of PlaceholderAPI."); return str; }
			} catch (Exception e) { }
		}
		return str;
	}
} public class DataObject {
	private Table table = Table.FIRST_JOIN;
	private Boolean isTemporary = false;
	private String playerId = new String();
	private String regionName = new String();
	private String worldName = new String();
	private String cooldown = new String();
	private String ipAddress = new String();
	private String duration = new String();
	private String command = new String();
	private String inventory64 = new String();
	private String mapImage = new String();
	private String mapId = new String();
	private String item = new String();
	private String isEnabled = new String();
	private String timeStamp = new String();
	
   /**
    * Gets the Player ID of the DataObject
    * 
    * @return The Player ID.
    */
	public String getPlayerId() {
		return this.playerId;
	}
	
   /**
    * Gets the World Name of the DataObject
    * 
    * @return The World Name.
    */
	public String getWorld() {
		return this.worldName;
	}
	
   /**
    * Gets the Region Name of the DataObject
    * 
    * @return The Region Name.
    */
	public String getRegion() {
		return this.regionName;
	}
	
   /**
    * Gets the IP Address of the DataObject
    * 
    * @return The IP Address.
    */
	public String getIPAddress() {
		return this.ipAddress;
	}
	
   /**
    * Gets the Map Image of the DataObject
    * 
    * @return The Map Image.
    */
	public String getMapIMG() {
		return this.mapImage;
	}
	
   /**
    * Gets the Map ID of the DataObject
    * 
    * @return The Map ID.
    */
	public String getMapID() {
		return this.mapId;
	}
	
   /**
    * Gets the Cooldown of the DataObject
    * 
    * @return The Cooldown.
    */
	public String getCooldown() {
		return this.cooldown;
	}
	
   /**
    * Gets the Duration of the DataObject
    * 
    * @return The Duration.
    */
	public String getDuration() {
		return this.duration;
	}
	
   /**
    * Gets the Enabled/Disabled Boolean of the DataObject
    * 
    * @return The Enabled/Disabled Boolean.
    */
	public String getEnabled() {
		return this.isEnabled;
	}
	
   /**
    * Gets the Inventory in 64 Hash of the DataObject
    * 
    * @return The Inventory in 64 Hash.
    */
	public String getInventory64() {
		return this.inventory64;
	}
	
   /**
    * Gets the Command String of the DataObject
    * 
    * @return The Command String.
    */
	public String getCommand() {
		return this.command;
	}
	
   /**
    * Gets the Item Node of the DataObject
    * 
    * @return The Item Node.
    */
	public String getItem() {
		return this.item;
	}
	
   /**
    * Gets the Time Stamp of the DataObject
    * 
    * @return The Time Stamp.
    */
	public String getTimeStamp() {
		return this.timeStamp;
	}
	
   /**
    * Sets the Time Stamp of the DataObject
    * 
    * @param stamp - The Time Stamp.
    */
	public void setTimeStamp(final String stamp) {
		this.timeStamp = stamp;
	}

   /**
    * Gets the Table of the DataObject
    * 
    * @return The Table.
    */	
	public Table getTable() {
		return this.table;
	}
	
   /**
    * Gets if the DataObject is only a reference.
    * 
    * @return If the DataObject is a reference.
    */	
	public boolean isTemporary() {
		return this.isTemporary;
	}
	
   /**
    * Creates a new DataObject instance
    * 
    * @param table - The Table being accessed.
    * @param isTemporary - If the DataObject is only a reference.
    */
	public DataObject(Table table) {
		this.table = table;
		this.isTemporary = true;
	}
	
   /**
    * Creates a new DataObject instance
    * 
    * @param table - The Table being accessed.
    * @param playerId - The Player UUID being referenced.
    * @param worldName - The World Name being referenced.
    * @param object - The Object being referenced.
    */
	public DataObject(final Table table, final String playerId, final String worldName, final String object) {
		if (playerId != null && !playerId.isEmpty()) {
			this.playerId = playerId;
		} else if (table.equals(Table.ENABLED_PLAYERS)) { 
			this.playerId = "ALL"; 
		}
		if (table.equals(Table.FIRST_JOIN) || table.equals(Table.FIRST_WORLD)) {
			this.item = object;
		} else if (table.equals(Table.RETURN_CRAFTITEMS) || table.equals(Table.RETURN_SWITCH_ITEMS)) {
			this.inventory64 = object;
		}else if (table.equals(Table.FIRST_COMMANDS)) {
			this.command = object;
		}
		this.table = table;
		this.worldName = worldName;
		this.timeStamp = new Timestamp(System.currentTimeMillis()).toString();
	}
	
   /**
    * Creates a new DataObject instance
    * 
    * @param table - The Table being accessed.
    * @param playerId - The Player UUID being referenced.
    * @param worldName - The World Name being referenced.
    * @param object1 - The Object being referenced.
    * @param object2 - The Object being referenced.
    */
	public DataObject(final Table table, final String playerId, final String worldName, final String object1, final String object2) {
		if (playerId != null && !playerId.isEmpty()) {
			this.playerId = playerId;
		} else if (table.equals(Table.ENABLED_PLAYERS)) { 
			this.playerId = "ALL"; 
		}
		if (table.equals(Table.MAP_IDS)) {
			this.mapImage = object1;
			this.mapId = object2;
		} else if (table.equals(Table.RETURN_ITEMS)) {
			this.regionName = object1;
			this.inventory64 = object2;
		} else if (table.equals(Table.IP_LIMITS)) {
			this.item = object1;
			this.ipAddress = object2;
		} else if (table.equals(Table.ENABLED_PLAYERS)) {
			this.item = object1;
			this.isEnabled = object2;
		}
		this.table = table;
		this.worldName = worldName;
		this.timeStamp = new Timestamp(System.currentTimeMillis()).toString();
	}
	
   /**
    * Creates a new DataObject instance
    * 
    * @param table - The Table being accessed.
    * @param playerId - The Player UUID being referenced.
    * @param worldName - The World Name being referenced.
    * @param object1 - The Object being referenced.
    * @param object2 - The Object being referenced.
    * @param object3 - The Object being referenced.
    */
	public DataObject(final Table table, final String playerId, final String worldName, final String object1, final String object2, final String object3) {
		if (playerId != null && !playerId.isEmpty()) {
			this.playerId = playerId;
		} else if (table.equals(Table.ENABLED_PLAYERS)) { 
			this.playerId = "ALL"; 
		}
		if (table.equals(Table.ON_COOLDOWN)) {
			this.item = object1;
			this.cooldown = object2;
			this.duration = object3;
		}
		this.table = table;
		this.worldName = ((worldName != null && !worldName.isEmpty()) ? worldName : "Global");
		this.timeStamp = new Timestamp(System.currentTimeMillis()).toString();
	}
	
   /**
    * Gets the Equal Data of the DataObject
    * 
    * @param object1 - The DataObject being compared.
    * @param object2 - The DataObject being compared.
    * @return If the data is equal.
    */	
	public boolean equalsData(final DataObject object1, final DataObject object2) {
		if (object1 == null || object2 == null) { return false; }
		if (object1.getTable().equals(Table.FIRST_JOIN)) {
			if (object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()) && (object1.getItem().isEmpty() || object1.getItem().equalsIgnoreCase(object2.getItem()))) {
				return true;
			}
		} else if (object1.getTable().equals(Table.FIRST_WORLD)) {
			if (object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()) 
					&& (object1.getWorld().isEmpty() || object1.getWorld().equalsIgnoreCase(object2.getWorld())) 
					&& (object1.getItem().isEmpty() || object1.getItem().equalsIgnoreCase(object2.getItem()))) {
				return true;
			}
		} else if (object1.getTable().equals(Table.IP_LIMITS)) {
			if ((object1.getItem().isEmpty() && object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()) 
					|| (object1.getWorld().equalsIgnoreCase(object2.getWorld()) && object1.getItem().equalsIgnoreCase(object2.getItem()) && object1.getIPAddress().equalsIgnoreCase(object2.getIPAddress())))) {
				return true;
			}
		} else if (object1.getTable().equals(Table.FIRST_COMMANDS)) {
			if (object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()) && (object1.getWorld().isEmpty() || object1.getWorld().equalsIgnoreCase(object2.getWorld())) 
					&& (object1.getCommand().isEmpty() || object1.getCommand().equalsIgnoreCase(object2.getCommand()))) {
				return true;
			}
		} else if (object1.getTable().equals(Table.ENABLED_PLAYERS)) {
			if ((object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()))
					&& (object1.getWorld().isEmpty() || (object1.getWorld().equalsIgnoreCase(object2.getWorld()) || object2.getWorld().equalsIgnoreCase("Global")))
					&& (object1.getItem().equalsIgnoreCase(object2.getItem()))) {
				return true;
			}
		} else if (object1.getTable().equals(Table.RETURN_ITEMS)) {
			if (object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()) && object1.getRegion().equalsIgnoreCase(object2.getRegion())) {
				return true;
			}
		} else if (object1.getTable().equals(Table.RETURN_SWITCH_ITEMS)) {
			if (object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId()) && object1.getWorld().equalsIgnoreCase(object2.getWorld())) {
				return true;
			}
		} else if (object1.getTable().equals(Table.RETURN_CRAFTITEMS)) {
			if (object1.getPlayerId().equalsIgnoreCase(object2.getPlayerId())) {
				return true;
			}
		} else if (object1.getTable().equals(Table.ON_COOLDOWN)) {
			if (object1.getItem().equalsIgnoreCase(object2.getItem()) && object1.getCooldown().equalsIgnoreCase(object2.getCooldown())) {
				return true;
			}
		} else if (object1.getTable().equals(Table.MAP_IDS)) {
			if (object1.getMapIMG().equalsIgnoreCase(object2.getMapIMG())) {
				return true;
			}
		} 
		return false;
	}
	
   /**
    * Gets the Removal Values of the DataObject
    * 
    * @return The Removal Values.
    */	
	public String getRemovalValues() {
		String removal = "";
		for (String column : this.table.removal().split(", ")) {
			if (column.equalsIgnoreCase("Player_UUID")) { removal += "'" + this.getPlayerId() + "',"; }
			else if (column.equalsIgnoreCase("World_Name")) { removal += "'" + this.getWorld() + "',"; }
			else if (column.equalsIgnoreCase("Region_Name")) { removal += "'" + this.getRegion() + "',"; }
			else if (column.equalsIgnoreCase("Map_IMG")) { removal += "'" + this.getMapIMG() + "',"; }
			else if (column.equalsIgnoreCase("Item_Name")) { removal += "'" + this.getItem() + "',"; }
		}
		return removal.substring(0, removal.length() - 1);
	}
	
   /**
    * Gets the Insert Values of the DataObject
    * 
    * @return The Insert Values.
    */	
	public String getInsertValues() {
		return 
				  (this.getWorld() != null && !this.getWorld().isEmpty() ? "'" + this.getWorld() + "'," : "")
				+ (this.getRegion() != null && !this.getRegion().isEmpty() ? "'" + this.getRegion() + "'," : "")
				+ (this.getPlayerId() != null && !this.getPlayerId().isEmpty() ? "'" + this.getPlayerId() + "'," : "")
				+ (this.getItem() != null && !this.getItem().isEmpty() ? "'" + this.getItem() + "'," : "")
			    + (this.getIPAddress() != null && !this.getIPAddress().isEmpty() ? "'" + this.getIPAddress() + "'," : "")
			    + (this.getCooldown() != null && !this.getCooldown().isEmpty() ? "'" + this.getCooldown() + "'," : "")
			    + (this.getDuration() != null && !this.getDuration().isEmpty() ? "'" + this.getDuration() + "'," : "")
			    + (this.getEnabled() != null && !this.getEnabled().isEmpty() ? "'" + this.getEnabled() + "'," : "")
			    + (this.getInventory64() != null && !this.getInventory64().isEmpty() ? "'" + this.getInventory64() + "'," : "")
			    + (this.getCommand() != null && !this.getCommand().isEmpty() ? "'" + this.getCommand() + "'," : "")
			    + (this.getMapIMG() != null && !this.getMapIMG().isEmpty() ? "'" + this.getMapIMG() + "'," : "")
			    + (this.getMapID() != null && !this.getMapID().isEmpty() ? "'" + this.getMapID() + "'," : "")
			    + "'" + new Timestamp(System.currentTimeMillis()) + "'";
	}
	
   /**
	* Defines the existing tables.
	* 
	*/ 
    public enum Table {
       FIRST_JOIN("first_join", "`Player_UUID`, `Item_Name`, `Time_Stamp`", "Player_UUID"), 
       FIRST_WORLD("first_world", "`World_Name`, `Player_UUID`, `Item_Name`, `Time_Stamp`", "Player_UUID"), 
       IP_LIMITS("ip_limits", "`World_Name`, `Player_UUID`, `Item_Name`, `IP_Address`, `Time_Stamp`", "Player_UUID"), 
       FIRST_COMMANDS("first_commands", "`World_Name`, `Player_UUID`, `Command_String`, `Time_Stamp`", "Player_UUID"), 
       ENABLED_PLAYERS("enabled_players", "`World_Name`, `Player_UUID`, `Item_Name`, `isEnabled`, `Time_Stamp`", "Player_UUID, World_Name"), 
       RETURN_ITEMS("return_items", "`World_Name`, `Region_Name`, `Player_UUID`, `Inventory64`, `Time_Stamp`", "Player_UUID, World_Name, Region_Name"), 
       RETURN_SWITCH_ITEMS("return_switch_items", "`World_Name`, `Player_UUID`, `Inventory64`, `Time_Stamp`", "Player_UUID, World_Name"), 
       RETURN_CRAFTITEMS("return_craftitems", "`Player_UUID`, `Inventory64`, `Time_Stamp`", "Player_UUID"), 
       ON_COOLDOWN("on_cooldown", "`World_Name`, `Player_UUID`, `Item_Name`, `Cooldown`, `Duration`, `Time_Stamp`", "Item_Name"), 
       MAP_IDS("map_ids", "`Map_IMG`, `Map_ID`, `Time_Stamp`", "Map_IMG");
    	
    	private String tableName;
    	private String header;
    	private String removal;
    	private Table(final String tableName, final String header, final String removal) {
    		this.tableName = tableName;
    		this.header = header;
    		this.removal = removal;
    	}
    	
    	public String tableName() { return this.tableName; }
    	public String headers()   { return this.header; }
    	public String removal()   { return this.removal; }
    }
} public class SQL {
	
	private Map < String, List<DataObject> > databaseData = new HashMap < String, List<DataObject> >();
	
	private static SQL data;
	
   /**
    * Creates a new SQLData instance.
    * 
    */
	public SQL() {
		Database.kill(); {
			this.createTables();
			this.loadData();
			ServerUtils.logDebug("{SQL} Database Connected."); 
		}
	}
	
   /**
    * Removes ItemJoin tables from the database.
    * 
    */
	public void purgeDatabase() {
		this.databaseData.clear();
		SchedulerUtils.runSingleAsync(() -> {
			for (Table table: Table.values()) {
				synchronized("IJ_SQL") {
					Database.getDatabase().executeStatement("DROP TABLE IF EXISTS " + ConfigHandler.getConfig().getTable() + table.tableName());
				}
			} { this.createTables(); }
		});
	}
	
   /**
    * Saves the table data for the specified DataObject.
    * 
    * @param object - The DataObject data being saved.
    */
	public void saveData(DataObject object) {
		if (object != null) { 
			String table = object.getTable().tableName();
			if (ItemJoin.getInstance().isEnabled()) {
				SchedulerUtils.runSingleAsync(() -> {
					synchronized("IJ_SQL") {
						Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + object.getTable().tableName() + " (" + object.getTable().headers() + ") VALUES (" + object.getInsertValues() + ")");
					}
				});
			} else {
				synchronized("IJ_SQL") {
					Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + object.getTable().tableName() + " (" + object.getTable().headers() + ") VALUES (" + object.getInsertValues() + ")");
				}
			}
			if (this.databaseData.get(table) != null) {
				List <DataObject> h1 = this.databaseData.get(table);
				h1.add(object);
				this.databaseData.put(table, h1);
			} else {
				List <DataObject> h1 = new ArrayList<DataObject>();
				h1.add(object);
				this.databaseData.put(table, h1);
			}
		}
	}
	
   /**
    * Removes the table data for the specified DataObject.
    * 
    * @param object - The DataObject being accessed.
    */
	public void removeData(DataObject object) {
		if (object != null) { 
			String table = object.getTable().tableName();
			if (this.databaseData.get(table) != null && !this.databaseData.get(table).isEmpty()) {
				Iterator<DataObject> dataSet = this.databaseData.get(table).iterator();
				while (dataSet.hasNext()) {
					DataObject dataObject = dataSet.next();
					if (dataObject != null && dataObject.getTable().equals(object.getTable()) && object.equalsData(object, dataObject)) {
						if (ItemJoin.getInstance().isEnabled()) {
							SchedulerUtils.runSingleAsync(() -> {
								synchronized("IJ_SQL") {
									Database.getDatabase().executeStatement("DELETE FROM " + ConfigHandler.getConfig().getTable() + dataObject.getTable().tableName() + " WHERE (" + dataObject.getTable().removal() + ") = (" + dataObject.getRemovalValues() + ")");
								}
							});
						} else {
							synchronized("IJ_SQL") {
								Database.getDatabase().executeStatement("DELETE FROM " + ConfigHandler.getConfig().getTable() + dataObject.getTable().tableName() + " WHERE (" + dataObject.getTable().removal() + ") = (" + dataObject.getRemovalValues() + ")");
							}
						}
						dataSet.remove();
					}
				}
			}
		}
	}
	
   /**
    * Gets the table data for the specified DataObject.
    * 
    * @param object - The DataObject being accessed.
    * @return The found table data.
    */
	public DataObject getData(DataObject object) {
		if (object != null) { 
			String table = object.getTable().tableName();
			if (this.databaseData.get(table) != null && !this.databaseData.get(table).isEmpty()) {
				Iterator<DataObject> dataSet = this.databaseData.get(table).iterator();
				while (dataSet.hasNext()) {
					DataObject dataObject = dataSet.next();
					if (dataObject != null && dataObject.getTable().equals(object.getTable()) && object.equalsData(object, dataObject)) {
						return dataObject;
					}
				}
			}
		}
		return null;
	}
	
   /**
    * Gets the table data list for the specified DataObject.
    * 
    * @param object - The DataObject being accessed.
    * @return The found table data list.
    */
	public List<DataObject> getDataList(DataObject object) {
		List<DataObject> dataList = new ArrayList<DataObject>();
		String table = object.getTable().tableName();
		if (this.databaseData.get(table) != null && !this.databaseData.get(table).isEmpty()) {
			Iterator<DataObject> dataSet = this.databaseData.get(table).iterator();
			while (dataSet.hasNext()) {
				DataObject dataObject = dataSet.next();
				if (dataObject != null && dataObject.getTable().equals(object.getTable()) && (object.isTemporary() || object.equalsData(object, dataObject))) {
					dataList.add(dataObject);
				}
			}
		}
		return dataList;
	}
	
   /**
    * Loads all the database data into memory.
    * 
    */
	private void loadData() {
		for (Table tableEnum: Table.values()) {
			String table = tableEnum.tableName();
			List<HashMap<String, String>> selectTable = Database.getDatabase().queryTableData("SELECT * FROM " + ConfigHandler.getConfig().getTable() + table, tableEnum.headers().replace("`", ""));
			if (selectTable != null && !selectTable.isEmpty()) {
				for (HashMap<String, String> sl1 : selectTable) {
					DataObject dataObject = null;
					if (tableEnum.equals(Table.FIRST_JOIN)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), "", sl1.get("Item_Name"));
					} else if (tableEnum.equals(Table.FIRST_WORLD)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Item_Name"));
					} else if (tableEnum.equals(Table.IP_LIMITS)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Item_Name"), sl1.get("IP_Address"));
					} else if (tableEnum.equals(Table.FIRST_COMMANDS)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Command_String"));
					} else if (tableEnum.equals(Table.ENABLED_PLAYERS)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Item_Name"), sl1.get("isEnabled"));
					} else if (tableEnum.equals(Table.RETURN_ITEMS)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Region_Name"), sl1.get("Inventory64"));
					} else if (tableEnum.equals(Table.RETURN_CRAFTITEMS)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), "", sl1.get("Inventory64"));
					} else if (tableEnum.equals(Table.RETURN_SWITCH_ITEMS)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Inventory64"));
					} else if (tableEnum.equals(Table.ON_COOLDOWN)) {
						dataObject = new DataObject(tableEnum, sl1.get("Player_UUID"), sl1.get("World_Name"), sl1.get("Item_Name"), sl1.get("Cooldown"), sl1.get("Duration"));
					} else if (tableEnum.equals(Table.MAP_IDS)) {
						dataObject = new DataObject(tableEnum, null, null, sl1.get("Map_IMG"), sl1.get("Map_ID"));
					}
					dataObject.setTimeStamp(sl1.get("Time_Stamp"));
					List <DataObject> dataSet = (this.databaseData.get(table) != null ? this.databaseData.get(table) : new ArrayList<DataObject>());
					dataSet.add(dataObject);
					this.databaseData.put(table, dataSet);
				}
			}
		}
	}
	
   /**
    * Gets the Equal Data of the DataObject
    * 
    * @param object - The DataObject being accessed.
    * @return If the data is equal.
    */	
	public boolean hasDataSet(DataObject object) {
		String table = object.getTable().tableName();
		Iterator<DataObject> dataSet = this.databaseData.get(table).iterator();
		while (dataSet.hasNext()) {
			DataObject dataObject = dataSet.next();
			if (dataObject.getTable().equals(object.getTable()) && object.equalsData(object, dataObject)) {
				return true;
			}
		}
		return false;
	}
	
   /**
    * Creates the missing database tables.
    * 
    */
	private void createTables() {
		this.alterTables(); {
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "first_join (`Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "first_world (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "ip_limits (`World_Name` varchar(1000), `IP_Address` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "first_commands (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Command_String` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "enabled_players (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `isEnabled` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "return_items (`World_Name` varchar(1000), `Region_Name` varchar(1000), `Player_UUID` varchar(1000), `Inventory64` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "return_craftitems (`Player_UUID` varchar(1000), `Inventory64` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "return_switch_items (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Inventory64` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "on_cooldown (`World_Name` varchar(1000), `Item_Name` varchar(1000), `Player_UUID` varchar(1000), `Cooldown` varchar(1000), `Duration` varchar(1000), `Time_Stamp` varchar(1000));");
	        Database.getDatabase().executeStatement("CREATE TABLE IF NOT EXISTS " + ConfigHandler.getConfig().getTable() + "map_ids (`Map_IMG` varchar(1000), `Map_ID` varchar(1000), `Time_Stamp` varchar(1000));");
		}
	}
	
   /**
    * Alters any existing tables to fit the new TIME_STAMP datatype.
    * 
    */
	private void alterTables() {
		// Removes legacy columns from legacy tables.
		if (Database.getDatabase().tableExists(ConfigHandler.getConfig().getTable() + "first_join") && Database.getDatabase().columnExists("SELECT Player_Name FROM " + ConfigHandler.getConfig().getTable() + "first_join")) {
			Database.getDatabase().executeStatement("CREATE TEMPORARY TABLE " + ConfigHandler.getConfig().getTable() + "first_join_backup (`Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
			Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + "first_join_backup SELECT Player_UUID,Item_Name,Time_Stamp FROM " + ConfigHandler.getConfig().getTable() + "first_join;");
			Database.getDatabase().executeStatement("DROP TABLE " + ConfigHandler.getConfig().getTable() + "first_join");
			Database.getDatabase().executeStatement("CREATE TABLE " + ConfigHandler.getConfig().getTable() + "first_join (`Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
			Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + "first_join SELECT Player_UUID,Item_Name,Time_Stamp FROM " + ConfigHandler.getConfig().getTable() + "first_join_backup;");
			Database.getDatabase().executeStatement("DROP TABLE " + ConfigHandler.getConfig().getTable() + "first_join_backup");
		}
		if (Database.getDatabase().tableExists(ConfigHandler.getConfig().getTable() + "first_world") && Database.getDatabase().columnExists("SELECT Player_Name FROM " + ConfigHandler.getConfig().getTable() + "first_world")) {
			Database.getDatabase().executeStatement("CREATE TEMPORARY TABLE " + ConfigHandler.getConfig().getTable() + "first_world_backup (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
			Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + "first_world_backup SELECT World_Name,Player_UUID,Item_Name,Time_Stamp FROM " + ConfigHandler.getConfig().getTable() + "first_world;");
			Database.getDatabase().executeStatement("DROP TABLE " + ConfigHandler.getConfig().getTable() + "first_world");
			Database.getDatabase().executeStatement("CREATE TABLE " + ConfigHandler.getConfig().getTable() + "first_world (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `Time_Stamp` varchar(1000));");
			Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + "first_world SELECT World_Name,Player_UUID,Item_Name,Time_Stamp FROM " + ConfigHandler.getConfig().getTable() + "first_world_backup;");
			Database.getDatabase().executeStatement("DROP TABLE " + ConfigHandler.getConfig().getTable() + "first_world_backup");
		}
		if (Database.getDatabase().tableExists(ConfigHandler.getConfig().getTable() + "enabled_players")) {
			if (!Database.getDatabase().columnExists("SELECT Item_Name FROM " + ConfigHandler.getConfig().getTable() + "enabled_players")) {
				Database.getDatabase().executeStatement("ALTER TABLE " + ConfigHandler.getConfig().getTable() + "enabled_players" + " ADD Item_Name varchar(1000);");
			}
			if (Database.getDatabase().columnExists("SELECT Player_Name FROM " + ConfigHandler.getConfig().getTable() + "enabled_players")) {
				Database.getDatabase().executeStatement("CREATE TEMPORARY TABLE " + ConfigHandler.getConfig().getTable() + "enabled_players_backup (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `isEnabled` varchar(1000), `Time_Stamp` varchar(1000));");
				Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + "enabled_players_backup SELECT World_Name,Player_UUID,Item_Name,isEnabled,Time_Stamp FROM " + ConfigHandler.getConfig().getTable() + "enabled_players;");
				Database.getDatabase().executeStatement("DROP TABLE " + ConfigHandler.getConfig().getTable() + "enabled_players");
				Database.getDatabase().executeStatement("CREATE TABLE " + ConfigHandler.getConfig().getTable() + "enabled_players (`World_Name` varchar(1000), `Player_UUID` varchar(1000), `Item_Name` varchar(1000), `isEnabled` varchar(1000), `Time_Stamp` varchar(1000));");
				Database.getDatabase().executeStatement("INSERT INTO " + ConfigHandler.getConfig().getTable() + "enabled_players SELECT World_Name,Player_UUID,Item_Name,isEnabled,Time_Stamp FROM " + ConfigHandler.getConfig().getTable() + "enabled_players_backup;");
				Database.getDatabase().executeStatement("DROP TABLE " + ConfigHandler.getConfig().getTable() + "enabled_players_backup");
			}
		}
	}
	
	public static void newData(final boolean reload) {
		if (!reload) {
			data = new SQL();
		} else if ((!ConfigHandler.getConfig().sqlEnabled() && Database.getDatabase().getConstant()) || (ConfigHandler.getConfig().sqlEnabled() && !Database.getDatabase().getConstant())) {
			data = new SQL();
		}
	}
	
   /**
    * Gets the instance of the SQLite.
    * 
    * @param regen - If the SQLite should have a new instance created.
    * @return The SQLite instance.
    */
    public static SQL getData() { 
        if (data == null) { newData(false); }
        return data; 
    } 
} public enum Table {
   FIRST_JOIN("first_join", "`Player_UUID`, `Item_Name`, `Time_Stamp`", "Player_UUID"), 
   FIRST_WORLD("first_world", "`World_Name`, `Player_UUID`, `Item_Name`, `Time_Stamp`", "Player_UUID"), 
   IP_LIMITS("ip_limits", "`World_Name`, `Player_UUID`, `Item_Name`, `IP_Address`, `Time_Stamp`", "Player_UUID"), 
   FIRST_COMMANDS("first_commands", "`World_Name`, `Player_UUID`, `Command_String`, `Time_Stamp`", "Player_UUID"), 
   ENABLED_PLAYERS("enabled_players", "`World_Name`, `Player_UUID`, `Item_Name`, `isEnabled`, `Time_Stamp`", "Player_UUID, World_Name"), 
   RETURN_ITEMS("return_items", "`World_Name`, `Region_Name`, `Player_UUID`, `Inventory64`, `Time_Stamp`", "Player_UUID, World_Name, Region_Name"), 
   RETURN_SWITCH_ITEMS("return_switch_items", "`World_Name`, `Player_UUID`, `Inventory64`, `Time_Stamp`", "Player_UUID, World_Name"), 
   RETURN_CRAFTITEMS("return_craftitems", "`Player_UUID`, `Inventory64`, `Time_Stamp`", "Player_UUID"), 
   ON_COOLDOWN("on_cooldown", "`World_Name`, `Player_UUID`, `Item_Name`, `Cooldown`, `Duration`, `Time_Stamp`", "Item_Name"), 
   MAP_IDS("map_ids", "`Map_IMG`, `Map_ID`, `Time_Stamp`", "Map_IMG");
    	
	private String tableName;
	private String header;
	private String removal;
	private Table(final String tableName, final String header, final String removal) {
		this.tableName = tableName;
		this.header = header;
		this.removal = removal;
	}
    	
	public String tableName() { return this.tableName; }
	public String headers()   { return this.header; }
	public String removal()   { return this.removal; }
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import me.RockinChaos.itemjoin.ChatComponent.ClickAction;
import me.RockinChaos.itemjoin.handlers.ConfigHandler;
import me.RockinChaos.itemjoin.handlers.ItemHandler;
import me.RockinChaos.itemjoin.handlers.PermissionsHandler;
import me.RockinChaos.itemjoin.handlers.PlayerHandler;
import me.RockinChaos.itemjoin.handlers.UpdateHandler;
import me.RockinChaos.itemjoin.item.ItemMap;
import me.RockinChaos.itemjoin.item.ItemUtilities;
import me.RockinChaos.itemjoin.utils.SchedulerUtils;
import me.RockinChaos.itemjoin.utils.ServerUtils;
import me.RockinChaos.itemjoin.utils.api.ChanceAPI;
import me.RockinChaos.itemjoin.utils.api.LanguageAPI;
import me.RockinChaos.itemjoin.utils.api.LegacyAPI;
import me.RockinChaos.itemjoin.utils.interfaces.menus.Menu;
import me.RockinChaos.itemjoin.utils.StringUtils;
import me.RockinChaos.itemjoin.utils.sql.DataObject;
import me.RockinChaos.itemjoin.utils.sql.SQL;
import me.RockinChaos.itemjoin.utils.sql.DataObject.Table;
		boolean worldSent = false;
		for (World world: Bukkit.getWorlds()) {
			if (((lineCount + 1) != (page * 15))) {
			boolean itemFound = false;
			String[] placeHolders = LanguageAPI.getLang(false).newString();
			placeHolders[0] = world.getName();
			if (!(lineCount > (page * 15)) && (page == 1 || !(lineCount < ((page - 1) * 15)))) {
				LanguageAPI.getLang(false).sendLangMessage("commands.list.worldHeader", sender, placeHolders);
				lineCount++;
				worldSent = true;
			} else { lineCount++; }
			List < String > inputListed = new ArrayList < String > ();
			for (ItemMap itemMap: ItemUtilities.getUtilities().getItems()) {
				if (!inputListed.contains(itemMap.getConfigName()) && itemMap.inWorld(world)) {
					if ((page == 1 && !(lineCount >= (page * 15))) || (page != 1 && !(lineCount > (page * 15))) && (page == 1 || !(lineCount < ((page - 1) * 15)))) {
						if (!worldSent) { 
							placeHolders[0] = world.getName();
							if (!(lineCount > (page * 15)) && (page == 1 || !(lineCount < ((page - 1) * 15)))) {
								LanguageAPI.getLang(false).sendLangMessage("commands.list.worldHeader", sender, placeHolders);
								lineCount++;
								worldSent = true;
							}
						}
						placeHolders[3] = itemMap.getConfigName();
						placeHolders[4] = itemMap.getConfigName();
						inputListed.add(itemMap.getConfigName());
						LanguageAPI.getLang(false).sendLangMessage("commands.list.itemRow", sender, placeHolders);
						lineCount++;
					} else { lineCount++; }
					itemFound = true;
				}
			}
			if (!itemFound) {
				LanguageAPI.getLang(false).sendLangMessage("commands.list.noItems", sender);
				lineCount++;
			}
			}
		}
		if (page != maxPage) { LanguageAPI.getLang(false).dispatchMessage(sender, "&aType &a&l/ItemJoin List " + (page + 1) + " &afor the next page.", "&eClick to View the Next Page.", "/itemjoin list " + (page + 1), ClickAction.RUN_COMMAND); }
		LanguageAPI.getLang(false).dispatchMessage(sender, "&a&l&m]----------------&a&l[&e List Menu " + page + "/" + maxPage + " &a&l]&a&l&m---------------[");
	}
	
   /**
	* Called when the CommandSender executes the Permisisons command.
	* @param sender - Source of the command. 
	* @param page - The page number to be displayed.
	* 
	*/
	private void permissions(final CommandSender sender, final int page) {
		LanguageAPI.getLang(false).dispatchMessage(sender, "&a&l&m]------------------&a&l[&e ItemJoin &a&l]&a&l&m-----------------[");
		int maxPage = ConfigHandler.getConfig().getPermissionPages();
		if (page == 1) {
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.*") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.*");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.all") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.All");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.use") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Use");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.reload") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Reload");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.updates") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Updates");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.upgrade") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Upgrade");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.permissions") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Permissions");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.query") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Query");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.get") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Get");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.remove") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Remove");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.enable") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Enable");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.disable") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Disable");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.get.others") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Get.Others");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.remove.others") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Remove.Others");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.enable.others") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Enable.Others");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.disable.others") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Disable.Others");
			LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin.bypass.inventorymodify") ? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin.Bypass.InventoryModify");
			for (World world: Bukkit.getWorlds()) { 
				LanguageAPI.getLang(false).dispatchMessage(sender, (PermissionsHandler.hasPermission(sender, "itemjoin." + world.getName()  + ".*")
					&& ((ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items-OP") && sender.isOp() 
							? sender.isPermissionSet("itemjoin." + world.getName() + ".*") : !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items-OP"))
					||  (ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items") && !sender.isOp() 
							? sender.isPermissionSet("itemjoin." + world.getName() + ".*") : !ConfigHandler.getConfig().getFile("config.yml").getBoolean("Permissions.Obtain-Items")))
				? "&a[\u2714]" : "&c[\u2718]") + " ItemJoin." + world.getName() + ".*"); 
			}
		} else if (page != 0) {
			List < String > customPermissions = new ArrayList < String > ();
			List < String > inputMessage = new ArrayList < String > ();
			for (World world: Bukkit.getServer().getWorlds()) {
				final ItemMap probable = ChanceAPI.getChances().getRandom(((Player) sender));
				for (ItemMap item: ItemUtilities.getUtilities().getItems()) {
					if ((item.getPermissionNode() != null ? !customPermissions.contains(item.getPermissionNode()) : true) && item.inWorld(world) && ChanceAPI.getChances().isProbability(item, probable)) {
						if (item.getPermissionNode() != null) { customPermissions.add(item.getPermissionNode()); }
						if (item.hasPermission(((Player) sender), world)) {
							inputMessage.add("&a[\u2714] " + PermissionsHandler.customPermissions(item.getPermissionNode(), item.getConfigName(), world.getName()));
						} else {
							inputMessage.add("&c[\u2718] " + PermissionsHandler.customPermissions(item.getPermissionNode(), item.getConfigName(), world.getName()));
						}
					}
				}
			}
			for (int i = (page == 2 ? 0 : ((page - 2) * 15) + 1); i <= ((page - 1) * 15 <= inputMessage.size() ? (page - 1) * 15 : (inputMessage.size() - 1)); i++) {
				LanguageAPI.getLang(false).dispatchMessage(sender, inputMessage.get(i));
			}
		}
		if (page != maxPage) { LanguageAPI.getLang(false).dispatchMessage(sender, "&aType &a&l/ItemJoin Permissions " + (page + 1) + " &afor the next page.", "&eClick to View the Next Page.", "/itemjoin permissions " + (page + 1), ClickAction.RUN_COMMAND); }
		LanguageAPI.getLang(false).dispatchMessage(sender, "&a&l&m]------------&a&l[&e Permissions Menu " + page + "/" + maxPage + " &a&l]&a&l&m-----------[");
	}
	
   /**
	* Called when the CommandSender executes the Purge command.
	* @param sender - Source of the command. 
	* @param table - The table being purged of data.
	* @param args - The player name having their data purged.
	* 
	*/
	private HashMap < String, Boolean > confirmationRequests = new HashMap < String, Boolean > ();
	private void purge(final CommandSender sender, final String table, final String args) {
		String[] placeHolders = LanguageAPI.getLang(false).newString(); placeHolders[1] = args; placeHolders[10] = table; 
		OfflinePlayer foundPlayer = null;
		if (!table.equalsIgnoreCase("Database")) { 
			placeHolders[9] = "/ij purge " + table + (table.equalsIgnoreCase("map-ids") ? " <image>" : " <player>"); 
			if (!table.equalsIgnoreCase("map-ids")) { foundPlayer = LegacyAPI.getOfflinePlayer(args); }
			if (!table.equalsIgnoreCase("map-ids") && foundPlayer == null && !args.equalsIgnoreCase("ALL")) { LanguageAPI.getLang(false).sendLangMessage("commands.default.noTarget", sender, placeHolders); return; } 
		} else { placeHolders[9] = "/ij purge"; }
		if (this.confirmationRequests.get(table + sender.getName()) != null && this.confirmationRequests.get(table + sender.getName()).equals(true)) {
			if (!table.equalsIgnoreCase("Database")) { 
				PlayerHandler.getPlayerID(PlayerHandler.getPlayerString(args));
				DataObject dataObject = (table.replace("-", "_").equalsIgnoreCase("map_ids") 