//# 1 errors, 331 messages
//#
/*
    //#GlobalClassLoader.java:1:1: class: com.dmdirc.plugins.GlobalClassLoader
    //#GlobalClassLoader.java:1:1: method: com.dmdirc.plugins.GlobalClassLoader.com.dmdirc.plugins.GlobalClassLoader__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.util.resourcemanager.ResourceManager;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This classloader knows about plugins and is used to store persistent classes.
 */
public final class GlobalClassLoader extends ClassLoader {

	/** Singleton instance of the GlobalClassLoader. */
	private static GlobalClassLoader me;
	
	/** HashMap containing sources of Global class files. */
	private Map<String,String> resourcesList = new HashMap<String,String>();

	/**
	 * Create a new GlobalClassLoader.
	 */
	private GlobalClassLoader() {
		super();
    //#GlobalClassLoader.java:47: method: void com.dmdirc.plugins.GlobalClassLoader.com.dmdirc.plugins.GlobalClassLoader()
    //#input(void com.dmdirc.plugins.GlobalClassLoader()): this
    //#output(void com.dmdirc.plugins.GlobalClassLoader()): new HashMap(GlobalClassLoader#1) num objects
    //#output(void com.dmdirc.plugins.GlobalClassLoader()): this.resourcesList
    //#new obj(void com.dmdirc.plugins.GlobalClassLoader()): new HashMap(GlobalClassLoader#1)
    //#post(void com.dmdirc.plugins.GlobalClassLoader()): this.resourcesList == &new HashMap(GlobalClassLoader#1)
    //#post(void com.dmdirc.plugins.GlobalClassLoader()): new HashMap(GlobalClassLoader#1) num objects == 1
	}
    //#GlobalClassLoader.java:48: end of method: void com.dmdirc.plugins.GlobalClassLoader.com.dmdirc.plugins.GlobalClassLoader()
	
	/**
	 * Have we already loaded the given class name?
	 *
	 * @param name Name to check.
     * @return True if the class is loaded, false otherwise
	 */
	public boolean isClassLoaded(final String name) {
		// Don't duplicate a class
		final Class existing = findLoadedClass(name);
    //#GlobalClassLoader.java:58: method: bool com.dmdirc.plugins.GlobalClassLoader.isClassLoaded(String)
    //#GlobalClassLoader.java:58: Warning: method not available - call not analyzed
    //#    call on Class com.dmdirc.plugins.GlobalClassLoader:findLoadedClass(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: bool isClassLoaded(String)
    //#    unanalyzed callee: Class com.dmdirc.plugins.GlobalClassLoader:findLoadedClass(String)
    //#input(bool isClassLoaded(String)): name
    //#input(bool isClassLoaded(String)): this
    //#output(bool isClassLoaded(String)): return_value
    //#post(bool isClassLoaded(String)): init'ed(return_value)
		return existing != null;
    //#GlobalClassLoader.java:59: end of method: bool com.dmdirc.plugins.GlobalClassLoader.isClassLoaded(String)
	}
	
	/**
	 * Retrieves the singleton instance of the GlobalClassLoader.
	 *
	 * @return A singleton instance of GlobalClassLoader.
	 */
	public static final synchronized GlobalClassLoader getGlobalClassLoader() {
		if (me == null) {
    //#GlobalClassLoader.java:68: method: GlobalClassLoader com.dmdirc.plugins.GlobalClassLoader.getGlobalClassLoader()
    //#input(GlobalClassLoader getGlobalClassLoader()): __Class_Obj.__Lock
    //#input(GlobalClassLoader getGlobalClassLoader()): me
    //#output(GlobalClassLoader getGlobalClassLoader()): me
    //#output(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1) num objects
    //#output(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1).__Tag
    //#output(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1).resourcesList
    //#output(GlobalClassLoader getGlobalClassLoader()): new HashMap(GlobalClassLoader#1) num objects
    //#output(GlobalClassLoader getGlobalClassLoader()): return_value
    //#new obj(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1)
    //#new obj(GlobalClassLoader getGlobalClassLoader()): new HashMap(GlobalClassLoader#1)
    //#pre[1] (GlobalClassLoader getGlobalClassLoader()): init'ed(me)
    //#post(GlobalClassLoader getGlobalClassLoader()): me == One-of{old me, &new GlobalClassLoader(getGlobalClassLoader#1)}
    //#post(GlobalClassLoader getGlobalClassLoader()): me != null
    //#post(GlobalClassLoader getGlobalClassLoader()): return_value == me
    //#post(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1) num objects <= 1
    //#post(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1).__Tag == com/dmdirc/plugins/GlobalClassLoader
    //#post(GlobalClassLoader getGlobalClassLoader()): new GlobalClassLoader(getGlobalClassLoader#1).resourcesList == &new HashMap(GlobalClassLoader#1)
    //#post(GlobalClassLoader getGlobalClassLoader()): new HashMap(GlobalClassLoader#1) num objects <= 1
    //#unanalyzed(GlobalClassLoader getGlobalClassLoader()): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(GlobalClassLoader getGlobalClassLoader()): Effects-of-calling:java.util.HashMap
    //#test_vector(GlobalClassLoader getGlobalClassLoader()): me: Inverse{null}, Addr_Set{null}
			me = new GlobalClassLoader();
		}
		
		return me;
    //#GlobalClassLoader.java:72: end of method: GlobalClassLoader com.dmdirc.plugins.GlobalClassLoader.getGlobalClassLoader()
	}

	/**
	 * Load the plugin with the given className.
	 *
	 * @param name Class Name of plugin
	 * @param pi The PluginInfo that contains this class
	 * @return plugin class
	 * @throws ClassNotFoundException if the class to be loaded could not be found.
	 */
	public Class<?> loadClass(final String name, final PluginInfo pi) throws ClassNotFoundException {
		for (String classname : pi.getPersistentClasses()) {
    //#GlobalClassLoader.java:84: method: Class com.dmdirc.plugins.GlobalClassLoader.loadClass(String, PluginInfo)
    //#GlobalClassLoader.java:84: ?null dereference
    //#    getPersistentClasses(...) != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: Class loadClass(String, PluginInfo)
    //#    basic block: Entry_BB_1
    //#    assertion: getPersistentClasses(...) != null
    //#    VN: getPersistentClasses(...)
    //#    Expected: Inverse{null} or Invalid
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
    //#input(Class loadClass(String, PluginInfo)): "-resourcemanagerTimer"._tainted
    //#input(Class loadClass(String, PluginInfo)): "jar:.."._tainted
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFullFilename()Ljava/lang/String;
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPersistentClasses()Ljava/util/List;
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getResourceManager()Lcom/dmdirc/util/resourcemanager/ResourceManager;
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getResourceManager(Z)Lcom/dmdirc/util/resourcemanager/ResourceManager;
    //#input(Class loadClass(String, PluginInfo)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(Class loadClass(String, PluginInfo)): name
    //#input(Class loadClass(String, PluginInfo)): pi
    //#input(Class loadClass(String, PluginInfo)): pi.__Tag
    //#input(Class loadClass(String, PluginInfo)): pi.filename
    //#input(Class loadClass(String, PluginInfo)): pi.filename._tainted
    //#input(Class loadClass(String, PluginInfo)): pi.metaData
    //#input(Class loadClass(String, PluginInfo)): pi.url
    //#input(Class loadClass(String, PluginInfo)): this
    //#input(Class loadClass(String, PluginInfo)): this.resourcesList
    //#output(Class loadClass(String, PluginInfo)): pi.myResourceManager
    //#output(Class loadClass(String, PluginInfo)): return_value
    //#pre[3] (Class loadClass(String, PluginInfo)): pi != null
    //#pre[5] (Class loadClass(String, PluginInfo)): pi.__Tag == com/dmdirc/plugins/PluginInfo
    //#pre[8] (Class loadClass(String, PluginInfo)): init'ed(pi.metaData)
    //#pre[9] (Class loadClass(String, PluginInfo)): (soft) pi.url != null
    //#pre[11] (Class loadClass(String, PluginInfo)): (soft) this.resourcesList != null
    //#post(Class loadClass(String, PluginInfo)): possibly_updated(pi.myResourceManager)
    //#post(Class loadClass(String, PluginInfo)): init'ed(return_value)
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.net.URL:getPath
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.List:add
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.String:matches
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourceManager
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.Timer
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.TimerTask
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.Timer:schedule
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourcesStartingWith
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.String:replaceAll
    //#unanalyzed(Class loadClass(String, PluginInfo)): Effects-of-calling:java.lang.String:replace
    //#test_vector(Class loadClass(String, PluginInfo)): java.util.Iterator:hasNext(...)@84: {0}, {1}
    //#test_vector(Class loadClass(String, PluginInfo)): java.util.Map:containsKey(...)@85: {1}, {0}
			if (!resourcesList.containsKey(classname)) {
				resourcesList.put(classname, pi.getFullFilename());
			}
		}
		return loadClass(name);
    //#GlobalClassLoader.java:89: Warning: call too complex - analysis skipped
    //#    call on Class loadClass(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: Class loadClass(String, PluginInfo)
    //#    unanalyzed callee: Class loadClass(String)
    //#GlobalClassLoader.java:89: end of method: Class com.dmdirc.plugins.GlobalClassLoader.loadClass(String, PluginInfo)
	}
	
	/**
	 * Load the plugin with the given className.
	 *
	 * @param name Class Name of plugin
	 * @return plugin class
	 * @throws ClassNotFoundException if the class to be loaded could not be found.
	 */
    @Override
	public Class<?> loadClass(final String name) throws ClassNotFoundException {
		try {
			return super.loadClass(name);
    //#GlobalClassLoader.java:102: method: Class com.dmdirc.plugins.GlobalClassLoader.loadClass(String)
    //#input(Class loadClass(String)): ""._tainted
    //#input(Class loadClass(String)): "' (wanted by "._tainted
    //#input(Class loadClass(String)): ") -> "._tainted
    //#input(Class loadClass(String)): ") does not exist."._tainted
    //#input(Class loadClass(String)): "-resourcemanagerTimer"._tainted
    //#input(Class loadClass(String)): ".class"._tainted
    //#input(Class loadClass(String)): "Could not load "._tainted
    //#input(Class loadClass(String)): "Error loading '"._tainted
    //#input(Class loadClass(String)): "Resource '"._tainted
    //#input(Class loadClass(String)): "jar:.."._tainted
    //#input(Class loadClass(String)): "plugins"._tainted
    //#input(Class loadClass(String)): __Class_Obj.__Lock
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[com/dmdirc/plugins/PluginClassLoader]
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginClassLoader.__Descendant_Table[others]
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.isClassLoaded(Ljava/lang/String;Z)Z
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginClassLoader.__Dispatch_Table.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[com/dmdirc/plugins/PluginInfo]
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Descendant_Table[others]
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getClassList()Ljava/util/List;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getFullFilename()Ljava/lang/String;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPersistentClasses()Ljava/util/List;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getPluginClassLoader()Lcom/dmdirc/plugins/PluginClassLoader;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getResourceManager()Lcom/dmdirc/util/resourcemanager/ResourceManager;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.getResourceManager(Z)Lcom/dmdirc/util/resourcemanager/ResourceManager;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent()Z
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginInfo.__Dispatch_Table.isPersistent(Ljava/lang/String;)Z
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.__Class_Obj.__Lock
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.__Descendant_Table[com/dmdirc/plugins/PluginManager]
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.__Descendant_Table[others]
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.__Dispatch_Table.getPluginInfos()Ljava/util/Collection;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.__Dispatch_Table.getPossiblePluginInfos(Z)Ljava/util/List;
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.me
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.me.__Tag
    //#input(Class loadClass(String)): com/dmdirc/plugins/PluginManager.me.knownPlugins
    //#input(Class loadClass(String)): me
    //#input(Class loadClass(String)): name
    //#input(Class loadClass(String)): name._tainted
    //#input(Class loadClass(String)): this
    //#input(Class loadClass(String)): this.resourcesList
    //#output(Class loadClass(String)): com/dmdirc/plugins/PluginManager.me
    //#output(Class loadClass(String)): java.lang.StringBuilder:toString(...)._tainted
    //#output(Class loadClass(String)): me
    //#output(Class loadClass(String)): new GlobalClassLoader(getGlobalClassLoader#1) num objects
    //#output(Class loadClass(String)): new GlobalClassLoader(getGlobalClassLoader#1).__Tag
    //#output(Class loadClass(String)): new GlobalClassLoader(getGlobalClassLoader#1).resourcesList
    //#output(Class loadClass(String)): new HashMap(GlobalClassLoader#1) num objects
    //#output(Class loadClass(String)): new HashMap(PluginManager#2) num objects
    //#output(Class loadClass(String)): new Hashtable(PluginManager#1) num objects
    //#output(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1) num objects
    //#output(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1).__Tag
    //#output(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1).pluginInfo
    //#output(Class loadClass(String)): new PluginManager(getPluginManager#1) num objects
    //#output(Class loadClass(String)): new PluginManager(getPluginManager#1).__Tag
    //#output(Class loadClass(String)): new PluginManager(getPluginManager#1).knownPlugins
    //#output(Class loadClass(String)): new PluginManager(getPluginManager#1).myDir
    //#output(Class loadClass(String)): new PluginManager(getPluginManager#1).services
    //#output(Class loadClass(String)): return_value
    //#new obj(Class loadClass(String)): java.lang.StringBuilder:toString(...)
    //#new obj(Class loadClass(String)): new GlobalClassLoader(getGlobalClassLoader#1)
    //#new obj(Class loadClass(String)): new HashMap(GlobalClassLoader#1)
    //#new obj(Class loadClass(String)): new HashMap(PluginManager#2)
    //#new obj(Class loadClass(String)): new Hashtable(PluginManager#1)
    //#new obj(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1)
    //#new obj(Class loadClass(String)): new PluginManager(getPluginManager#1)
    //#pre[6] (Class loadClass(String)): (soft) name != null
    //#pre[8] (Class loadClass(String)): (soft) init'ed(com/dmdirc/plugins/PluginManager.me)
    //#pre[9] (Class loadClass(String)): (soft) me != null
    //#pre[11] (Class loadClass(String)): (soft) this.resourcesList != null
    //#presumption(Class loadClass(String)): data.length <= 4_294_967_295
    //#presumption(Class loadClass(String)): getPluginClassLoader(...).__Tag@111 == com/dmdirc/plugins/PluginClassLoader
    //#presumption(Class loadClass(String)): getPluginClassLoader(...).pluginInfo.__Tag@111 == com/dmdirc/plugins/PluginInfo
    //#presumption(Class loadClass(String)): getPluginClassLoader(...).pluginInfo.url@111 != null
    //#presumption(Class loadClass(String)): getPluginClassLoader(...).pluginInfo@111 != null
    //#presumption(Class loadClass(String)): getPluginManager(...).__Tag == com/dmdirc/plugins/PluginManager
    //#presumption(Class loadClass(String)): getPluginManager(...).knownPlugins != null
    //#presumption(Class loadClass(String)): java.util.Iterator:next(...).__Tag@111 == com/dmdirc/plugins/PluginInfo
    //#presumption(Class loadClass(String)): java.util.Iterator:next(...)@111 != null
    //#presumption(Class loadClass(String)): me.resourcesList@113 != null
    //#presumption(Class loadClass(String)): pi.myClasses@111 != null
    //#post(Class loadClass(String)): com/dmdirc/plugins/PluginManager.me == One-of{old com/dmdirc/plugins/PluginManager.me, &new PluginManager(getPluginManager#1)}
    //#post(Class loadClass(String)): init'ed(com/dmdirc/plugins/PluginManager.me)
    //#post(Class loadClass(String)): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(Class loadClass(String)): init'ed(me)
    //#post(Class loadClass(String)): init'ed(return_value)
    //#post(Class loadClass(String)): new GlobalClassLoader(getGlobalClassLoader#1) num objects == 0
    //#post(Class loadClass(String)): init'ed(new GlobalClassLoader(getGlobalClassLoader#1).__Tag)
    //#post(Class loadClass(String)): init'ed(new GlobalClassLoader(getGlobalClassLoader#1).resourcesList)
    //#post(Class loadClass(String)): new HashMap(GlobalClassLoader#1) num objects == 0
    //#post(Class loadClass(String)): new HashMap(PluginManager#2) num objects <= 1
    //#post(Class loadClass(String)): new Hashtable(PluginManager#1) num objects <= 1
    //#post(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1) num objects == 0, if init'ed
    //#post(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1).__Tag not init'ed, if init'ed
    //#post(Class loadClass(String)): new PluginClassLoader(getSubClassLoader#1).pluginInfo == null
    //#post(Class loadClass(String)): new PluginManager(getPluginManager#1) num objects <= 1
    //#post(Class loadClass(String)): init'ed(new PluginManager(getPluginManager#1).__Tag)
    //#post(Class loadClass(String)): init'ed(new PluginManager(getPluginManager#1).knownPlugins)
    //#post(Class loadClass(String)): init'ed(new PluginManager(getPluginManager#1).myDir)
    //#post(Class loadClass(String)): init'ed(new PluginManager(getPluginManager#1).services)
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.ClassLoader
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.HashMap
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.GlobalClassLoader:findLoadedClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourceManager
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:replace
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:resourceExists
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourceBytes
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.GlobalClassLoader:defineClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.ClassLoader:loadClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getPluginManager
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getPluginInfos
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Collection:iterator
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getClassList
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getPluginClassLoader
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:loadClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getPersistentClasses
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getFullFilename
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Map:put
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Hashtable
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.System:getProperty
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.actions.ActionManager:addListener
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Map:values
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:toLowerCase
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getName
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:addError
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.actions.ActionManager:processEvent
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isKeyDomain
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getKeyDomain
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.List:remove
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:isFlatDomain
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.ConfigFile:getFlatDomain
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getPluginInfoByName
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:unloadPlugin
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:delProvider
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.List:clear
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:isUnloadable
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:onUnload
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.Exception:getMessage
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.Exception:printStackTrace
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.LinkedList
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.LinkedList:add
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.LinkedList:isEmpty
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.LinkedList:pop
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File:isDirectory
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File:listFiles
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File:isFile
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File:getName
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:endsWith
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File:getPath
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:length
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:substring
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:addPlugin
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.net.URL
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.PluginInfo
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.net.MalformedURLException:getMessage
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.net.URL:getPath
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:delPlugin
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.updater.components.PluginComponent
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.Exception
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.PluginException:getMessage
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Map:remove
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getPossiblePluginInfos
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:findLoadedClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:getParent
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:getResourceManager
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:isPersistent
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.NoClassDefFoundError:getMessage
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.ClassNotFoundException
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:defineClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.plugins.PluginClassLoader:resolveClass
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:matches
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Timer
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.TimerTask
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.util.Timer:schedule
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:com.dmdirc.util.resourcemanager.ResourceManager:getResourcesStartingWith
    //#unanalyzed(Class loadClass(String)): Effects-of-calling:java.lang.String:replaceAll
		} catch (ClassNotFoundException e) {
			byte[] data = getClassData(name);
			if (data != null) {
				return defineClass(name, data);
			}
		}
		
		// Check the other plugins.
		for (PluginInfo pi : PluginManager.getPluginManager().getPluginInfos()) {
			List<String> classList = pi.getClassList();
			if (classList.contains(name)) {
				if (pi.getPluginClassLoader() != null) {
					return pi.getPluginClassLoader().loadClass(name, false);
				}
			}
		}
		
		return null;
    //#GlobalClassLoader.java:120: end of method: Class com.dmdirc.plugins.GlobalClassLoader.loadClass(String)
	}
	
	/**
	 * Look in all known sources of persisant classes for file asked for.
	 *
	 * @param classname Class name to define.
	 * @param data Data to define class with.
	 */
	public Class<?> defineClass(final String classname, final byte[] data) {
		return defineClass(classname, data, 0, data.length);
    //#GlobalClassLoader.java:130: method: Class com.dmdirc.plugins.GlobalClassLoader.defineClass(String, byte[])
    //#GlobalClassLoader.java:130: Warning: method not available - call not analyzed
    //#    call on Class com.dmdirc.plugins.GlobalClassLoader:defineClass(String, byte[], int, int)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: Class defineClass(String, byte[])
    //#    unanalyzed callee: Class com.dmdirc.plugins.GlobalClassLoader:defineClass(String, byte[], int, int)
    //#input(Class defineClass(String, byte[])): classname
    //#input(Class defineClass(String, byte[])): data
    //#input(Class defineClass(String, byte[])): data.length
    //#input(Class defineClass(String, byte[])): this
    //#output(Class defineClass(String, byte[])): return_value
    //#pre[2] (Class defineClass(String, byte[])): data != null
    //#pre[3] (Class defineClass(String, byte[])): data.length <= 4_294_967_295
    //#post(Class defineClass(String, byte[])): init'ed(return_value)
    //#GlobalClassLoader.java:130: end of method: Class com.dmdirc.plugins.GlobalClassLoader.defineClass(String, byte[])
	}
	
	/**
	 * Get the requested class from its plugin jar.
	 *
	 * @param classname Class to look for.
	 */
	private byte[] getClassData(final String classname) {
		try {
			final String jarname = resourcesList.get(classname);
    //#GlobalClassLoader.java:140: method: byte[] com.dmdirc.plugins.GlobalClassLoader.getClassData(String)
    //#input(byte[] getClassData(String)): ".class"._tainted
    //#input(byte[] getClassData(String)): "jar:.."._tainted
    //#input(byte[] getClassData(String)): classname
    //#input(byte[] getClassData(String)): this
    //#input(byte[] getClassData(String)): this.resourcesList
    //#output(byte[] getClassData(String)): return_value
    //#pre[1] (byte[] getClassData(String)): (soft) classname != null
    //#pre[3] (byte[] getClassData(String)): (soft) this.resourcesList != null
    //#presumption(byte[] getClassData(String)): com.dmdirc.util.resourcemanager.ResourceManager:getResourceManager(...)@142 != null
    //#post(byte[] getClassData(String)): init'ed(return_value)
			if (jarname != null) {
				ResourceManager rm = ResourceManager.getResourceManager("jar://"+jarname);
    //#GlobalClassLoader.java:142: Warning: method not available - call not analyzed
    //#    call on ResourceManager com.dmdirc.util.resourcemanager.ResourceManager:getResourceManager(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: byte[] getClassData(String)
    //#    unanalyzed callee: ResourceManager com.dmdirc.util.resourcemanager.ResourceManager:getResourceManager(String)
				final String filename = classname.replace('.', '/')+".class";
				if (rm.resourceExists(filename)) {
    //#GlobalClassLoader.java:144: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.util.resourcemanager.ResourceManager:resourceExists(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: byte[] getClassData(String)
    //#    unanalyzed callee: bool com.dmdirc.util.resourcemanager.ResourceManager:resourceExists(String)
					return rm.getResourceBytes(filename);
    //#GlobalClassLoader.java:145: Warning: method not available - call not analyzed
    //#    call on byte[] com.dmdirc.util.resourcemanager.ResourceManager:getResourceBytes(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.plugins.GlobalClassLoader
    //#    method: byte[] getClassData(String)
    //#    unanalyzed callee: byte[] com.dmdirc.util.resourcemanager.ResourceManager:getResourceBytes(String)
				}
			}
		} catch (IOException e) {
			// File might have been deleted, oh well.
		}
		return null;
    //#GlobalClassLoader.java:151: end of method: byte[] com.dmdirc.plugins.GlobalClassLoader.getClassData(String)
	}
	
}
    //#output(com.dmdirc.plugins.GlobalClassLoader__static_init): __Descendant_Table[com/dmdirc/plugins/GlobalClassLoader]
    //#output(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.defineClass(Ljava/lang/String;[B)Ljava/lang/Class;
    //#output(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.getClassData(Ljava/lang/String;)[B
    //#output(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.isClassLoaded(Ljava/lang/String;)Z
    //#output(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.loadClass(Ljava/lang/String;)Ljava/lang/Class;
    //#output(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.loadClass(Ljava/lang/String;Lcom/dmdirc/plugins/PluginInfo;)Ljava/lang/Class;
    //#post(com.dmdirc.plugins.GlobalClassLoader__static_init): __Descendant_Table[com/dmdirc/plugins/GlobalClassLoader] == &__Dispatch_Table
    //#post(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.defineClass(Ljava/lang/String;[B)Ljava/lang/Class; == &defineClass
    //#post(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.getClassData(Ljava/lang/String;)[B == &getClassData
    //#post(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.isClassLoaded(Ljava/lang/String;)Z == &isClassLoaded
    //#post(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.loadClass(Ljava/lang/String;)Ljava/lang/Class; == &loadClass
    //#post(com.dmdirc.plugins.GlobalClassLoader__static_init): __Dispatch_Table.loadClass(Ljava/lang/String;Lcom/dmdirc/plugins/PluginInfo;)Ljava/lang/Class; == &loadClass
    //#GlobalClassLoader.java:: end of method: com.dmdirc.plugins.GlobalClassLoader.com.dmdirc.plugins.GlobalClassLoader__static_init
    //#GlobalClassLoader.java:: end of class: com.dmdirc.plugins.GlobalClassLoader
