//# 9 errors, 1,617 messages
//#
/*
    //#PluginManager.java:1:1: class: com.dmdirc.plugins.PluginManager
    //#PluginManager.java:1:1: method: com.dmdirc.plugins.PluginManager.com.dmdirc.plugins.PluginManager__static_init
 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.dmdirc.plugins;

import com.dmdirc.Main;
import com.dmdirc.actions.ActionManager;
import com.dmdirc.actions.CoreActionType;
import com.dmdirc.actions.interfaces.ActionType;
import com.dmdirc.config.IdentityManager;
import com.dmdirc.config.prefs.PreferencesManager;
import com.dmdirc.interfaces.ActionListener;
import com.dmdirc.logger.Logger;
import com.dmdirc.logger.ErrorLevel;
import com.dmdirc.updater.components.PluginComponent;

import java.io.File;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

/**
 * Searches for and manages plugins and services.
 *
 * @author shane
 * @author chris
 */
public class PluginManager implements ActionListener {

    /** List of known plugins' file names to their corresponding {@link PluginInfo} objects. */
	private final Map<String, PluginInfo> knownPlugins = new Hashtable<String, PluginInfo>();

	/** Directory where plugins are stored. */
	private final String myDir;

	/** Singleton instance of the plugin manager. */
	private static PluginManager me;

	/** Map of services. */
	private final Map<String, Map<String, Service>> services = new HashMap<String, Map<String, Service>>();
	
	/**
	 * Creates a new instance of PluginManager.
	 */
	private PluginManager() {
    //#PluginManager.java:69: method: void com.dmdirc.plugins.PluginManager.com.dmdirc.plugins.PluginManager()
    //#input(void com.dmdirc.plugins.PluginManager()): "plugins"._tainted
    //#input(void com.dmdirc.plugins.PluginManager()): com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED
    //#input(void com.dmdirc.plugins.PluginManager()): com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED
    //#input(void com.dmdirc.plugins.PluginManager()): this
    //#output(void com.dmdirc.plugins.PluginManager()): java.lang.StringBuilder:toString(...)._tainted
    //#output(void com.dmdirc.plugins.PluginManager()): new HashMap(PluginManager#2) num objects
    //#output(void com.dmdirc.plugins.PluginManager()): new Hashtable(PluginManager#1) num objects
    //#output(void com.dmdirc.plugins.PluginManager()): this.knownPlugins
    //#output(void com.dmdirc.plugins.PluginManager()): this.myDir
    //#output(void com.dmdirc.plugins.PluginManager()): this.services
    //#new obj(void com.dmdirc.plugins.PluginManager()): java.lang.StringBuilder:toString(...)
    //#new obj(void com.dmdirc.plugins.PluginManager()): new HashMap(PluginManager#2)
    //#new obj(void com.dmdirc.plugins.PluginManager()): new Hashtable(PluginManager#1)
    //#presumption(void com.dmdirc.plugins.PluginManager()): init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED)
    //#presumption(void com.dmdirc.plugins.PluginManager()): init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED)
    //#post(void com.dmdirc.plugins.PluginManager()): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(void com.dmdirc.plugins.PluginManager()): this.knownPlugins == &new Hashtable(PluginManager#1)
    //#post(void com.dmdirc.plugins.PluginManager()): this.myDir == &java.lang.StringBuilder:toString(...)
    //#post(void com.dmdirc.plugins.PluginManager()): this.services == &new HashMap(PluginManager#2)
    //#post(void com.dmdirc.plugins.PluginManager()): new HashMap(PluginManager#2) num objects == 1
    //#post(void com.dmdirc.plugins.PluginManager()): new Hashtable(PluginManager#1) num objects == 1
		final String fs = System.getProperty("file.separator");
		myDir = Main.getConfigDir() + "plugins" + fs;
    //#PluginManager.java:71: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.Main:getConfigDir()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void com.dmdirc.plugins.PluginManager()
    //#    unanalyzed callee: String com.dmdirc.Main:getConfigDir()
		ActionManager.addListener(this, CoreActionType.CLIENT_PREFS_OPENED, CoreActionType.CLIENT_PREFS_CLOSED);
    //#PluginManager.java:72: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.actions.ActionManager:addListener(ActionListener, ActionType[])
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void com.dmdirc.plugins.PluginManager()
    //#    unanalyzed callee: void com.dmdirc.actions.ActionManager:addListener(ActionListener, ActionType[])
	}
    //#PluginManager.java:73: end of method: void com.dmdirc.plugins.PluginManager.com.dmdirc.plugins.PluginManager()
	
	/**
	 * Get a service object for the given name/type if one exists.
	 *
	 * @param type Type of this service
	 * @param name Name of this service
	 * @return The service requested, or null if service wasn't found and create wasn't specifed
	 */
	public Service getService(final String type, final String name) {
		return getService(type, name, false);
    //#PluginManager.java:83: method: Service com.dmdirc.plugins.PluginManager.getService(String, String)
    //#input(Service getService(String, String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(Service getService(String, String)): __Descendant_Table[others]
    //#input(Service getService(String, String)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;Z)Lcom/dmdirc/plugins/Service;
    //#input(Service getService(String, String)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(Service getService(String, String)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(Service getService(String, String)): name
    //#input(Service getService(String, String)): this
    //#input(Service getService(String, String)): this.__Tag
    //#input(Service getService(String, String)): this.services
    //#input(Service getService(String, String)): type
    //#output(Service getService(String, String)): new ArrayList(Service#1) num objects
    //#output(Service getService(String, String)): new Service(getService#1*) num objects
    //#output(Service getService(String, String)): new Service(getService#1*).__Tag
    //#output(Service getService(String, String)): new Service(getService#1*).name
    //#output(Service getService(String, String)): new Service(getService#1*).serviceproviders
    //#output(Service getService(String, String)): new Service(getService#1*).type
    //#output(Service getService(String, String)): new Service(getService#3*) num objects
    //#output(Service getService(String, String)): new Service(getService#3*).__Tag
    //#output(Service getService(String, String)): new Service(getService#3*).name
    //#output(Service getService(String, String)): new Service(getService#3*).serviceproviders
    //#output(Service getService(String, String)): new Service(getService#3*).type
    //#output(Service getService(String, String)): return_value
    //#new obj(Service getService(String, String)): new ArrayList(Service#1)
    //#new obj(Service getService(String, String)): new Service(getService#1*)
    //#new obj(Service getService(String, String)): new Service(getService#3*)
    //#pre[3] (Service getService(String, String)): this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[4] (Service getService(String, String)): this.services != null
    //#post(Service getService(String, String)): init'ed(return_value)
    //#post(Service getService(String, String)): new ArrayList(Service#1) num objects == 0
    //#post(Service getService(String, String)): new Service(getService#1*) num objects == 0
    //#post(Service getService(String, String)): new Service(getService#3*) num objects == 0
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#1*).__Tag)
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#3*).__Tag)
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#1*).name)
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#3*).name)
    //#post(Service getService(String, String)): init'ed(new Service(getService#1*).serviceproviders)
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#1*).type)
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#3*).type)
    //#post(Service getService(String, String)): not_init'ed(new Service(getService#3*).serviceproviders)
    //#unanalyzed(Service getService(String, String)): Effects-of-calling:java.util.HashMap
    //#unanalyzed(Service getService(String, String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(Service getService(String, String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(Service getService(String, String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(Service getService(String, String)): Effects-of-calling:java.util.Map:put
    //#PluginManager.java:83: end of method: Service com.dmdirc.plugins.PluginManager.getService(String, String)
	}
	
	/**
	 * Get a service object for the given name/type.
	 *
	 * @param type Type of this service
	 * @param name Name of this service
	 * @param create If the requested service doesn't exist, should it be created?
	 * @return The service requested, or null if service wasn't found and create wasn't specifed
	 */
	public Service getService(final String type, final String name, final boolean create) {
		// Find the type first
		if (services.containsKey(type)) {
    //#PluginManager.java:96: method: Service com.dmdirc.plugins.PluginManager.getService(String, String, bool)
    //#input(Service getService(String, String, bool)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(Service getService(String, String, bool)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(Service getService(String, String, bool)): create
    //#input(Service getService(String, String, bool)): name
    //#input(Service getService(String, String, bool)): this
    //#input(Service getService(String, String, bool)): this.services
    //#input(Service getService(String, String, bool)): type
    //#output(Service getService(String, String, bool)): new ArrayList(Service#1) num objects
    //#output(Service getService(String, String, bool)): new Service(getService#1) num objects
    //#output(Service getService(String, String, bool)): new Service(getService#1).__Tag
    //#output(Service getService(String, String, bool)): new Service(getService#1).name
    //#output(Service getService(String, String, bool)): new Service(getService#1).serviceproviders
    //#output(Service getService(String, String, bool)): new Service(getService#1).type
    //#output(Service getService(String, String, bool)): new Service(getService#3) num objects
    //#output(Service getService(String, String, bool)): new Service(getService#3).__Tag
    //#output(Service getService(String, String, bool)): new Service(getService#3).name
    //#output(Service getService(String, String, bool)): new Service(getService#3).serviceproviders
    //#output(Service getService(String, String, bool)): new Service(getService#3).type
    //#output(Service getService(String, String, bool)): return_value
    //#new obj(Service getService(String, String, bool)): new ArrayList(Service#1)
    //#new obj(Service getService(String, String, bool)): new Service(getService#1)
    //#new obj(Service getService(String, String, bool)): new Service(getService#3)
    //#pre[4] (Service getService(String, String, bool)): this.services != null
    //#presumption(Service getService(String, String, bool)): java.util.Map:get(...).__Tag@100 == com/dmdirc/plugins/Service
    //#presumption(Service getService(String, String, bool)): java.util.Map:get(...)@97 != null
    //#post(Service getService(String, String, bool)): init'ed(return_value)
    //#post(Service getService(String, String, bool)): new ArrayList(Service#1) num objects <= 1
    //#post(Service getService(String, String, bool)): new Service(getService#1) num objects <= 1
    //#post(Service getService(String, String, bool)): new Service(getService#1).__Tag == com/dmdirc/plugins/Service
    //#post(Service getService(String, String, bool)): new Service(getService#1).name == name
    //#post(Service getService(String, String, bool)): init'ed(new Service(getService#1).name)
    //#post(Service getService(String, String, bool)): init'ed(new Service(getService#1).serviceproviders)
    //#post(Service getService(String, String, bool)): new Service(getService#1).type == type
    //#post(Service getService(String, String, bool)): init'ed(new Service(getService#1).type)
    //#post(Service getService(String, String, bool)): new Service(getService#3) num objects <= 1
    //#post(Service getService(String, String, bool)): new Service(getService#3).__Tag == com/dmdirc/plugins/Service
    //#post(Service getService(String, String, bool)): new Service(getService#3).name == name
    //#post(Service getService(String, String, bool)): init'ed(new Service(getService#3).name)
    //#post(Service getService(String, String, bool)): new Service(getService#3).serviceproviders == &new ArrayList(Service#1)
    //#post(Service getService(String, String, bool)): new Service(getService#3).type == type
    //#post(Service getService(String, String, bool)): init'ed(new Service(getService#3).type)
    //#unanalyzed(Service getService(String, String, bool)): Effects-of-calling:java.util.ArrayList
    //#test_vector(Service getService(String, String, bool)): create: {0}, {1}
    //#test_vector(Service getService(String, String, bool)): java.util.Map:containsKey(...)@96: {0}, {1}
    //#test_vector(Service getService(String, String, bool)): java.util.Map:containsKey(...)@99: {0}, {1}
			final Map<String, Service> map = services.get(type);
			// Now the name
			if (map.containsKey(name)) {
				return map.get(name);
			} else if (create) {
				final Service service = new Service(type, name);
				map.put(name, service);
				return service;
			}
		} else if (create) {
			final Map<String, Service> map = new HashMap<String, Service>();
			final Service service = new Service(type, name);
			map.put(name, service);
			services.put(type, map);
			return service;
		}
		
		return null;
    //#PluginManager.java:114: end of method: Service com.dmdirc.plugins.PluginManager.getService(String, String, bool)
	}
	
	/**
	 * Get a ServiceProvider object for the given name/type if one exists.
	 *
	 * @param type Type of this service
	 * @param name Name of this service
	 * @return A ServiceProvider that provides the requested service.
	 * @throws NoSuchProviderException If no provider exists for the requested service
	 */
	public ServiceProvider getServiceProvider(final String type, final String name) throws NoSuchProviderException {
		final Service service = getService(type, name);
    //#PluginManager.java:126: method: ServiceProvider com.dmdirc.plugins.PluginManager.getServiceProvider(String, String)
    //#input(ServiceProvider getServiceProvider(String, String)): "->"._tainted
    //#input(ServiceProvider getServiceProvider(String, String)): "No provider found for: "._tainted
    //#input(ServiceProvider getServiceProvider(String, String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(ServiceProvider getServiceProvider(String, String)): __Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, String)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/Service;
    //#input(ServiceProvider getServiceProvider(String, String)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;Z)Lcom/dmdirc/plugins/Service;
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.activateServices()V
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isActive()Z
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPlugin()V
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/Service.__Dispatch_Table.activate()Z
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/Service.__Dispatch_Table.getActiveProvider()Lcom/dmdirc/plugins/ServiceProvider;
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/Service.__Dispatch_Table.getProviders()Ljava/util/List;
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/Service.__Dispatch_Table.isActive()Z
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[com/dmdirc/plugins/ServiceProvider]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.activateServices()V
    //#input(ServiceProvider getServiceProvider(String, String)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.isActive()Z
    //#input(ServiceProvider getServiceProvider(String, String)): name
    //#input(ServiceProvider getServiceProvider(String, String)): name._tainted
    //#input(ServiceProvider getServiceProvider(String, String)): this
    //#input(ServiceProvider getServiceProvider(String, String)): this.__Tag
    //#input(ServiceProvider getServiceProvider(String, String)): this.services
    //#input(ServiceProvider getServiceProvider(String, String)): type
    //#input(ServiceProvider getServiceProvider(String, String)): type._tainted
    //#output(ServiceProvider getServiceProvider(String, String)): return_value
    //#pre[4] (ServiceProvider getServiceProvider(String, String)): this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[5] (ServiceProvider getServiceProvider(String, String)): this.services != null
    //#presumption(ServiceProvider getServiceProvider(String, String)): service.__Tag@126 == com/dmdirc/plugins/Service
    //#post(ServiceProvider getServiceProvider(String, String)): return_value != null
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.HashMap
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.Map:put
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.lang.RuntimeException
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:updateProvides
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:checkRequirements
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:loadRequired
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:onLoad
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:getName
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.lang.Throwable:getMessage
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:addError
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:unloadPlugin
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:getMainClass
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:loadClass
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:loadPlugin
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:isActive
    //#unanalyzed(ServiceProvider getServiceProvider(String, String)): Effects-of-calling:activateServices
		if (service != null) {
			ServiceProvider provider = service.getActiveProvider();
    //#PluginManager.java:128: ?use of default init
    //#    init'ed(service.__Tag)
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ServiceProvider getServiceProvider(String, String)
    //#    basic block: bb_2
    //#    assertion: init'ed(service.__Tag)
    //#    VN: service.__Tag
    //#    Expected: {-Inf..+Inf}
    //#    Bad: {Invalid}
    //#    Attribs:  Int  Bad only invalid  Uncertain
    //#PluginManager.java:128: ?precondition failure
    //#    com/dmdirc/plugins/Service.getActiveProvider: init'ed(this.serviceproviders)
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ServiceProvider getServiceProvider(String, String)
    //#    basic block: bb_2
    //#    assertion: init'ed(service.serviceproviders)
    //#    callee: ServiceProvider com/dmdirc/plugins/Service.getActiveProvider()
    //#    callee assertion: init'ed(this.serviceproviders)
    //#    callee file: Service.java
    //#    callee precondition index: [3]
    //#    callee srcpos: 102
    //#    VN: service.serviceproviders
    //#    Expected: Univ-VN-Set
    //#    Bad: {Invalid}
    //#    Attribs:  Ptr  Bad only invalid
			if (provider != null) {
				return provider;
			} else {
				// Try to activate the service then try again.
				service.activate();
				provider = service.getActiveProvider();
				if (provider != null) {
					return provider;
				}
			}
		}
		
		throw new NoSuchProviderException("No provider found for: "+type+"->"+name);
    //#PluginManager.java:141: ?conditional throw
    //#    service != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ServiceProvider getServiceProvider(String, String)
    //#    basic block: Entry_BB_1
    //#    assertion: service != null
    //#    VN: getService(...) == null
    //#    Expected: {-Inf..0, 2..+Inf}
    //#    Bad: {1}
    //#    Attribs:  Int  Bad singleton  Bad overlaps +/-1000  Bad > Exp
    //#PluginManager.java:141: ?conditional throw
    //#    provider != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ServiceProvider getServiceProvider(String, String)
    //#    basic block: bb_4
    //#    assertion: provider != null
    //#    VN: getActiveProvider(...) == null
    //#    Expected: {-Inf..0, 2..+Inf}
    //#    Bad: {1}
    //#    Attribs:  Int  Bad singleton  Bad overlaps +/-1000  Bad > Exp
    //#PluginManager.java:141: end of method: ServiceProvider com.dmdirc.plugins.PluginManager.getServiceProvider(String, String)
	}
	
	/**
	 * Get a ServiceProvider object for the given tpye, prioritising those in the list of names.
	 *
	 * @param type Type to look for
	 * @param names Names to look for
	 * @param fallback Fallback to the first provider of type that exists if one from the list is not found.
	 * @return A ServiceProvider that provides the requested service.
	 * @throws NoSuchProviderException If no provider exists for the requested service and fallback is false, or no providers exist at all.
	 */
	public ServiceProvider getServiceProvider(final String type, final List<String> names, final boolean fallback) throws NoSuchProviderException {
		for (final String name : names) {
    //#PluginManager.java:154: method: ServiceProvider com.dmdirc.plugins.PluginManager.getServiceProvider(String, List, bool)
    //#input(ServiceProvider getServiceProvider(String, List, bool)): "->"._tainted
    //#input(ServiceProvider getServiceProvider(String, List, bool)): "No provider found for "._tainted
    //#input(ServiceProvider getServiceProvider(String, List, bool)): "No provider found for: "._tainted
    //#input(ServiceProvider getServiceProvider(String, List, bool)): "from the given list"._tainted
    //#input(ServiceProvider getServiceProvider(String, List, bool)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): __Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/Service;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;Z)Lcom/dmdirc/plugins/Service;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): __Dispatch_Table.getServiceProvider(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/ServiceProvider;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): __Dispatch_Table.getServicesByType(Ljava/lang/String;)Ljava/util/List;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.activateServices()V
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isActive()Z
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPlugin()V
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Dispatch_Table.activate()Z
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Dispatch_Table.getActiveProvider()Lcom/dmdirc/plugins/ServiceProvider;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Dispatch_Table.getProviders()Ljava/util/List;
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/Service.__Dispatch_Table.isActive()Z
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[com/dmdirc/plugins/ServiceProvider]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[others]
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.activateServices()V
    //#input(ServiceProvider getServiceProvider(String, List, bool)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.isActive()Z
    //#input(ServiceProvider getServiceProvider(String, List, bool)): fallback
    //#input(ServiceProvider getServiceProvider(String, List, bool)): names
    //#input(ServiceProvider getServiceProvider(String, List, bool)): this
    //#input(ServiceProvider getServiceProvider(String, List, bool)): this.__Tag
    //#input(ServiceProvider getServiceProvider(String, List, bool)): this.services
    //#input(ServiceProvider getServiceProvider(String, List, bool)): type
    //#input(ServiceProvider getServiceProvider(String, List, bool)): type._tainted
    //#output(ServiceProvider getServiceProvider(String, List, bool)): return_value
    //#pre[2] (ServiceProvider getServiceProvider(String, List, bool)): names != null
    //#pre[4] (ServiceProvider getServiceProvider(String, List, bool)): this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[1] (ServiceProvider getServiceProvider(String, List, bool)): (soft) fallback == 1
    //#pre[5] (ServiceProvider getServiceProvider(String, List, bool)): (soft) this.services != null
    //#presumption(ServiceProvider getServiceProvider(String, List, bool)): java.util.List:get(...).__Tag@164 == com/dmdirc/plugins/Service
    //#presumption(ServiceProvider getServiceProvider(String, List, bool)): java.util.List:get(...)@164 != null
    //#presumption(ServiceProvider getServiceProvider(String, List, bool)): java.util.List:size(...)@163 >= 1
    //#post(ServiceProvider getServiceProvider(String, List, bool)): return_value != null
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.HashMap
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.Map:values
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.Map:put
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.lang.RuntimeException
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:updateProvides
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:checkRequirements
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:loadRequired
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:onLoad
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:getName
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.lang.Throwable:getMessage
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:addError
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:unloadPlugin
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:getMainClass
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:loadClass
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:loadPlugin
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:getService
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:isActive
    //#unanalyzed(ServiceProvider getServiceProvider(String, List, bool)): Effects-of-calling:activateServices
    //#test_vector(ServiceProvider getServiceProvider(String, List, bool)): java.util.Iterator:hasNext(...)@154: {0}, {1}
			final ServiceProvider provider = getServiceProvider(type, name);
			if (provider != null) {
    //#PluginManager.java:156: Warning: test always goes same way
    //#    Test predetermined because provider != null
    //#    severity: LOW
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ServiceProvider getServiceProvider(String, List, bool)
    //#    from bb: bb_3
    //#    live edge: bb_3-->bb_4
    //#    tested vn: getServiceProvider(...) == null
    //#    tested vn values: {0}
				return provider;
			}
		}
    //#PluginManager.java:159: Warning: dead code
    //#    Dead code here because provider != null
    //#    severity: LOW
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ServiceProvider getServiceProvider(String, List, bool)
    //#    dead bb: bb_5
		
		if (fallback) {
			final List<Service> servicesType = getServicesByType(type);
			if (servicesType.size() > 0) {
				final Service service = servicesType.get(0);
				return getServiceProvider(type, service.getName());
			}
		}
		
		throw new NoSuchProviderException("No provider found for "+type+ "from the given list");
    //#PluginManager.java:169: end of method: ServiceProvider com.dmdirc.plugins.PluginManager.getServiceProvider(String, List, bool)
	}
	
	/**
	 * Get an ExportedService object of the given name from any provider that provides it.
	 * This is the same as doing getServiceProvider("export", name).getExportedService(name)
	 *
	 * @param name Name of this service
	 * @return An ExportedService object.
	 * @throws NoSuchProviderException If no provider exists for the requested service.
	 */
	public ExportedService getExportedService(final String name) {
		return getServiceProvider("export", name).getExportedService(name);
    //#PluginManager.java:181: method: ExportedService com.dmdirc.plugins.PluginManager.getExportedService(String)
    //#PluginManager.java:181: ?use of default init
    //#    init'ed(getServiceProvider(...).__Tag)
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ExportedService getExportedService(String)
    //#    basic block: Entry_BB_1
    //#    assertion: init'ed(getServiceProvider(...).__Tag)
    //#    VN: getServiceProvider(...).__Tag
    //#    Expected: {-Inf..+Inf}
    //#    Bad: {Invalid}
    //#    Attribs:  Int  Bad only invalid
    //#PluginManager.java:181: ?null dereference
    //#    com/dmdirc/plugins/ServiceProvider.__Descendant_Table[getServiceProvider(...).__Tag] != null
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: ExportedService getExportedService(String)
    //#    basic block: Entry_BB_1
    //#    assertion: com/dmdirc/plugins/ServiceProvider.__Descendant_Table[getServiceProvider(...).__Tag] != null
    //#    VN: com/dmdirc/plugins/ServiceProvider.__Descendant_Table[getServiceProvider(...).__Tag]
    //#    Expected: Inverse{null}
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
    //#input(ExportedService getExportedService(String)): ""._tainted
    //#input(ExportedService getExportedService(String)): "' (wanted by "._tainted
    //#input(ExportedService getExportedService(String)): ") -> "._tainted
    //#input(ExportedService getExportedService(String)): ") does not exist."._tainted
    //#input(ExportedService getExportedService(String)): "->"._tainted
    //#input(ExportedService getExportedService(String)): "-resourcemanagerTimer"._tainted
    //#input(ExportedService getExportedService(String)): ".class"._tainted
    //#input(ExportedService getExportedService(String)): "Could not load "._tainted
    //#input(ExportedService getExportedService(String)): "Error loading '"._tainted
    //#input(ExportedService getExportedService(String)): "No provider found for: "._tainted
    //#input(ExportedService getExportedService(String)): "Resource '"._tainted
    //#input(ExportedService getExportedService(String)): "export"._tainted
    //#input(ExportedService getExportedService(String)): "jar:.."._tainted
    //#input(ExportedService getExportedService(String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(ExportedService getExportedService(String)): __Descendant_Table[others]
    //#input(ExportedService getExportedService(String)): __Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#input(ExportedService getExportedService(String)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/Service;
    //#input(ExportedService getExportedService(String)): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;Z)Lcom/dmdirc/plugins/Service;
    //#input(ExportedService getExportedService(String)): __Dispatch_Table.getServiceProvider(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/ServiceProvider;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ExportInfo.__Descendant_Table[com/dmdirc/plugins/ExportInfo]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ExportInfo.__Descendant_Table[others]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ExportInfo.__Dispatch_Table.getExportedService()Lcom/dmdirc/plugins/ExportedService;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/GlobalClassLoader.__Class_Obj.__Lock
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/GlobalClassLoader.me
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[com/dmdirc/plugins/PluginClassLoader]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[others]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.isClassLoaded(Ljava/lang/String;Z)Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.activateServices()V
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getClassList()Ljava/util/List;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getExportedService(Ljava/lang/String;)Lcom/dmdirc/plugins/ExportedService;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFullFilename()Ljava/lang/String;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getMainClass()Ljava/lang/String;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPersistentClasses()Ljava/util/List;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginClassLoader()Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginObject()Lcom/dmdirc/plugins/Plugin;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getResourceManager()Lcom/dmdirc/util/resourcemanager/ResourceManager;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getResourceManager(Z)Lcom/dmdirc/util/resourcemanager/ResourceManager;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isActive()Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent(Ljava/lang/String;)Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPlugin()V
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/Service.__Dispatch_Table.activate()Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/Service.__Dispatch_Table.getActiveProvider()Lcom/dmdirc/plugins/ServiceProvider;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/Service.__Dispatch_Table.getProviders()Ljava/util/List;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/Service.__Dispatch_Table.isActive()Z
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[com/dmdirc/plugins/ServiceProvider]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ServiceProvider.__Descendant_Table[others]
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.activateServices()V
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.getExportedService(Ljava/lang/String;)Lcom/dmdirc/plugins/ExportedService;
    //#input(ExportedService getExportedService(String)): com/dmdirc/plugins/ServiceProvider.__Dispatch_Table.isActive()Z
    //#input(ExportedService getExportedService(String)): name
    //#input(ExportedService getExportedService(String)): name._tainted
    //#input(ExportedService getExportedService(String)): this
    //#input(ExportedService getExportedService(String)): this.__Tag
    //#input(ExportedService getExportedService(String)): this.services
    //#output(ExportedService getExportedService(String)): com/dmdirc/plugins/GlobalClassLoader.me
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*) num objects
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*).__Tag
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*).myMethod
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*).myObject
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*) num objects
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*).__Tag
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*).myMethod
    //#output(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*).myObject
    //#output(ExportedService getExportedService(String)): new GlobalClassLoader(getGlobalClassLoader#1) num objects
    //#output(ExportedService getExportedService(String)): new GlobalClassLoader(getGlobalClassLoader#1).__Tag
    //#output(ExportedService getExportedService(String)): new GlobalClassLoader(getGlobalClassLoader#1).resourcesList
    //#output(ExportedService getExportedService(String)): new HashMap(GlobalClassLoader#1) num objects
    //#output(ExportedService getExportedService(String)): return_value
    //#new obj(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*)
    //#new obj(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*)
    //#new obj(ExportedService getExportedService(String)): new GlobalClassLoader(getGlobalClassLoader#1)
    //#new obj(ExportedService getExportedService(String)): new HashMap(GlobalClassLoader#1)
    //#pre[6] (ExportedService getExportedService(String)): this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[7] (ExportedService getExportedService(String)): this.services != null
    //#pre[4] (ExportedService getExportedService(String)): (soft) com/dmdirc/plugins/GlobalClassLoader.me != null
    //#presumption(ExportedService getExportedService(String)): getServiceProvider(...).exports@181 != null
    //#post(ExportedService getExportedService(String)): init'ed(com/dmdirc/plugins/GlobalClassLoader.me)
    //#post(ExportedService getExportedService(String)): return_value == One-of{&new ExportedService(getExportedService#1*), &new ExportedService(getExportedService#2*)}
    //#post(ExportedService getExportedService(String)): return_value in Addr_Set{&new ExportedService(getExportedService#1*),&new ExportedService(getExportedService#2*),&new ExportedService(getExportedService#1*)}
    //#post(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*) num objects <= 1
    //#post(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*).__Tag == com/dmdirc/plugins/ExportedService
    //#post(ExportedService getExportedService(String)): init'ed(new ExportedService(getExportedService#1*).myMethod)
    //#post(ExportedService getExportedService(String)): init'ed(new ExportedService(getExportedService#1*).myObject)
    //#post(ExportedService getExportedService(String)): new ExportedService(getExportedService#1*).myObject == null
    //#post(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*) num objects <= 1
    //#post(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*).__Tag == com/dmdirc/plugins/ExportedService
    //#post(ExportedService getExportedService(String)): init'ed(new ExportedService(getExportedService#2*).myMethod)
    //#post(ExportedService getExportedService(String)): new ExportedService(getExportedService#2*).myObject == null
    //#post(ExportedService getExportedService(String)): new GlobalClassLoader(getGlobalClassLoader#1) num objects == 0
    //#post(ExportedService getExportedService(String)): init'ed(new GlobalClassLoader(getGlobalClassLoader#1).__Tag)
    //#post(ExportedService getExportedService(String)): init'ed(new GlobalClassLoader(getGlobalClassLoader#1).resourcesList)
    //#post(ExportedService getExportedService(String)): new HashMap(GlobalClassLoader#1) num objects == 0
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.HashMap
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Map:put
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.RuntimeException
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getPluginInfos
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:updateProvides
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:checkRequirements
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:loadRequired
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:onLoad
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getName
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.Throwable:getMessage
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:addError
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:unloadPlugin
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getMainClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:loadClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:loadPlugin
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getPluginManager
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.net.URL:getPath
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getFullFilename
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getService
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:isActive
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:activateServices
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getPluginClassLoader
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getPluginObject
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.Class:getDeclaredMethods
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.reflect.Method:getName
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getResourceManager
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:findLoadedClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.plugins.GlobalClassLoader:findLoadedClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:getParent
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.String:replace
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:isPersistent
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:resourceExists
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourceManager
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourceBytes
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.plugins.GlobalClassLoader:defineClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.ClassLoader:loadClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Collection:iterator
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getClassList
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:getPersistentClasses
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.NoClassDefFoundError:getMessage
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.ClassNotFoundException
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:defineClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:resolveClass
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.String:matches
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Timer
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.TimerTask
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.util.Timer:schedule
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourcesStartingWith
    //#unanalyzed(ExportedService getExportedService(String)): Effects-of-calling:java.lang.String:replaceAll
    //#PluginManager.java:181: end of method: ExportedService com.dmdirc.plugins.PluginManager.getExportedService(String)
	}
	
	/**
	 * Get a List of all services of a specifed type.
	 *
	 * @param type Type of service
	 * @return The list of services requested.
	 */
	public List<Service> getServicesByType(final String type) {
		// Find the type first
		if (services.containsKey(type)) {
    //#PluginManager.java:192: method: List com.dmdirc.plugins.PluginManager.getServicesByType(String)
    //#input(List getServicesByType(String)): this
    //#input(List getServicesByType(String)): this.services
    //#input(List getServicesByType(String)): type
    //#output(List getServicesByType(String)): new ArrayList(getServicesByType#1) num objects
    //#output(List getServicesByType(String)): new ArrayList(getServicesByType#2) num objects
    //#output(List getServicesByType(String)): return_value
    //#new obj(List getServicesByType(String)): new ArrayList(getServicesByType#1)
    //#new obj(List getServicesByType(String)): new ArrayList(getServicesByType#2)
    //#pre[2] (List getServicesByType(String)): this.services != null
    //#presumption(List getServicesByType(String)): java.util.Map:get(...)@193 != null
    //#post(List getServicesByType(String)): return_value in Addr_Set{&new ArrayList(getServicesByType#2),&new ArrayList(getServicesByType#1)}
    //#post(List getServicesByType(String)): new ArrayList(getServicesByType#1) num objects <= 1
    //#post(List getServicesByType(String)): new ArrayList(getServicesByType#2) num objects <= 1
    //#test_vector(List getServicesByType(String)): java.util.Map:containsKey(...)@192: {0}, {1}
			final Map<String, Service> map = services.get(type);
			return new ArrayList<Service>(map.values());
		}
		
		return new ArrayList<Service>();
    //#PluginManager.java:197: end of method: List com.dmdirc.plugins.PluginManager.getServicesByType(String)
	}
	
	/**
	 * Get a List of all services
	 *
	 * @return The list of all services.
	 */
	public List<Service> getAllServices() {
		// Find the type first
		final List<Service> allServices = new ArrayList<Service>();
    //#PluginManager.java:207: method: List com.dmdirc.plugins.PluginManager.getAllServices()
    //#input(List getAllServices()): this
    //#input(List getAllServices()): this.services
    //#output(List getAllServices()): new ArrayList(getAllServices#1) num objects
    //#output(List getAllServices()): return_value
    //#new obj(List getAllServices()): new ArrayList(getAllServices#1)
    //#pre[2] (List getAllServices()): this.services != null
    //#presumption(List getAllServices()): java.util.Iterator:next(...)@208 != null
    //#presumption(List getAllServices()): java.util.Map:values(...)@208 != null
    //#post(List getAllServices()): return_value == &new ArrayList(getAllServices#1)
    //#post(List getAllServices()): new ArrayList(getAllServices#1) num objects == 1
    //#test_vector(List getAllServices()): java.util.Iterator:hasNext(...)@208: {0}, {1}
		for (Map<String, Service> map : services.values()) {
			allServices.addAll(map.values());
		}
		
		return allServices;
    //#PluginManager.java:212: end of method: List com.dmdirc.plugins.PluginManager.getAllServices()
	}
	
	/**
	 * Autoloads plugins.
	 */
	public void doAutoLoad() {
		for (String plugin : IdentityManager.getGlobalConfig().getOptionList("plugins", "autoload")) {
    //#PluginManager.java:219: method: void com.dmdirc.plugins.PluginManager.doAutoLoad()
    //#PluginManager.java:219: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void doAutoLoad()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#PluginManager.java:219: Warning: method not available - call not analyzed
    //#    call on List com.dmdirc.config.ConfigManager:getOptionList(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void doAutoLoad()
    //#    unanalyzed callee: List com.dmdirc.config.ConfigManager:getOptionList(String, String)
    //#input(void doAutoLoad()): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(void doAutoLoad()): __Descendant_Table[others]
    //#input(void doAutoLoad()): __Dispatch_Table.getPluginInfo(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(void doAutoLoad()): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(void doAutoLoad()): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(void doAutoLoad()): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPlugin()V
    //#input(void doAutoLoad()): this
    //#input(void doAutoLoad()): this.__Tag
    //#input(void doAutoLoad()): this.knownPlugins
    //#pre[2] (void doAutoLoad()): (soft) this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[3] (void doAutoLoad()): (soft) this.knownPlugins != null
    //#presumption(void doAutoLoad()): com.dmdirc.config.ConfigManager:getOptionList(...)@219 != null
    //#presumption(void doAutoLoad()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@219 != null
    //#presumption(void doAutoLoad()): java.util.Iterator:next(...)@219 != null
    //#presumption(void doAutoLoad()): java.util.Map:get(...)@348 != null
    //#presumption(void doAutoLoad()): java.util.Map:get(...)@348.__Tag == com/dmdirc/plugins/PluginInfo
    //#unanalyzed(void doAutoLoad()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void doAutoLoad()): Effects-of-calling:java.lang.String:toLowerCase
    //#test_vector(void doAutoLoad()): java.lang.String:charAt(...)@221: {35}, {0..34, 36..65_535}
    //#test_vector(void doAutoLoad()): java.lang.String:isEmpty(...)@221: {1}, {0}
    //#test_vector(void doAutoLoad()): java.util.Iterator:hasNext(...)@219: {0}, {1}
    //#test_vector(void doAutoLoad()): java.util.Map:get(...)@348: Addr_Set{null}, Inverse{null}
			plugin = plugin.trim();
			if (!plugin.isEmpty() && plugin.charAt(0) != '#' && getPluginInfo(plugin) != null) {
				getPluginInfo(plugin).loadPlugin();
    //#PluginManager.java:222: Warning: call too complex - analysis skipped
    //#    call on void loadPlugin()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void doAutoLoad()
    //#    unanalyzed callee: void loadPlugin()
			}
		}
	}
    //#PluginManager.java:225: end of method: void com.dmdirc.plugins.PluginManager.doAutoLoad()

	/**
	 * Retrieves the singleton instance of the plugin manager.
	 *
	 * @return A singleton instance of PluginManager.
	 */
	public static final synchronized PluginManager getPluginManager() {
		if (me == null) {
    //#PluginManager.java:233: method: PluginManager com.dmdirc.plugins.PluginManager.getPluginManager()
    //#input(PluginManager getPluginManager()): "plugins"._tainted
    //#input(PluginManager getPluginManager()): __Class_Obj.__Lock
    //#input(PluginManager getPluginManager()): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(PluginManager getPluginManager()): __Descendant_Table[others]
    //#input(PluginManager getPluginManager()): __Dispatch_Table.getPossiblePluginInfos(Z)Ljava/util/List;
    //#input(PluginManager getPluginManager()): com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED
    //#input(PluginManager getPluginManager()): com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED
    //#input(PluginManager getPluginManager()): me
    //#input(PluginManager getPluginManager()): me.__Tag
    //#output(PluginManager getPluginManager()): java.lang.StringBuilder:toString(...)._tainted
    //#output(PluginManager getPluginManager()): me
    //#output(PluginManager getPluginManager()): new HashMap(PluginManager#2) num objects
    //#output(PluginManager getPluginManager()): new Hashtable(PluginManager#1) num objects
    //#output(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#output(PluginManager getPluginManager()): new PluginManager(getPluginManager#1) num objects
    //#output(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).__Tag
    //#output(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).knownPlugins
    //#output(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).myDir
    //#output(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).services
    //#output(PluginManager getPluginManager()): return_value
    //#new obj(PluginManager getPluginManager()): java.lang.StringBuilder:toString(...)
    //#new obj(PluginManager getPluginManager()): new HashMap(PluginManager#2)
    //#new obj(PluginManager getPluginManager()): new Hashtable(PluginManager#1)
    //#new obj(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1)
    //#new obj(PluginManager getPluginManager()): new PluginManager(getPluginManager#1)
    //#pre[1] (PluginManager getPluginManager()): init'ed(me)
    //#post(PluginManager getPluginManager()): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(PluginManager getPluginManager()): me == One-of{old me, &new PluginManager(getPluginManager#1)}
    //#post(PluginManager getPluginManager()): me != null
    //#post(PluginManager getPluginManager()): return_value == me
    //#post(PluginManager getPluginManager()): new HashMap(PluginManager#2) num objects <= 1
    //#post(PluginManager getPluginManager()): new Hashtable(PluginManager#1) num objects <= 1
    //#post(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1) num objects == undefined
    //#post(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1) num objects == 0, if init'ed
    //#post(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1).__Tag == new PluginClassLoader(getSubClassLoader#1) num objects
    //#post(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1).pluginInfo == undefined
    //#post(PluginManager getPluginManager()): new PluginClassLoader(getSubClassLoader#1).pluginInfo == null
    //#post(PluginManager getPluginManager()): new PluginManager(getPluginManager#1) num objects <= 1
    //#post(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).__Tag == com/dmdirc/plugins/PluginManager
    //#post(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).knownPlugins == &new Hashtable(PluginManager#1)
    //#post(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).myDir == &java.lang.StringBuilder:toString(...)
    //#post(PluginManager getPluginManager()): new PluginManager(getPluginManager#1).services == &new HashMap(PluginManager#2)
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:java.util.Hashtable
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:java.util.HashMap
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:java.lang.System:getProperty
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(PluginManager getPluginManager()): Effects-of-calling:com.dmdirc.actions.ActionManager:addListener
    //#test_vector(PluginManager getPluginManager()): me: Inverse{null}, Addr_Set{null}
			me = new PluginManager();
			me.getPossiblePluginInfos(true);
    //#PluginManager.java:235: Warning: call too complex - analysis skipped
    //#    call on List getPossiblePluginInfos(bool)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: PluginManager getPluginManager()
    //#    unanalyzed callee: List getPossiblePluginInfos(bool)
		}
		
		
		return me;
    //#PluginManager.java:239: end of method: PluginManager com.dmdirc.plugins.PluginManager.getPluginManager()
	}

	/**
	 * Tests and adds the specified plugin to the known plugins list. Plugins
	 * will only be added if: <ul><li>The file exists,<li>No other plugin with
	 * the same name is known,<li>All requirements are met for the plugin,
	 * <li>The plugin has a valid config file that can be read</ul>.
	 *
	 * @param filename Filename of Plugin jar
	 * @return True if the plugin is in the known plugins list (either before
	 * this invocation or as a result of it), false if it was not added for
	 * one of the reasons outlined above.
	 */
	public boolean addPlugin(final String filename) {
		if (knownPlugins.containsKey(filename.toLowerCase())) {
    //#PluginManager.java:254: method: bool com.dmdirc.plugins.PluginManager.addPlugin(String)
    //#input(bool addPlugin(String)): " is the same as "._tainted
    //#input(bool addPlugin(String)): " was not loaded, one or more requirements not met ("._tainted
    //#input(bool addPlugin(String)): "&#09;"._tainted
    //#input(bool addPlugin(String)): "&#10;Which caused: "._tainted
    //#input(bool addPlugin(String)): ")"._tainted
    //#input(bool addPlugin(String)): "-"._tainted
    //#input(bool addPlugin(String)): ".log"._tainted
    //#input(bool addPlugin(String)): ": "._tainted
    //#input(bool addPlugin(String)): ": File does not exist"._tainted
    //#input(bool addPlugin(String)): "A fatal error has occurred: "._tainted
    //#input(bool addPlugin(String)): "An error has occurred: "._tainted
    //#input(bool addPlugin(String)): "Date:"._tainted
    //#input(bool addPlugin(String)): "Description: "._tainted
    //#input(bool addPlugin(String)): "Duplicate Plugin detected, Ignoring. ("._tainted
    //#input(bool addPlugin(String)): "Error creating URL for plugin "._tainted
    //#input(bool addPlugin(String)): "Error loading plugin "._tainted
    //#input(bool addPlugin(String)): "ID must be a positive integer: "._tainted
    //#input(bool addPlugin(String)): "Level: "._tainted
    //#input(bool addPlugin(String)): "Plugin "._tainted
    //#input(bool addPlugin(String)): "errors"._tainted
    //#input(bool addPlugin(String)): "file:"._tainted
    //#input(bool addPlugin(String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(bool addPlugin(String)): __Descendant_Table[others]
    //#input(bool addPlugin(String)): __Dispatch_Table.getDirectory()Ljava/lang/String;
    //#input(bool addPlugin(String)): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(bool addPlugin(String)): __Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorLevel__static_init.new ErrorLevel(ErrorLevel__static_init#3)._tainted
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2).length
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[0..4_294_967_295]
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errors
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errors.__Lock
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportQueue
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(bool addPlugin(String)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(bool addPlugin(String)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(bool addPlugin(String)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorLevel.MEDIUM
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorManager.BANNED_EXCEPTIONS
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorManager.java.lang.System.err
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorManager.me
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(bool addPlugin(String)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(bool addPlugin(String)): com/dmdirc/logger/Logger.manager
    //#input(bool addPlugin(String)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(bool addPlugin(String)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(bool addPlugin(String)): com/dmdirc/logger/ProgramError.errorDir
    //#input(bool addPlugin(String)): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(bool addPlugin(String)): com/dmdirc/logger/ProgramError.writingSem
    //#input(bool addPlugin(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(bool addPlugin(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(bool addPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFilename()Ljava/lang/String;
    //#input(bool addPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(bool addPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool addPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getRequirementsError()Ljava/lang/String;
    //#input(bool addPlugin(String)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(bool addPlugin(String)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(bool addPlugin(String)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(bool addPlugin(String)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(bool addPlugin(String)): filename
    //#input(bool addPlugin(String)): filename._tainted
    //#input(bool addPlugin(String)): this
    //#input(bool addPlugin(String)): this.__Tag
    //#input(bool addPlugin(String)): this.knownPlugins
    //#input(bool addPlugin(String)): this.myDir
    //#input(bool addPlugin(String)): this.myDir._tainted
    //#output(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#output(bool addPlugin(String)): com/dmdirc/logger/ProgramError.errorDir
    //#output(bool addPlugin(String)): new ErrorReportingThread(sendError#1) num objects
    //#output(bool addPlugin(String)): new ErrorReportingThread(sendError#1).__Tag
    //#output(bool addPlugin(String)): new ErrorReportingThread(sendError#1).queue
    //#output(bool addPlugin(String)): new File(getErrorFile#1) num objects
    //#output(bool addPlugin(String)): return_value
    //#new obj(bool addPlugin(String)): new ErrorReportingThread(sendError#1)
    //#new obj(bool addPlugin(String)): new File(getErrorFile#1)
    //#pre[9] (bool addPlugin(String)): filename != null
    //#pre[16] (bool addPlugin(String)): this.knownPlugins != null
    //#pre[3] (bool addPlugin(String)): (soft) com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[0..4_294_967_295] != null
    //#pre[5] (bool addPlugin(String)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports)
    //#pre[6] (bool addPlugin(String)): (soft) com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID != null
    //#pre[7] (bool addPlugin(String)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports)
    //#pre[8] (bool addPlugin(String)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[12] (bool addPlugin(String)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#pre[13] (bool addPlugin(String)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[15] (bool addPlugin(String)): (soft) this.__Tag == com/dmdirc/plugins/PluginManager
    //#presumption(bool addPlugin(String)): java.lang.String:isEmpty(...)@273 == 1
    //#presumption(bool addPlugin(String)): pluginInfo.requirementsError@270 != null
    //#post(bool addPlugin(String)): com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &new File(getErrorFile#1)}
    //#post(bool addPlugin(String)): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(bool addPlugin(String)): init'ed(return_value)
    //#post(bool addPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread == old com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#post(bool addPlugin(String)): init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#post(bool addPlugin(String)): new ErrorReportingThread(sendError#1) num objects == 0
    //#post(bool addPlugin(String)): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(bool addPlugin(String)): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(bool addPlugin(String)): new File(getErrorFile#1) num objects <= 1
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Map:values
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Collection:iterator
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:getErrorManager
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:addError
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.plugins.PluginInfo
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Exception
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Date
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:isReady
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:errorAdded
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.File
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Throwable:getStackTrace
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Throwable:toString
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.StackTraceElement:toString
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Throwable:getCause
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:getTrace
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.Object:equals
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:equals
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:getReportStatus
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(bool addPlugin(String)): Effects-of-calling:java.util.Arrays:equals
    //#test_vector(bool addPlugin(String)): java.io.File:exists(...)@258: {1}, {0}
    //#test_vector(bool addPlugin(String)): java.util.Map:containsKey(...)@254: {0}, {1}
			return true;
		}
		
		if (!new File(getDirectory() + filename).exists()) {
			Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin " + filename + ": File does not exist");
			return false;
		}
		
		try {
			final PluginInfo pluginInfo = new PluginInfo(new URL("file:"+getDirectory()+filename));
			final PluginInfo existing = getPluginInfoByName(pluginInfo.getName());
			if (existing != null) {
				Logger.userError(ErrorLevel.MEDIUM, "Duplicate Plugin detected, Ignoring. (" + filename + " is the same as " + existing.getFilename() + ")");
    //#PluginManager.java:267: ?use of default init
    //#    init'ed(existing.__Tag)
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: bool addPlugin(String)
    //#    basic block: bb_7
    //#    assertion: init'ed(existing.__Tag)
    //#    VN: existing.__Tag
    //#    Expected: {-Inf..+Inf}
    //#    Bad: {Invalid}
    //#    Attribs:  Int  Bad only invalid
    //#PluginManager.java:267: ?null dereference
    //#    com/dmdirc/plugins/PluginInfo.__Descendant_Table[existing.__Tag] != null
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: bool addPlugin(String)
    //#    basic block: bb_7
    //#    assertion: com/dmdirc/plugins/PluginInfo.__Descendant_Table[existing.__Tag] != null
    //#    VN: com/dmdirc/plugins/PluginInfo.__Descendant_Table[existing.__Tag]
    //#    Expected: Inverse{null}
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
				return false;
			}
			new PluginComponent(pluginInfo);
    //#PluginManager.java:270: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.updater.components.PluginComponent(PluginInfo)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: bool addPlugin(String)
    //#    unanalyzed callee: void com.dmdirc.updater.components.PluginComponent(PluginInfo)
			
			final String requirements = pluginInfo.getRequirementsError();
			if (requirements.isEmpty()) {
				knownPlugins.put(filename.toLowerCase(), pluginInfo);
			
				return true;
			} else {
				throw new PluginException("Plugin "+filename+" was not loaded, one or more requirements not met ("+requirements+")");
			}
		} catch (MalformedURLException mue) {
			Logger.userError(ErrorLevel.MEDIUM, "Error creating URL for plugin " + filename + ": " + mue.getMessage(), mue);
		} catch (PluginException e) {
			Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin " + filename + ": " + e.getMessage(), e);
    //#PluginManager.java:283: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.plugins.PluginException:getMessage()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: bool addPlugin(String)
    //#    unanalyzed callee: String com.dmdirc.plugins.PluginException:getMessage()
		}
		
		return false;
    //#PluginManager.java:286: end of method: bool com.dmdirc.plugins.PluginManager.addPlugin(String)
	}

	/**
	 * Remove a plugin.
	 *
	 * @param filename Filename of Plugin jar
	 * @return True if removed.
	 */
	public boolean delPlugin(final String filename) {
		if (!knownPlugins.containsKey(filename.toLowerCase())) {
    //#PluginManager.java:296: method: bool com.dmdirc.plugins.PluginManager.delPlugin(String)
    //#input(bool delPlugin(String)): " - "._tainted
    //#input(bool delPlugin(String)): ""._tainted
    //#input(bool delPlugin(String)): ":"._tainted
    //#input(bool delPlugin(String)): "Error in onUnload for "._tainted
    //#input(bool delPlugin(String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(bool delPlugin(String)): __Descendant_Table[others]
    //#input(bool delPlugin(String)): __Dispatch_Table.getPluginInfo(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(bool delPlugin(String)): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(bool delPlugin(String)): com/dmdirc/logger/ErrorLevel.MEDIUM
    //#input(bool delPlugin(String)): com/dmdirc/logger/Logger.manager
    //#input(bool delPlugin(String)): com/dmdirc/plugins/Plugin.__Descendant_Table[com/dmdirc/plugins/Plugin]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/Plugin.__Descendant_Table[others]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/Plugin.__Dispatch_Table.onUnload()V
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[com/dmdirc/plugins/PluginClassLoader]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[others]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.getSubClassLoader(Lcom/dmdirc/plugins/PluginInfo;)Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.delChild(Lcom/dmdirc/plugins/PluginInfo;)V
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginClassLoader()Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isTempLoaded()Z
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isUnloadable()Z
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.unloadPlugin()V
    //#input(bool delPlugin(String)): com/dmdirc/plugins/PluginInfo.com.dmdirc.actions.CoreActionType.PLUGIN_UNLOADED
    //#input(bool delPlugin(String)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(bool delPlugin(String)): com/dmdirc/plugins/Service.__Dispatch_Table.delProvider(Lcom/dmdirc/plugins/ServiceProvider;)V
    //#input(bool delPlugin(String)): filename
    //#input(bool delPlugin(String)): this
    //#input(bool delPlugin(String)): this.__Tag
    //#input(bool delPlugin(String)): this.knownPlugins
    //#output(bool delPlugin(String)): java.lang.StringBuilder:toString(...)._tainted
    //#output(bool delPlugin(String)): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(bool delPlugin(String)): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(bool delPlugin(String)): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#output(bool delPlugin(String)): return_value
    //#new obj(bool delPlugin(String)): java.lang.StringBuilder:toString(...)
    //#new obj(bool delPlugin(String)): new PluginClassLoader(getSubClassLoader#1)
    //#pre[1] (bool delPlugin(String)): filename != null
    //#pre[4] (bool delPlugin(String)): this.knownPlugins != null
    //#pre[3] (bool delPlugin(String)): (soft) this.__Tag == com/dmdirc/plugins/PluginManager
    //#presumption(bool delPlugin(String)): java.util.Map:get(...)@348 != null
    //#presumption(bool delPlugin(String)): java.util.Map:get(...)@348.__Tag == com/dmdirc/plugins/PluginInfo
    //#presumption(bool delPlugin(String)): pluginInfo.children@300 != null
    //#presumption(bool delPlugin(String)): pluginInfo.plugin.__Tag@300 == com/dmdirc/plugins/Plugin
    //#presumption(bool delPlugin(String)): pluginInfo.plugin@300 != null
    //#presumption(bool delPlugin(String)): pluginInfo.provides@300 != null
    //#post(bool delPlugin(String)): init'ed(java.lang.StringBuilder:toString(...)._tainted)
    //#post(bool delPlugin(String)): possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
    //#post(bool delPlugin(String)): init'ed(return_value)
    //#post(bool delPlugin(String)): init'ed(new PluginClassLoader(getSubClassLoader#1) num objects)
    //#post(bool delPlugin(String)): possibly_updated(new PluginClassLoader(getSubClassLoader#1).__Tag)
    //#post(bool delPlugin(String)): possibly_updated(new PluginClassLoader(getSubClassLoader#1).pluginInfo)
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.String:toLowerCase
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:addError
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.List:remove
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:getPluginManager
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:getPluginInfoByName
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:unloadPlugin
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:delProvider
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.util.List:clear
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:isUnloadable
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:onUnload
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.Exception:getMessage
    //#unanalyzed(bool delPlugin(String)): Effects-of-calling:java.lang.Exception:printStackTrace
    //#test_vector(bool delPlugin(String)): java.util.Map:containsKey(...)@296: {1}, {0}
			return false;
		}

		PluginInfo pluginInfo = getPluginInfo(filename);
		
		pluginInfo.unloadPlugin();
		
		knownPlugins.remove(filename.toLowerCase());

		return true;
    //#PluginManager.java:306: end of method: bool com.dmdirc.plugins.PluginManager.delPlugin(String)
	}

	/**
	 * Reload a plugin.
	 *
	 * @param filename Filename of Plugin jar
	 * @return True if reloaded.
	 */
	public boolean reloadPlugin(final String filename) {
		if (!knownPlugins.containsKey(filename.toLowerCase())) {
    //#PluginManager.java:316: method: bool com.dmdirc.plugins.PluginManager.reloadPlugin(String)
    //#input(bool reloadPlugin(String)): " - "._tainted
    //#input(bool reloadPlugin(String)): ""._tainted
    //#input(bool reloadPlugin(String)): ":"._tainted
    //#input(bool reloadPlugin(String)): "Error in onUnload for "._tainted
    //#input(bool reloadPlugin(String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(bool reloadPlugin(String)): __Descendant_Table[others]
    //#input(bool reloadPlugin(String)): __Dispatch_Table.addPlugin(Ljava/lang/String;)Z
    //#input(bool reloadPlugin(String)): __Dispatch_Table.delPlugin(Ljava/lang/String;)Z
    //#input(bool reloadPlugin(String)): __Dispatch_Table.getPluginInfo(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(bool reloadPlugin(String)): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(bool reloadPlugin(String)): com/dmdirc/logger/ErrorLevel.MEDIUM
    //#input(bool reloadPlugin(String)): com/dmdirc/logger/Logger.manager
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/Plugin.__Descendant_Table[com/dmdirc/plugins/Plugin]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/Plugin.__Descendant_Table[others]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/Plugin.__Dispatch_Table.onUnload()V
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[com/dmdirc/plugins/PluginClassLoader]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[others]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.getSubClassLoader(Lcom/dmdirc/plugins/PluginInfo;)Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.delChild(Lcom/dmdirc/plugins/PluginInfo;)V
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginClassLoader()Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isTempLoaded()Z
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isUnloadable()Z
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPlugin()V
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.unloadPlugin()V
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/PluginInfo.com.dmdirc.actions.CoreActionType.PLUGIN_UNLOADED
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(bool reloadPlugin(String)): com/dmdirc/plugins/Service.__Dispatch_Table.delProvider(Lcom/dmdirc/plugins/ServiceProvider;)V
    //#input(bool reloadPlugin(String)): filename
    //#input(bool reloadPlugin(String)): this
    //#input(bool reloadPlugin(String)): this.__Tag
    //#input(bool reloadPlugin(String)): this.knownPlugins
    //#output(bool reloadPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#output(bool reloadPlugin(String)): com/dmdirc/logger/ProgramError.errorDir
    //#output(bool reloadPlugin(String)): java.lang.StringBuilder:toString(...)._tainted
    //#output(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1) num objects
    //#output(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1).__Tag
    //#output(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1).queue
    //#output(bool reloadPlugin(String)): new File(getErrorFile#1) num objects
    //#output(bool reloadPlugin(String)): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(bool reloadPlugin(String)): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(bool reloadPlugin(String)): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#output(bool reloadPlugin(String)): return_value
    //#new obj(bool reloadPlugin(String)): java.lang.StringBuilder:toString(...)
    //#new obj(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1)
    //#new obj(bool reloadPlugin(String)): new File(getErrorFile#1)
    //#new obj(bool reloadPlugin(String)): new PluginClassLoader(getSubClassLoader#1)
    //#pre[7] (bool reloadPlugin(String)): filename != null
    //#pre[13] (bool reloadPlugin(String)): this.knownPlugins != null
    //#pre[9] (bool reloadPlugin(String)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#pre[10] (bool reloadPlugin(String)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[12] (bool reloadPlugin(String)): (soft) this.__Tag == com/dmdirc/plugins/PluginManager
    //#presumption(bool reloadPlugin(String)): java.util.Map:get(...)@348 != null
    //#presumption(bool reloadPlugin(String)): java.util.Map:get(...)@348 != null
    //#presumption(bool reloadPlugin(String)): java.util.Map:get(...)@348 != null
    //#presumption(bool reloadPlugin(String)): java.util.Map:get(...)@348.__Tag == com/dmdirc/plugins/PluginInfo
    //#presumption(bool reloadPlugin(String)): java.util.Map:get(...)@348.__Tag == com/dmdirc/plugins/PluginInfo
    //#presumption(bool reloadPlugin(String)): java.util.Map:get(...)@348.__Tag == com/dmdirc/plugins/PluginInfo
    //#post(bool reloadPlugin(String)): com/dmdirc/logger/ProgramError.errorDir == old com/dmdirc/logger/ProgramError.errorDir
    //#post(bool reloadPlugin(String)): init'ed(java.lang.StringBuilder:toString(...)._tainted)
    //#post(bool reloadPlugin(String)): possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
    //#post(bool reloadPlugin(String)): init'ed(return_value)
    //#post(bool reloadPlugin(String)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread == old com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#post(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1) num objects == undefined
    //#post(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1) num objects == 0, if init'ed
    //#post(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1).__Tag == new ErrorReportingThread(sendError#1) num objects
    //#post(bool reloadPlugin(String)): new File(getErrorFile#1) num objects == new ErrorReportingThread(sendError#1) num objects
    //#post(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1).queue == undefined
    //#post(bool reloadPlugin(String)): new ErrorReportingThread(sendError#1).queue == null
    //#post(bool reloadPlugin(String)): init'ed(new PluginClassLoader(getSubClassLoader#1) num objects)
    //#post(bool reloadPlugin(String)): possibly_updated(new PluginClassLoader(getSubClassLoader#1).__Tag)
    //#post(bool reloadPlugin(String)): possibly_updated(new PluginClassLoader(getSubClassLoader#1).pluginInfo)
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.String:toLowerCase
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:addError
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.List:remove
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:getPluginManager
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:getPluginInfoByName
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:unloadPlugin
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:delProvider
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.List:clear
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:isUnloadable
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:onUnload
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.Exception:getMessage
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.lang.Exception:printStackTrace
    //#unanalyzed(bool reloadPlugin(String)): Effects-of-calling:java.util.Map:remove
    //#test_vector(bool reloadPlugin(String)): addPlugin(...)@322: {0}, {1}
    //#test_vector(bool reloadPlugin(String)): java.util.Map:containsKey(...)@316: {1}, {0}
			return false;
		}
		
		final boolean wasLoaded = getPluginInfo(filename).isLoaded();
		delPlugin(filename);
		boolean result = addPlugin(filename);
    //#PluginManager.java:322: Warning: call too complex - analysis skipped
    //#    call on bool addPlugin(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: bool reloadPlugin(String)
    //#    unanalyzed callee: bool addPlugin(String)
		
		if (wasLoaded && result) {
			getPluginInfo(filename).loadPlugin();
    //#PluginManager.java:325: Warning: call too complex - analysis skipped
    //#    call on void loadPlugin()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: bool reloadPlugin(String)
    //#    unanalyzed callee: void loadPlugin()
			result = getPluginInfo(filename).isLoaded();
		}
		
		return result;
    //#PluginManager.java:329: end of method: bool com.dmdirc.plugins.PluginManager.reloadPlugin(String)
	}

	/**
	 * Reload all plugins.
	 */
	public void reloadAllPlugins() {
		for (PluginInfo pluginInfo : getPluginInfos()) {
    //#PluginManager.java:336: method: void com.dmdirc.plugins.PluginManager.reloadAllPlugins()
    //#input(void reloadAllPlugins()): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(void reloadAllPlugins()): __Descendant_Table[others]
    //#input(void reloadAllPlugins()): __Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#input(void reloadAllPlugins()): __Dispatch_Table.reloadPlugin(Ljava/lang/String;)Z
    //#input(void reloadAllPlugins()): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(void reloadAllPlugins()): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(void reloadAllPlugins()): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFilename()Ljava/lang/String;
    //#input(void reloadAllPlugins()): this
    //#input(void reloadAllPlugins()): this.__Tag
    //#input(void reloadAllPlugins()): this.knownPlugins
    //#output(void reloadAllPlugins()): java.lang.StringBuilder:toString(...)._tainted
    //#output(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#new obj(void reloadAllPlugins()): java.lang.StringBuilder:toString(...)
    //#new obj(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1)
    //#pre[2] (void reloadAllPlugins()): this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[3] (void reloadAllPlugins()): this.knownPlugins != null
    //#presumption(void reloadAllPlugins()): java.util.Iterator:next(...).__Tag@336 == com/dmdirc/plugins/PluginInfo
    //#presumption(void reloadAllPlugins()): java.util.Iterator:next(...)@336 != null
    //#post(void reloadAllPlugins()): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1) num objects == undefined
    //#post(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1) num objects == 0, if init'ed
    //#post(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1).__Tag == new PluginClassLoader(getSubClassLoader#1) num objects
    //#post(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1).pluginInfo == undefined
    //#post(void reloadAllPlugins()): new PluginClassLoader(getSubClassLoader#1).pluginInfo == null
    //#unanalyzed(void reloadAllPlugins()): Effects-of-calling:java.util.Map:values
    //#unanalyzed(void reloadAllPlugins()): Effects-of-calling:java.util.ArrayList
    //#test_vector(void reloadAllPlugins()): java.util.Iterator:hasNext(...)@336: {0}, {1}
			reloadPlugin(pluginInfo.getFilename());
    //#PluginManager.java:337: Warning: call too complex - analysis skipped
    //#    call on bool reloadPlugin(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void reloadAllPlugins()
    //#    unanalyzed callee: bool reloadPlugin(String)
		}
	}
    //#PluginManager.java:339: end of method: void com.dmdirc.plugins.PluginManager.reloadAllPlugins()

	/**
	 * Get a plugin instance.
	 *
	 * @param filename File name of plugin jar
	 * @return PluginInfo instance, or null
	 */
	public PluginInfo getPluginInfo(final String filename) {
		return knownPlugins.get(filename.toLowerCase());
    //#PluginManager.java:348: method: PluginInfo com.dmdirc.plugins.PluginManager.getPluginInfo(String)
    //#input(PluginInfo getPluginInfo(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(PluginInfo getPluginInfo(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(PluginInfo getPluginInfo(String)): filename
    //#input(PluginInfo getPluginInfo(String)): this
    //#input(PluginInfo getPluginInfo(String)): this.knownPlugins
    //#output(PluginInfo getPluginInfo(String)): return_value
    //#pre[1] (PluginInfo getPluginInfo(String)): filename != null
    //#pre[3] (PluginInfo getPluginInfo(String)): this.knownPlugins != null
    //#presumption(PluginInfo getPluginInfo(String)): java.util.Map:get(...).__Tag@348 == com/dmdirc/plugins/PluginInfo
    //#post(PluginInfo getPluginInfo(String)): init'ed(return_value)
    //#PluginManager.java:348: end of method: PluginInfo com.dmdirc.plugins.PluginManager.getPluginInfo(String)
	}

	/**
	 * Get a plugin instance by plugin name.
	 *
	 * @param name Name of plugin to find.
	 * @return PluginInfo instance, or null
	 */
	public PluginInfo getPluginInfoByName(final String name) {
		for (PluginInfo pluginInfo : getPluginInfos()) {
    //#PluginManager.java:358: method: PluginInfo com.dmdirc.plugins.PluginManager.getPluginInfoByName(String)
    //#input(PluginInfo getPluginInfoByName(String)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(PluginInfo getPluginInfoByName(String)): __Descendant_Table[others]
    //#input(PluginInfo getPluginInfoByName(String)): __Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#input(PluginInfo getPluginInfoByName(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(PluginInfo getPluginInfoByName(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(PluginInfo getPluginInfoByName(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(PluginInfo getPluginInfoByName(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(PluginInfo getPluginInfoByName(String)): name
    //#input(PluginInfo getPluginInfoByName(String)): this
    //#input(PluginInfo getPluginInfoByName(String)): this.__Tag
    //#input(PluginInfo getPluginInfoByName(String)): this.knownPlugins
    //#output(PluginInfo getPluginInfoByName(String)): return_value
    //#pre[3] (PluginInfo getPluginInfoByName(String)): this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[4] (PluginInfo getPluginInfoByName(String)): this.knownPlugins != null
    //#presumption(PluginInfo getPluginInfoByName(String)): java.util.Iterator:next(...).__Tag@358 == com/dmdirc/plugins/PluginInfo
    //#presumption(PluginInfo getPluginInfoByName(String)): java.util.Iterator:next(...)@358 != null
    //#post(PluginInfo getPluginInfoByName(String)): init'ed(return_value)
    //#unanalyzed(PluginInfo getPluginInfoByName(String)): Effects-of-calling:java.util.Map:values
    //#unanalyzed(PluginInfo getPluginInfoByName(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(PluginInfo getPluginInfoByName(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(PluginInfo getPluginInfoByName(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(PluginInfo getPluginInfoByName(String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(PluginInfo getPluginInfoByName(String)): Effects-of-calling:java.util.Map:get
    //#test_vector(PluginInfo getPluginInfoByName(String)): java.lang.String:equalsIgnoreCase(...)@359: {0}, {1}
    //#test_vector(PluginInfo getPluginInfoByName(String)): java.util.Iterator:hasNext(...)@358: {0}, {1}
			if (pluginInfo.getName().equalsIgnoreCase(name)) {
    //#PluginManager.java:359: ?null dereference
    //#    getName(...) != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: PluginInfo getPluginInfoByName(String)
    //#    basic block: bb_7
    //#    assertion: getName(...) != null
    //#    VN: getName(...)
    //#    Expected: Inverse{null} or Invalid
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
				return pluginInfo;
			}
		}
		
		return null;
    //#PluginManager.java:364: end of method: PluginInfo com.dmdirc.plugins.PluginManager.getPluginInfoByName(String)
	}

	/**
	 * Get directory where plugins are stored.
	 *
	 * @return Directory where plugins are stored.
	 */
	public String getDirectory() {
		return myDir;
    //#PluginManager.java:373: method: String com.dmdirc.plugins.PluginManager.getDirectory()
    //#input(String getDirectory()): this
    //#input(String getDirectory()): this.myDir
    //#output(String getDirectory()): return_value
    //#post(String getDirectory()): return_value == this.myDir
    //#post(String getDirectory()): init'ed(return_value)
    //#PluginManager.java:373: end of method: String com.dmdirc.plugins.PluginManager.getDirectory()
	}

	/**
	 * Retrieves a list of all installed plugins.
	 * Any file under the main plugin directory (~/.DMDirc/plugins or similar)
	 * that matches *.jar is deemed to be a valid plugin.
	 *
	 * @param addPlugins Should all found plugins be automatically have addPlugin() called?
	 * @return A list of all installed plugins
	 */
	public List<PluginInfo> getPossiblePluginInfos(final boolean addPlugins) {
		final Map<String, PluginInfo> res = new Hashtable<String, PluginInfo>();
    //#PluginManager.java:385: method: List com.dmdirc.plugins.PluginManager.getPossiblePluginInfos(bool)
    //#input(List getPossiblePluginInfos(bool)): " - "._tainted
    //#input(List getPossiblePluginInfos(bool)): ""._tainted
    //#input(List getPossiblePluginInfos(bool)): "&#09;"._tainted
    //#input(List getPossiblePluginInfos(bool)): "&#10;Which caused: "._tainted
    //#input(List getPossiblePluginInfos(bool)): "-"._tainted
    //#input(List getPossiblePluginInfos(bool)): ".log"._tainted
    //#input(List getPossiblePluginInfos(bool)): ": "._tainted
    //#input(List getPossiblePluginInfos(bool)): ":"._tainted
    //#input(List getPossiblePluginInfos(bool)): "A fatal error has occurred: "._tainted
    //#input(List getPossiblePluginInfos(bool)): "An error has occurred: "._tainted
    //#input(List getPossiblePluginInfos(bool)): "Date:"._tainted
    //#input(List getPossiblePluginInfos(bool)): "Description: "._tainted
    //#input(List getPossiblePluginInfos(bool)): "Error creating URL for plugin "._tainted
    //#input(List getPossiblePluginInfos(bool)): "Error in onUnload for "._tainted
    //#input(List getPossiblePluginInfos(bool)): "ID must be a positive integer: "._tainted
    //#input(List getPossiblePluginInfos(bool)): "Level: "._tainted
    //#input(List getPossiblePluginInfos(bool)): "errors"._tainted
    //#input(List getPossiblePluginInfos(bool)): "file:"._tainted
    //#input(List getPossiblePluginInfos(bool)): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(List getPossiblePluginInfos(bool)): __Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): __Dispatch_Table.addPlugin(Ljava/lang/String;)Z
    //#input(List getPossiblePluginInfos(bool)): __Dispatch_Table.delPlugin(Ljava/lang/String;)Z
    //#input(List getPossiblePluginInfos(bool)): __Dispatch_Table.getDirectory()Ljava/lang/String;
    //#input(List getPossiblePluginInfos(bool)): __Dispatch_Table.getPluginInfo(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(List getPossiblePluginInfos(bool)): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(List getPossiblePluginInfos(bool)): addPlugins
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorLevel__static_init.new ErrorLevel(ErrorLevel__static_init#3)._tainted
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2).length
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[0..4_294_967_295]
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errors
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errors.__Lock
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportQueue
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(List getPossiblePluginInfos(bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorLevel.MEDIUM
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorManager.BANNED_EXCEPTIONS
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorManager.java.lang.System.err
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorManager.me
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/Logger.manager
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ProgramError.errorDir
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ProgramError.writingSem
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/Plugin.__Descendant_Table[com/dmdirc/plugins/Plugin]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/Plugin.__Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/Plugin.__Dispatch_Table.onUnload()V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[com/dmdirc/plugins/PluginClassLoader]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.getSubClassLoader(Lcom/dmdirc/plugins/PluginInfo;)Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.delChild(Lcom/dmdirc/plugins/PluginInfo;)V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFilename()Ljava/lang/String;
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFullFilename()Ljava/lang/String;
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginClassLoader()Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isTempLoaded()Z
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isUnloadable()Z
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.unloadPlugin()V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/PluginInfo.com.dmdirc.actions.CoreActionType.PLUGIN_UNLOADED
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/plugins/Service.__Dispatch_Table.delProvider(Lcom/dmdirc/plugins/ServiceProvider;)V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(List getPossiblePluginInfos(bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(List getPossiblePluginInfos(bool)): this
    //#input(List getPossiblePluginInfos(bool)): this.__Tag
    //#input(List getPossiblePluginInfos(bool)): this.knownPlugins
    //#input(List getPossiblePluginInfos(bool)): this.myDir
    //#input(List getPossiblePluginInfos(bool)): this.myDir._tainted
    //#output(List getPossiblePluginInfos(bool)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#output(List getPossiblePluginInfos(bool)): com/dmdirc/logger/ProgramError.errorDir
    //#output(List getPossiblePluginInfos(bool)): java.lang.StringBuilder:toString(...)._tainted
    //#output(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1) num objects
    //#output(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1).__Tag
    //#output(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1).queue
    //#output(List getPossiblePluginInfos(bool)): new File(getErrorFile#1) num objects
    //#output(List getPossiblePluginInfos(bool)): new LinkedList(getPossiblePluginInfos#10) num objects
    //#output(List getPossiblePluginInfos(bool)): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(List getPossiblePluginInfos(bool)): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(List getPossiblePluginInfos(bool)): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#output(List getPossiblePluginInfos(bool)): return_value
    //#new obj(List getPossiblePluginInfos(bool)): java.lang.StringBuilder:toString(...)
    //#new obj(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1)
    //#new obj(List getPossiblePluginInfos(bool)): new File(getErrorFile#1)
    //#new obj(List getPossiblePluginInfos(bool)): new LinkedList(getPossiblePluginInfos#10)
    //#new obj(List getPossiblePluginInfos(bool)): new PluginClassLoader(getSubClassLoader#1)
    //#pre[4] (List getPossiblePluginInfos(bool)): (soft) com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[0..4_294_967_295] != null
    //#pre[6] (List getPossiblePluginInfos(bool)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports)
    //#pre[7] (List getPossiblePluginInfos(bool)): (soft) com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID != null
    //#pre[8] (List getPossiblePluginInfos(bool)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports)
    //#pre[9] (List getPossiblePluginInfos(bool)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[10] (List getPossiblePluginInfos(bool)): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#pre[11] (List getPossiblePluginInfos(bool)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[13] (List getPossiblePluginInfos(bool)): (soft) this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[14] (List getPossiblePluginInfos(bool)): (soft) this.knownPlugins != null
    //#pre[15] (List getPossiblePluginInfos(bool)): (soft) this.myDir != null
    //#presumption(List getPossiblePluginInfos(bool)): arr$.length@394 <= 4_294_967_295
    //#presumption(List getPossiblePluginInfos(bool)): java.io.File:getName(...)@397 != null
    //#presumption(List getPossiblePluginInfos(bool)): java.io.File:getPath(...)@398 != null
    //#presumption(List getPossiblePluginInfos(bool)): java.io.File:listFiles(...)@394 != null
    //#presumption(List getPossiblePluginInfos(bool)): java.util.Iterator:next(...).__Tag@416 == com/dmdirc/plugins/PluginInfo
    //#presumption(List getPossiblePluginInfos(bool)): java.util.Iterator:next(...)@416 != null
    //#presumption(List getPossiblePluginInfos(bool)): java.util.LinkedList:pop(...)@392 != null
    //#presumption(List getPossiblePluginInfos(bool)): java.util.Map:values(...)@416 != null
    //#presumption(List getPossiblePluginInfos(bool)): pi.filename@416 != null
    //#presumption(List getPossiblePluginInfos(bool)): pi.url@416 != null
    //#post(List getPossiblePluginInfos(bool)): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(List getPossiblePluginInfos(bool)): init'ed(java.lang.StringBuilder:toString(...)._tainted)
    //#post(List getPossiblePluginInfos(bool)): possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
    //#post(List getPossiblePluginInfos(bool)): return_value == &new LinkedList(getPossiblePluginInfos#10)
    //#post(List getPossiblePluginInfos(bool)): init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#post(List getPossiblePluginInfos(bool)): init'ed(new ErrorReportingThread(sendError#1) num objects)
    //#post(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1) num objects == undefined
    //#post(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1) num objects == 0, if init'ed
    //#post(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1).__Tag == new ErrorReportingThread(sendError#1) num objects
    //#post(List getPossiblePluginInfos(bool)): new File(getErrorFile#1) num objects == new ErrorReportingThread(sendError#1) num objects
    //#post(List getPossiblePluginInfos(bool)): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(List getPossiblePluginInfos(bool)): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1).queue == undefined
    //#post(List getPossiblePluginInfos(bool)): new ErrorReportingThread(sendError#1).queue == null
    //#post(List getPossiblePluginInfos(bool)): init'ed(new File(getErrorFile#1) num objects)
    //#post(List getPossiblePluginInfos(bool)): new LinkedList(getPossiblePluginInfos#10) num objects == 1
    //#post(List getPossiblePluginInfos(bool)): init'ed(new PluginClassLoader(getSubClassLoader#1) num objects)
    //#post(List getPossiblePluginInfos(bool)): init'ed(new PluginClassLoader(getSubClassLoader#1).__Tag)
    //#post(List getPossiblePluginInfos(bool)): init'ed(new PluginClassLoader(getSubClassLoader#1).pluginInfo)
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.String:toLowerCase
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:getErrorManager
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:addError
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.List:remove
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:getPluginManager
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:getPluginInfoByName
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:unloadPlugin
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:delProvider
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.List:clear
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:isUnloadable
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:onUnload
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Exception:getMessage
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Exception:printStackTrace
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.net.URL:getPath
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Map:remove
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Date
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.List:add
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:isReady
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:errorAdded
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.File
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Throwable:getStackTrace
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Throwable:toString
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.StackTraceElement:toString
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Throwable:getCause
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:getTrace
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.Object:equals
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:equals
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:getReportStatus
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(List getPossiblePluginInfos(bool)): Effects-of-calling:java.util.Arrays:equals
    //#test_vector(List getPossiblePluginInfos(bool)): addPlugins: {0}, {1}
    //#test_vector(List getPossiblePluginInfos(bool)): java.io.File:exists(...)@417: {1}, {0}
    //#test_vector(List getPossiblePluginInfos(bool)): java.io.File:isDirectory(...)@393: {0}, {1}
    //#test_vector(List getPossiblePluginInfos(bool)): java.io.File:isFile(...)@397: {0}, {1}
    //#test_vector(List getPossiblePluginInfos(bool)): java.lang.String:endsWith(...)@397: {0}, {1}
    //#test_vector(List getPossiblePluginInfos(bool)): java.util.Iterator:hasNext(...)@416: {0}, {1}
    //#test_vector(List getPossiblePluginInfos(bool)): java.util.LinkedList:isEmpty(...)@391: {1}, {0}
		
		final LinkedList<File> dirs = new LinkedList<File>();
		
		dirs.add(new File(myDir));
		
		while (!dirs.isEmpty()) {
			final File dir = dirs.pop();
			if (dir.isDirectory()) {
				for (File file : dir.listFiles()) {
					dirs.add(file);
				}
			} else if (dir.isFile() && dir.getName().endsWith(".jar")) {
				String target = dir.getPath();
				
				// Remove the plugin dir
				target = target.substring(myDir.length(), target.length());
				if (addPlugins) {
					addPlugin(target);
    //#PluginManager.java:403: Warning: call too complex - analysis skipped
    //#    call on bool addPlugin(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: List getPossiblePluginInfos(bool)
    //#    unanalyzed callee: bool addPlugin(String)
				} else {
					try {
						final PluginInfo pi = new PluginInfo(new URL("file:"+getDirectory()+target), false);
    //#PluginManager.java:406: Warning: call too complex - analysis skipped
    //#    call on void com.dmdirc.plugins.PluginInfo(URL, bool)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: List getPossiblePluginInfos(bool)
    //#    unanalyzed callee: void com.dmdirc.plugins.PluginInfo(URL, bool)
						res.put(target, pi);
					} catch (MalformedURLException mue) {
						Logger.userError(ErrorLevel.MEDIUM, "Error creating URL for plugin " + target + ": " + mue.getMessage(), mue);
					} catch (PluginException pe) { /* This can not be thrown when the second param is false */}
				}
			}
		}

		final Map<String, PluginInfo> knownPluginsCopy = new Hashtable<String, PluginInfo>(knownPlugins);
		for (PluginInfo pi : knownPluginsCopy.values()) {
			if (!(new File(pi.getFullFilename())).exists()) {
				delPlugin(pi.getFilename());
			} else if (addPlugins) {
				res.put(pi.getFilename().toLowerCase(), pi);
			}
		}
		
		return new LinkedList<PluginInfo>(res.values());
    //#PluginManager.java:424: end of method: List com.dmdirc.plugins.PluginManager.getPossiblePluginInfos(bool)
	}

	/**
	 * Update the autoLoadList
	 *
	 * @param plugin to add/remove (Decided automatically based on isLoaded())
	 */
	public void updateAutoLoad(final PluginInfo plugin) {
		final List<String> list = IdentityManager.getGlobalConfig().getOptionList("plugins", "autoload");
    //#PluginManager.java:433: method: void com.dmdirc.plugins.PluginManager.updateAutoLoad(PluginInfo)
    //#PluginManager.java:433: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void updateAutoLoad(PluginInfo)
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#PluginManager.java:433: Warning: method not available - call not analyzed
    //#    call on List com.dmdirc.config.ConfigManager:getOptionList(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void updateAutoLoad(PluginInfo)
    //#    unanalyzed callee: List com.dmdirc.config.ConfigManager:getOptionList(String, String)
    //#input(void updateAutoLoad(PluginInfo)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(void updateAutoLoad(PluginInfo)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(void updateAutoLoad(PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getRelativeFilename()Ljava/lang/String;
    //#input(void updateAutoLoad(PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(void updateAutoLoad(PluginInfo)): plugin
    //#input(void updateAutoLoad(PluginInfo)): plugin.__Tag
    //#input(void updateAutoLoad(PluginInfo)): plugin.plugin
    //#input(void updateAutoLoad(PluginInfo)): plugin.tempLoaded
    //#pre[5] (void updateAutoLoad(PluginInfo)): plugin != null
    //#pre[6] (void updateAutoLoad(PluginInfo)): plugin.__Tag == com/dmdirc/plugins/PluginInfo
    //#pre[7] (void updateAutoLoad(PluginInfo)): init'ed(plugin.plugin)
    //#pre[8] (void updateAutoLoad(PluginInfo)): (soft) init'ed(plugin.tempLoaded)
    //#presumption(void updateAutoLoad(PluginInfo)): com.dmdirc.config.ConfigManager:getOptionList(...)@433 != null
    //#presumption(void updateAutoLoad(PluginInfo)): com.dmdirc.config.IdentityManager:getConfigIdentity(...)@442 != null
    //#presumption(void updateAutoLoad(PluginInfo)): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@433 != null
    //#test_vector(void updateAutoLoad(PluginInfo)): !(plugin.plugin == null) & plugin.tempLoaded == 0: {0}, {1}
    //#test_vector(void updateAutoLoad(PluginInfo)): java.util.List:contains(...)@436: {1}, {0}
    //#test_vector(void updateAutoLoad(PluginInfo)): java.util.List:contains(...)@438: {0}, {1}
        final String path = plugin.getRelativeFilename();
    //#PluginManager.java:434: Warning: call too complex - analysis skipped
    //#    call on String getRelativeFilename()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void updateAutoLoad(PluginInfo)
    //#    unanalyzed callee: String getRelativeFilename()
		
		if (plugin.isLoaded() && !list.contains(path)) {
			list.add(path);
		} else if (!plugin.isLoaded() && list.contains(path)) {
			list.remove(path);
		}
		
		IdentityManager.getConfigIdentity().setOption("plugins", "autoload", list);
    //#PluginManager.java:442: Warning: method not available - call not analyzed
    //#    call on Identity com.dmdirc.config.IdentityManager:getConfigIdentity()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void updateAutoLoad(PluginInfo)
    //#    unanalyzed callee: Identity com.dmdirc.config.IdentityManager:getConfigIdentity()
    //#PluginManager.java:442: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.config.Identity:setOption(String, String, List)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.PluginManager
    //#    method: void updateAutoLoad(PluginInfo)
    //#    unanalyzed callee: void com.dmdirc.config.Identity:setOption(String, String, List)
	}
    //#PluginManager.java:443: end of method: void com.dmdirc.plugins.PluginManager.updateAutoLoad(PluginInfo)
	
	/**
	 * Get Collection<PluginInfo> of known plugins.
	 *
	 * @return Collection<PluginInfo> of known plugins.
	 */
	public Collection<PluginInfo> getPluginInfos() {
		return new ArrayList<PluginInfo>(knownPlugins.values());
    //#PluginManager.java:451: method: Collection com.dmdirc.plugins.PluginManager.getPluginInfos()
    //#input(Collection getPluginInfos()): this
    //#input(Collection getPluginInfos()): this.knownPlugins
    //#output(Collection getPluginInfos()): new ArrayList(getPluginInfos#1) num objects
    //#output(Collection getPluginInfos()): return_value
    //#new obj(Collection getPluginInfos()): new ArrayList(getPluginInfos#1)
    //#pre[2] (Collection getPluginInfos()): this.knownPlugins != null
    //#post(Collection getPluginInfos()): return_value == &new ArrayList(getPluginInfos#1)
    //#post(Collection getPluginInfos()): new ArrayList(getPluginInfos#1) num objects == 1
    //#PluginManager.java:451: end of method: Collection com.dmdirc.plugins.PluginManager.getPluginInfos()
	}

	/** {@inheritDoc} */
	@Override
	public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) {
		if (type.equals(CoreActionType.CLIENT_PREFS_OPENED)) {
    //#PluginManager.java:457: method: void com.dmdirc.plugins.PluginManager.processEvent(ActionType, StringBuffer, Object[])
    //#input(void processEvent(ActionType, StringBuffer, Object[])): " - "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): ""._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "&#09;"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "&#10;Which caused: "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): ")"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "), unable to show config ("._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "-"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): ".log"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): ": "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): ":"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "A fatal error has occurred: "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "An error has occurred: "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "Date:"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "Description: "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "Error in onUnload for "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "Error with plugin ("._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "ID must be a positive integer: "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "Level: "._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): "errors"._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): __Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): __Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): arguments
    //#input(void processEvent(ActionType, StringBuffer, Object[])): arguments.length
    //#input(void processEvent(ActionType, StringBuffer, Object[])): arguments[0]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorLevel__static_init.new ErrorLevel(ErrorLevel__static_init#3)._tainted
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2).length
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[0..4_294_967_295]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errors
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errors.__Lock
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportQueue
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorLevel.MEDIUM
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorManager.BANNED_EXCEPTIONS
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorManager.java.lang.System.err
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorManager.me
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/Logger.manager
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ProgramError.errorDir
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ProgramError.writingSem
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Plugin.__Descendant_Table[com/dmdirc/plugins/Plugin]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Plugin.__Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Plugin.__Dispatch_Table.onUnload()V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Plugin.__Dispatch_Table.showConfig(Lcom/dmdirc/config/prefs/PreferencesManager;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[com/dmdirc/plugins/PluginClassLoader]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.getSubClassLoader(Lcom/dmdirc/plugins/PluginInfo;)Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.delChild(Lcom/dmdirc/plugins/PluginInfo;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getNiceName()Ljava/lang/String;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPlugin()Lcom/dmdirc/plugins/Plugin;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginClassLoader()Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isLoaded()Z
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isTempLoaded()Z
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isUnloadable()Z
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPlugin()V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.loadPluginTemp()V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.unloadPlugin()V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/PluginInfo.com.dmdirc.actions.CoreActionType.PLUGIN_UNLOADED
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Service.__Descendant_Table[com/dmdirc/plugins/Service]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Service.__Descendant_Table[others]
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/plugins/Service.__Dispatch_Table.delProvider(Lcom/dmdirc/plugins/ServiceProvider;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(void processEvent(ActionType, StringBuffer, Object[])): this
    //#input(void processEvent(ActionType, StringBuffer, Object[])): this.__Tag
    //#input(void processEvent(ActionType, StringBuffer, Object[])): this.knownPlugins
    //#input(void processEvent(ActionType, StringBuffer, Object[])): type
    //#output(void processEvent(ActionType, StringBuffer, Object[])): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
    //#output(void processEvent(ActionType, StringBuffer, Object[])): com/dmdirc/logger/ProgramError.errorDir
    //#output(void processEvent(ActionType, StringBuffer, Object[])): java.lang.StringBuilder:toString(...)._tainted
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new ErrorReportingThread(sendError#1) num objects
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new ErrorReportingThread(sendError#1).__Tag
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new ErrorReportingThread(sendError#1).queue
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new File(getErrorFile#1) num objects
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(void processEvent(ActionType, StringBuffer, Object[])): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#new obj(void processEvent(ActionType, StringBuffer, Object[])): java.lang.StringBuilder:toString(...)
    //#new obj(void processEvent(ActionType, StringBuffer, Object[])): new ErrorReportingThread(sendError#1)
    //#new obj(void processEvent(ActionType, StringBuffer, Object[])): new File(getErrorFile#1)
    //#new obj(void processEvent(ActionType, StringBuffer, Object[])): new PluginClassLoader(getSubClassLoader#1)
    //#pre[17] (void processEvent(ActionType, StringBuffer, Object[])): type != null
    //#pre[1] (void processEvent(ActionType, StringBuffer, Object[])): (soft) arguments != null
    //#pre[2] (void processEvent(ActionType, StringBuffer, Object[])): (soft) arguments.length >= 1
    //#pre[3] (void processEvent(ActionType, StringBuffer, Object[])): (soft) init'ed(arguments[0])
    //#pre[6] (void processEvent(ActionType, StringBuffer, Object[])): (soft) com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[0..4_294_967_295] != null
    //#pre[8] (void processEvent(ActionType, StringBuffer, Object[])): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports)
    //#pre[9] (void processEvent(ActionType, StringBuffer, Object[])): (soft) com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID != null
    //#pre[10] (void processEvent(ActionType, StringBuffer, Object[])): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports)
    //#pre[11] (void processEvent(ActionType, StringBuffer, Object[])): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[12] (void processEvent(ActionType, StringBuffer, Object[])): (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#pre[13] (void processEvent(ActionType, StringBuffer, Object[])): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[15] (void processEvent(ActionType, StringBuffer, Object[])): (soft) this.__Tag == com/dmdirc/plugins/PluginManager
    //#pre[16] (void processEvent(ActionType, StringBuffer, Object[])): (soft) this.knownPlugins != null
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED)
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED)
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): getPlugin(...).__Tag@458 == com/dmdirc/plugins/Plugin
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): java.util.Iterator:next(...).__Tag@458 == com/dmdirc/plugins/PluginInfo
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): java.util.Iterator:next(...).__Tag@471 == com/dmdirc/plugins/PluginInfo
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): java.util.Iterator:next(...)@458 != null
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): java.util.Iterator:next(...)@471 != null
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): pi.children@471 != null
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): pi.plugin.__Tag@471 == com/dmdirc/plugins/Plugin
    //#presumption(void processEvent(ActionType, StringBuffer, Object[])): pi.provides@471 != null
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(java.lang.StringBuilder:toString(...)._tainted)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new ErrorReportingThread(sendError#1) num objects)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new File(getErrorFile#1) num objects)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new PluginClassLoader(getSubClassLoader#1) num objects)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new PluginClassLoader(getSubClassLoader#1).__Tag)
    //#post(void processEvent(ActionType, StringBuffer, Object[])): init'ed(new PluginClassLoader(getSubClassLoader#1).pluginInfo)
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Map:values
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:updateProvides
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:checkRequirements
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:loadRequired
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:onLoad
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getName
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Throwable:getMessage
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getErrorManager
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:addError
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:unloadPlugin
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getMainClass
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:loadClass
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:loadPlugin
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.List:remove
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.List:contains
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getPluginManager
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getPluginInfoByName
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:delProvider
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.List:clear
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:isUnloadable
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:onUnload
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Exception:getMessage
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Exception:printStackTrace
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Date
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.List:add
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:isReady
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:errorAdded
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.File:exists
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.File
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Throwable:getStackTrace
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Throwable:toString
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.StackTraceElement:toString
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Throwable:getCause
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getTrace
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.Object:equals
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:equals
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:getReportStatus
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:errorStatusChanged
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void processEvent(ActionType, StringBuffer, Object[])): Effects-of-calling:java.util.Arrays:equals
    //#test_vector(void processEvent(ActionType, StringBuffer, Object[])): java.lang.Object:equals(...)@457: {0}, {1}
    //#test_vector(void processEvent(ActionType, StringBuffer, Object[])): java.lang.Object:equals(...)@470: {0}, {1}
    //#test_vector(void processEvent(ActionType, StringBuffer, Object[])): java.util.Iterator:hasNext(...)@471: {0}, {1}
    //#test_vector(void processEvent(ActionType, StringBuffer, Object[])): pi.tempLoaded@458: {0}, {1}
			for (PluginInfo pi : getPluginInfos()) {
				if (!pi.isLoaded() && !pi.isTempLoaded()) {
					pi.loadPluginTemp();
				}
				if (pi.isLoaded() || pi.isTempLoaded()) {
					try {
						pi.getPlugin().showConfig((PreferencesManager) arguments[0]);
					} catch (Throwable t) {
						Logger.userError(ErrorLevel.MEDIUM, "Error with plugin ("+pi.getNiceName()+"), unable to show config ("+t+")", t);
					}
				}
			}
		} else if (type.equals(CoreActionType.CLIENT_PREFS_CLOSED)) {
			for (PluginInfo pi : getPluginInfos()) {
				if (pi.isTempLoaded()) {
					pi.unloadPlugin();
				}
			}
		}
	}
    //#PluginManager.java:477: end of method: void com.dmdirc.plugins.PluginManager.processEvent(ActionType, StringBuffer, Object[])
}
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.addPlugin(Ljava/lang/String;)Z
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.delPlugin(Ljava/lang/String;)Z
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.doAutoLoad()V
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getAllServices()Ljava/util/List;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getDirectory()Ljava/lang/String;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getExportedService(Ljava/lang/String;)Lcom/dmdirc/plugins/ExportedService;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPluginInfo(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPossiblePluginInfos(Z)Ljava/util/List;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/Service;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;Z)Lcom/dmdirc/plugins/Service;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getServiceProvider(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/ServiceProvider;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getServiceProvider(Ljava/lang/String;Ljava/util/List;Z)Lcom/dmdirc/plugins/ServiceProvider;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getServicesByType(Ljava/lang/String;)Ljava/util/List;
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.processEvent(Lcom/dmdirc/actions/interfaces/ActionType;Ljava/lang/StringBuffer;[Ljava/lang/Object;)V
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.reloadAllPlugins()V
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.reloadPlugin(Ljava/lang/String;)Z
    //#output(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.updateAutoLoad(Lcom/dmdirc/plugins/PluginInfo;)V
    //#output(com.dmdirc.plugins.PluginManager__static_init): com/dmdirc/interfaces/ActionListener.__Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Descendant_Table[com/dmdirc/plugins/PluginManager] == &__Dispatch_Table
    //#post(com.dmdirc.plugins.PluginManager__static_init): com/dmdirc/interfaces/ActionListener.__Descendant_Table[com/dmdirc/plugins/PluginManager] == &__Dispatch_Table
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.addPlugin(Ljava/lang/String;)Z == &addPlugin
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.delPlugin(Ljava/lang/String;)Z == &delPlugin
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.doAutoLoad()V == &doAutoLoad
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getAllServices()Ljava/util/List; == &getAllServices
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getDirectory()Ljava/lang/String; == &getDirectory
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getExportedService(Ljava/lang/String;)Lcom/dmdirc/plugins/ExportedService; == &getExportedService
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPluginInfo(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo; == &getPluginInfo
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPluginInfoByName(Ljava/lang/String;)Lcom/dmdirc/plugins/PluginInfo; == &getPluginInfoByName
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPluginInfos()Ljava/util/Collection; == &getPluginInfos
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getPossiblePluginInfos(Z)Ljava/util/List; == &getPossiblePluginInfos
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/Service; == &getService
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getService(Ljava/lang/String;Ljava/lang/String;Z)Lcom/dmdirc/plugins/Service; == &getService
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getServiceProvider(Ljava/lang/String;Ljava/lang/String;)Lcom/dmdirc/plugins/ServiceProvider; == &getServiceProvider
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getServiceProvider(Ljava/lang/String;Ljava/util/List;Z)Lcom/dmdirc/plugins/ServiceProvider; == &getServiceProvider
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.getServicesByType(Ljava/lang/String;)Ljava/util/List; == &getServicesByType
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.processEvent(Lcom/dmdirc/actions/interfaces/ActionType;Ljava/lang/StringBuffer;[Ljava/lang/Object;)V == &processEvent
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.reloadAllPlugins()V == &reloadAllPlugins
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.reloadPlugin(Ljava/lang/String;)Z == &reloadPlugin
    //#post(com.dmdirc.plugins.PluginManager__static_init): __Dispatch_Table.updateAutoLoad(Lcom/dmdirc/plugins/PluginInfo;)V == &updateAutoLoad
    //#PluginManager.java:: end of method: com.dmdirc.plugins.PluginManager.com.dmdirc.plugins.PluginManager__static_init
    //#PluginManager.java:: end of class: com.dmdirc.plugins.PluginManager
