//# 5 errors, 1,167 messages
//#
/*
    //#ErrorManager.java:1:1: class: com.dmdirc.logger.ErrorManager
 * 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.logger;

import com.dmdirc.config.ConfigManager;
import com.dmdirc.config.IdentityManager;
import com.dmdirc.interfaces.ConfigChangeListener;
import com.dmdirc.ui.FatalErrorDialog;
import com.dmdirc.util.ListenerList;

import java.awt.GraphicsEnvironment;
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Error manager.
 */
public final class ErrorManager implements Serializable, ConfigChangeListener {

    /**
     * A version number for this class. It should be changed whenever the class
     * structure is changed (or anything else that would prevent serialized
     * objects being unserialized with the new class).
     */
    private static final long serialVersionUID = 4;

    /** Previously instantiated instance of ErrorManager. */
    private static final ErrorManager me = new ErrorManager();
    //#ErrorManager.java:53: method: com.dmdirc.logger.ErrorManager.com.dmdirc.logger.ErrorManager__static_init
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Descendant_Table[com/dmdirc/logger/ErrorManager]
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;Ljava/lang/Throwable;Z)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;[Ljava/lang/String;Z)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;[Ljava/lang/String;ZZ)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ProgramError;)Z
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addErrorListener(Lcom/dmdirc/logger/ErrorListener;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.configChanged(Ljava/lang/String;Ljava/lang/String;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.deleteAll()V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.deleteError(Lcom/dmdirc/logger/ProgramError;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireErrorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireErrorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireErrorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireFatalError(Lcom/dmdirc/logger/ProgramError;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;[Ljava/lang/String;Z)Lcom/dmdirc/logger/ProgramError;
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getErrorCount()I
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getErrors()Ljava/util/List;
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getTrace(Ljava/lang/Throwable;)[Ljava/lang/String;
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.isValidError(Ljava/lang/Throwable;)Z
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.removeErrorListener(Lcom/dmdirc/logger/ErrorListener;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.sendError(Lcom/dmdirc/logger/ProgramError;)V
    //#output(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.updateSettings()V
    //#output(com.dmdirc.logger.ErrorManager__static_init): com/dmdirc/interfaces/ConfigChangeListener.__Descendant_Table[com/dmdirc/logger/ErrorManager]
    //#output(com.dmdirc.logger.ErrorManager__static_init): me
    //#output(com.dmdirc.logger.ErrorManager__static_init): new AtomicLong(ErrorManager#4) num objects
    //#output(com.dmdirc.logger.ErrorManager__static_init): new Class[](ErrorManager__static_init#2) num objects
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS.length
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[0]
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[1]
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[2]
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[3]
    //#output(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[4]
    //#output(com.dmdirc.logger.ErrorManager__static_init): new ErrorManager(ErrorManager__static_init#1) num objects
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.__Tag
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.errorListeners
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.errors
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.logReports
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.nextErrorID
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.reportQueue
    //#output(com.dmdirc.logger.ErrorManager__static_init): me.sendReports
    //#output(com.dmdirc.logger.ErrorManager__static_init): new LinkedBlockingQueue(ErrorManager#1) num objects
    //#output(com.dmdirc.logger.ErrorManager__static_init): new LinkedList(ErrorManager#3) num objects
    //#output(com.dmdirc.logger.ErrorManager__static_init): new ListenerList(ErrorManager#2) num objects
    //#new obj(com.dmdirc.logger.ErrorManager__static_init): new AtomicLong(ErrorManager#4)
    //#new obj(com.dmdirc.logger.ErrorManager__static_init): new Class[](ErrorManager__static_init#2)
    //#new obj(com.dmdirc.logger.ErrorManager__static_init): new ErrorManager(ErrorManager__static_init#1)
    //#new obj(com.dmdirc.logger.ErrorManager__static_init): new LinkedBlockingQueue(ErrorManager#1)
    //#new obj(com.dmdirc.logger.ErrorManager__static_init): new LinkedList(ErrorManager#3)
    //#new obj(com.dmdirc.logger.ErrorManager__static_init): new ListenerList(ErrorManager#2)
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS == &new Class[](ErrorManager__static_init#2)
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Descendant_Table[com/dmdirc/logger/ErrorManager] == &__Dispatch_Table
    //#post(com.dmdirc.logger.ErrorManager__static_init): com/dmdirc/interfaces/ConfigChangeListener.__Descendant_Table[com/dmdirc/logger/ErrorManager] == &__Dispatch_Table
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;)V == &addError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;Ljava/lang/Throwable;Z)V == &addError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;[Ljava/lang/String;Z)V == &addError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;[Ljava/lang/String;ZZ)V == &addError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addError(Lcom/dmdirc/logger/ProgramError;)Z == &addError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.addErrorListener(Lcom/dmdirc/logger/ErrorListener;)V == &addErrorListener
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.configChanged(Ljava/lang/String;Ljava/lang/String;)V == &configChanged
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.deleteAll()V == &deleteAll
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.deleteError(Lcom/dmdirc/logger/ProgramError;)V == &deleteError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireErrorAdded(Lcom/dmdirc/logger/ProgramError;)V == &fireErrorAdded
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireErrorDeleted(Lcom/dmdirc/logger/ProgramError;)V == &fireErrorDeleted
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireErrorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V == &fireErrorStatusChanged
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.fireFatalError(Lcom/dmdirc/logger/ProgramError;)V == &fireFatalError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getError(Lcom/dmdirc/logger/ErrorLevel;Ljava/lang/String;[Ljava/lang/String;Z)Lcom/dmdirc/logger/ProgramError; == &getError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getErrorCount()I == &getErrorCount
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getErrors()Ljava/util/List; == &getErrors
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.getTrace(Ljava/lang/Throwable;)[Ljava/lang/String; == &getTrace
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.isValidError(Ljava/lang/Throwable;)Z == &isValidError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.removeErrorListener(Lcom/dmdirc/logger/ErrorListener;)V == &removeErrorListener
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.sendError(Lcom/dmdirc/logger/ProgramError;)V == &sendError
    //#post(com.dmdirc.logger.ErrorManager__static_init): __Dispatch_Table.updateSettings()V == &updateSettings
    //#post(com.dmdirc.logger.ErrorManager__static_init): me == &new ErrorManager(ErrorManager__static_init#1)
    //#post(com.dmdirc.logger.ErrorManager__static_init): new AtomicLong(ErrorManager#4) num objects == 1
    //#post(com.dmdirc.logger.ErrorManager__static_init): new Class[](ErrorManager__static_init#2) num objects == 1
    //#post(com.dmdirc.logger.ErrorManager__static_init): new ErrorManager(ErrorManager__static_init#1) num objects == 1
    //#post(com.dmdirc.logger.ErrorManager__static_init): new LinkedBlockingQueue(ErrorManager#1) num objects == 1
    //#post(com.dmdirc.logger.ErrorManager__static_init): new LinkedList(ErrorManager#3) num objects == 1
    //#post(com.dmdirc.logger.ErrorManager__static_init): new ListenerList(ErrorManager#2) num objects == 1
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS.length == 5
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[0] == &java.lang.NoSuchMethodError.__Class_Obj
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[1] == &java.lang.NoClassDefFoundError.__Class_Obj
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[2] == &java.lang.UnsatisfiedLinkError.__Class_Obj
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[3] == &java.lang.AbstractMethodError.__Class_Obj
    //#post(com.dmdirc.logger.ErrorManager__static_init): BANNED_EXCEPTIONS[4] == &java.lang.IllegalAccessError.__Class_Obj
    //#post(com.dmdirc.logger.ErrorManager__static_init): me.__Tag == com/dmdirc/logger/ErrorManager
    //#post(com.dmdirc.logger.ErrorManager__static_init): me.errorListeners == &new ListenerList(ErrorManager#2)
    //#post(com.dmdirc.logger.ErrorManager__static_init): me.errors == &new LinkedList(ErrorManager#3)
    //#post(com.dmdirc.logger.ErrorManager__static_init): init'ed(me.logReports)
    //#post(com.dmdirc.logger.ErrorManager__static_init): me.nextErrorID == &new AtomicLong(ErrorManager#4)
    //#post(com.dmdirc.logger.ErrorManager__static_init): me.reportQueue == &new LinkedBlockingQueue(ErrorManager#1)
    //#post(com.dmdirc.logger.ErrorManager__static_init): init'ed(me.sendReports)
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionBool
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:java.util.concurrent.LinkedBlockingQueue
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:com.dmdirc.util.ListenerList
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:java.util.LinkedList
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:java.util.concurrent.atomic.AtomicLong
    //#unanalyzed(com.dmdirc.logger.ErrorManager__static_init): Effects-of-calling:com.dmdirc.config.ConfigManager:addChangeListener

    /** A list of exceptions which we don't consider bugs and thus don't report. */
    private static final Class[] BANNED_EXCEPTIONS = new Class[]{
    //#ErrorManager.java:56: end of method: com.dmdirc.logger.ErrorManager.com.dmdirc.logger.ErrorManager__static_init
        NoSuchMethodError.class, NoClassDefFoundError.class,
        UnsatisfiedLinkError.class, AbstractMethodError.class,
        IllegalAccessError.class,
    };

    /** Whether or not to send error reports. */
    private boolean sendReports;

    /** Whether or not to log error reports. */
    private boolean logReports;

    /** Queue of errors to be reported. */
    private final BlockingQueue<ProgramError> reportQueue = new LinkedBlockingQueue<ProgramError>();

    /** Thread used for sending errors. */
    private volatile Thread reportThread;

    /** Error list. */
    private final List<ProgramError> errors;

    /** Listener list. */
    private final ListenerList errorListeners = new ListenerList();
    //#ErrorManager.java:78: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.util.ListenerList()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void com.dmdirc.logger.ErrorManager()
    //#    unanalyzed callee: void com.dmdirc.util.ListenerList()

    /** Next error ID. */
    private AtomicLong nextErrorID;

    /** Creates a new instance of ErrorListDialog. */
    private ErrorManager() {
    //#ErrorManager.java:84: method: void com.dmdirc.logger.ErrorManager.com.dmdirc.logger.ErrorManager()
    //#input(void com.dmdirc.logger.ErrorManager()): this
    //#output(void com.dmdirc.logger.ErrorManager()): new AtomicLong(ErrorManager#4) num objects
    //#output(void com.dmdirc.logger.ErrorManager()): new LinkedBlockingQueue(ErrorManager#1) num objects
    //#output(void com.dmdirc.logger.ErrorManager()): new LinkedList(ErrorManager#3) num objects
    //#output(void com.dmdirc.logger.ErrorManager()): new ListenerList(ErrorManager#2) num objects
    //#output(void com.dmdirc.logger.ErrorManager()): this.errorListeners
    //#output(void com.dmdirc.logger.ErrorManager()): this.errors
    //#output(void com.dmdirc.logger.ErrorManager()): this.logReports
    //#output(void com.dmdirc.logger.ErrorManager()): this.nextErrorID
    //#output(void com.dmdirc.logger.ErrorManager()): this.reportQueue
    //#output(void com.dmdirc.logger.ErrorManager()): this.sendReports
    //#new obj(void com.dmdirc.logger.ErrorManager()): new AtomicLong(ErrorManager#4)
    //#new obj(void com.dmdirc.logger.ErrorManager()): new LinkedBlockingQueue(ErrorManager#1)
    //#new obj(void com.dmdirc.logger.ErrorManager()): new LinkedList(ErrorManager#3)
    //#new obj(void com.dmdirc.logger.ErrorManager()): new ListenerList(ErrorManager#2)
    //#presumption(void com.dmdirc.logger.ErrorManager()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@88 != null
    //#post(void com.dmdirc.logger.ErrorManager()): this.errorListeners == &new ListenerList(ErrorManager#2)
    //#post(void com.dmdirc.logger.ErrorManager()): this.errors == &new LinkedList(ErrorManager#3)
    //#post(void com.dmdirc.logger.ErrorManager()): init'ed(this.logReports)
    //#post(void com.dmdirc.logger.ErrorManager()): this.nextErrorID == &new AtomicLong(ErrorManager#4)
    //#post(void com.dmdirc.logger.ErrorManager()): this.reportQueue == &new LinkedBlockingQueue(ErrorManager#1)
    //#post(void com.dmdirc.logger.ErrorManager()): init'ed(this.sendReports)
    //#post(void com.dmdirc.logger.ErrorManager()): new AtomicLong(ErrorManager#4) num objects == 1
    //#post(void com.dmdirc.logger.ErrorManager()): new LinkedBlockingQueue(ErrorManager#1) num objects == 1
    //#post(void com.dmdirc.logger.ErrorManager()): new LinkedList(ErrorManager#3) num objects == 1
    //#post(void com.dmdirc.logger.ErrorManager()): new ListenerList(ErrorManager#2) num objects == 1
    //#unanalyzed(void com.dmdirc.logger.ErrorManager()): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(void com.dmdirc.logger.ErrorManager()): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionBool
    //#unanalyzed(void com.dmdirc.logger.ErrorManager()): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
        errors = new LinkedList<ProgramError>();
        nextErrorID = new AtomicLong();

        final ConfigManager config = IdentityManager.getGlobalConfig();
    //#ErrorManager.java:88: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void com.dmdirc.logger.ErrorManager()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()

        config.addChangeListener("general", "logerrors", this);
    //#ErrorManager.java:90: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.config.ConfigManager:addChangeListener(String, String, ConfigChangeListener)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void com.dmdirc.logger.ErrorManager()
    //#    unanalyzed callee: void com.dmdirc.config.ConfigManager:addChangeListener(String, String, ConfigChangeListener)
        config.addChangeListener("general", "submitErrors", this);
    //#ErrorManager.java:91: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.config.ConfigManager:addChangeListener(String, String, ConfigChangeListener)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void com.dmdirc.logger.ErrorManager()
    //#    unanalyzed callee: void com.dmdirc.config.ConfigManager:addChangeListener(String, String, ConfigChangeListener)
        config.addChangeListener("temp", "noerrorreporting", this);
    //#ErrorManager.java:92: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.config.ConfigManager:addChangeListener(String, String, ConfigChangeListener)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void com.dmdirc.logger.ErrorManager()
    //#    unanalyzed callee: void com.dmdirc.config.ConfigManager:addChangeListener(String, String, ConfigChangeListener)

        updateSettings();
    }
    //#ErrorManager.java:95: end of method: void com.dmdirc.logger.ErrorManager.com.dmdirc.logger.ErrorManager()

    /**
     * Returns the instance of ErrorManager.
     *
     * @return Instance of ErrorManager
     */
    public static ErrorManager getErrorManager() {
        synchronized (me) {
    //#ErrorManager.java:103: method: ErrorManager com.dmdirc.logger.ErrorManager.getErrorManager()
    //#input(ErrorManager getErrorManager()): me
    //#input(ErrorManager getErrorManager()): return_value.__Lock
    //#output(ErrorManager getErrorManager()): return_value
    //#post(ErrorManager getErrorManager()): return_value == &new ErrorManager(ErrorManager__static_init#1)
            return me;
        }
    //#ErrorManager.java:105: end of method: ErrorManager com.dmdirc.logger.ErrorManager.getErrorManager()
    }

    /**
     * Adds a new error to the manager with the specified details. It is
     * assumed that errors without exceptions or details are not application
     * errors.
     *
     * @param level The severity of the error
     * @param message The error message
     * @since 0.6.3m1
     */
    protected void addError(final ErrorLevel level, final String message) {
        addError(level, message, new String[0], false);
    //#ErrorManager.java:118: method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String)
    //#input(void addError(ErrorLevel, String)): "&#09;"._tainted
    //#input(void addError(ErrorLevel, String)): "-"._tainted
    //#input(void addError(ErrorLevel, String)): ".log"._tainted
    //#input(void addError(ErrorLevel, String)): ": "._tainted
    //#input(void addError(ErrorLevel, String)): "A fatal error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String)): "An error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String)): "Date:"._tainted
    //#input(void addError(ErrorLevel, String)): "Description: "._tainted
    //#input(void addError(ErrorLevel, String)): "ID must be a positive integer: "._tainted
    //#input(void addError(ErrorLevel, String)): "Level: "._tainted
    //#input(void addError(ErrorLevel, String)): "errors"._tainted
    //#input(void addError(ErrorLevel, String)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(void addError(ErrorLevel, String)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(void addError(ErrorLevel, String)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(void addError(ErrorLevel, String)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void addError(ErrorLevel, String)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.errorDir
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.writingSem
    //#input(void addError(ErrorLevel, String)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void addError(ErrorLevel, String)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String)): java.lang.System.err
    //#input(void addError(ErrorLevel, String)): level
    //#input(void addError(ErrorLevel, String)): level._tainted
    //#input(void addError(ErrorLevel, String)): me
    //#input(void addError(ErrorLevel, String)): message
    //#input(void addError(ErrorLevel, String)): message._tainted
    //#input(void addError(ErrorLevel, String)): me.errorListeners
    //#input(void addError(ErrorLevel, String)): this
    //#input(void addError(ErrorLevel, String)): this.errorListeners
    //#input(void addError(ErrorLevel, String)): this.errors
    //#input(void addError(ErrorLevel, String)): this.logReports
    //#input(void addError(ErrorLevel, String)): this.nextErrorID
    //#input(void addError(ErrorLevel, String)): this.reportQueue
    //#input(void addError(ErrorLevel, String)): this.reportThread
    //#input(void addError(ErrorLevel, String)): this.sendReports
    //#output(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.errorDir
    //#output(void addError(ErrorLevel, String)): new ErrorReportingThread(sendError#1) num objects
    //#output(void addError(ErrorLevel, String)): new ErrorReportingThread(sendError#1).__Tag
    //#output(void addError(ErrorLevel, String)): new ErrorReportingThread(sendError#1).queue
    //#output(void addError(ErrorLevel, String)): new File(getErrorFile#1) num objects
    //#output(void addError(ErrorLevel, String)): this.reportThread
    //#new obj(void addError(ErrorLevel, String)): new ErrorReportingThread(sendError#1)
    //#new obj(void addError(ErrorLevel, String)): new File(getErrorFile#1)
    //#pre[2] (void addError(ErrorLevel, String)): level != null
    //#pre[4] (void addError(ErrorLevel, String)): message != null
    //#pre[11] (void addError(ErrorLevel, String)): this.errors != null
    //#pre[13] (void addError(ErrorLevel, String)): init'ed(this.logReports)
    //#pre[14] (void addError(ErrorLevel, String)): this.nextErrorID != null
    //#pre[1] (void addError(ErrorLevel, String)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[7] (void addError(ErrorLevel, String)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[8] (void addError(ErrorLevel, String)): (soft) init'ed(this.reportThread)
    //#pre[10] (void addError(ErrorLevel, String)): (soft) this.errorListeners != null
    //#pre[15] (void addError(ErrorLevel, String)): (soft) this.reportQueue != null
    //#pre[16] (void addError(ErrorLevel, String)): (soft) init'ed(this.sendReports)
    //#post(void addError(ErrorLevel, String)): com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &new File(getErrorFile#1)}
    //#post(void addError(ErrorLevel, String)): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(void addError(ErrorLevel, String)): this.reportThread == old this.reportThread
    //#post(void addError(ErrorLevel, String)): init'ed(this.reportThread)
    //#post(void addError(ErrorLevel, String)): new ErrorReportingThread(sendError#1) num objects == 0
    //#post(void addError(ErrorLevel, String)): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(void addError(ErrorLevel, String)): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(void addError(ErrorLevel, String)): new File(getErrorFile#1) num objects <= 1
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Date
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:getErrorManager
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:equals
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:getReportStatus
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:isReady
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:errorAdded
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.File
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void addError(ErrorLevel, String)): Effects-of-calling:java.util.Arrays:equals
    }
    //#ErrorManager.java:119: end of method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String)

    /**
     * Adds a new error to the manager with the specified details.
     *
     * @param level The severity of the error
     * @param message The error message
     * @param exception The exception that caused this error
     * @param appError Whether or not this is an application error
     * @since 0.6.3m1
     */
    protected void addError(final ErrorLevel level, final String message,
            final Throwable exception, final boolean appError) {
        addError(level, message, getTrace(exception), appError, isValidError(exception));
    //#ErrorManager.java:132: method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String, Throwable, bool)
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "&#09;"._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "&#10;Which caused: "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "-"._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): ".log"._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): ": "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "A fatal error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "An error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "Date:"._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "Description: "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "ID must be a positive integer: "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "Level: "._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): "errors"._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): BANNED_EXCEPTIONS
    //#input(void addError(ErrorLevel, String, Throwable, bool)): appError
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.errorDir
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.writingSem
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String, Throwable, bool)): exception
    //#input(void addError(ErrorLevel, String, Throwable, bool)): exception._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): java.lang.System.err
    //#input(void addError(ErrorLevel, String, Throwable, bool)): level
    //#input(void addError(ErrorLevel, String, Throwable, bool)): level._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): me
    //#input(void addError(ErrorLevel, String, Throwable, bool)): message
    //#input(void addError(ErrorLevel, String, Throwable, bool)): message._tainted
    //#input(void addError(ErrorLevel, String, Throwable, bool)): BANNED_EXCEPTIONS.length
    //#input(void addError(ErrorLevel, String, Throwable, bool)): BANNED_EXCEPTIONS[0..4_294_967_295]
    //#input(void addError(ErrorLevel, String, Throwable, bool)): me.errorListeners
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.errorListeners
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.errors
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.logReports
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.nextErrorID
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.reportQueue
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.reportThread
    //#input(void addError(ErrorLevel, String, Throwable, bool)): this.sendReports
    //#output(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.errorDir
    //#output(void addError(ErrorLevel, String, Throwable, bool)): new ErrorReportingThread(sendError#1) num objects
    //#output(void addError(ErrorLevel, String, Throwable, bool)): new ErrorReportingThread(sendError#1).__Tag
    //#output(void addError(ErrorLevel, String, Throwable, bool)): new ErrorReportingThread(sendError#1).queue
    //#output(void addError(ErrorLevel, String, Throwable, bool)): new File(getErrorFile#1) num objects
    //#output(void addError(ErrorLevel, String, Throwable, bool)): this.reportThread
    //#new obj(void addError(ErrorLevel, String, Throwable, bool)): new ErrorReportingThread(sendError#1)
    //#new obj(void addError(ErrorLevel, String, Throwable, bool)): new File(getErrorFile#1)
    //#pre[5] (void addError(ErrorLevel, String, Throwable, bool)): level != null
    //#pre[7] (void addError(ErrorLevel, String, Throwable, bool)): message != null
    //#pre[15] (void addError(ErrorLevel, String, Throwable, bool)): this.errors != null
    //#pre[17] (void addError(ErrorLevel, String, Throwable, bool)): init'ed(this.logReports)
    //#pre[18] (void addError(ErrorLevel, String, Throwable, bool)): this.nextErrorID != null
    //#pre[2] (void addError(ErrorLevel, String, Throwable, bool)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[9] (void addError(ErrorLevel, String, Throwable, bool)): (soft) BANNED_EXCEPTIONS[0..4_294_967_295] != null
    //#pre[11] (void addError(ErrorLevel, String, Throwable, bool)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[12] (void addError(ErrorLevel, String, Throwable, bool)): (soft) init'ed(this.reportThread)
    //#pre[14] (void addError(ErrorLevel, String, Throwable, bool)): (soft) this.errorListeners != null
    //#pre[19] (void addError(ErrorLevel, String, Throwable, bool)): (soft) this.reportQueue != null
    //#pre[20] (void addError(ErrorLevel, String, Throwable, bool)): (soft) init'ed(this.sendReports)
    //#presumption(void addError(ErrorLevel, String, Throwable, bool)): getTrace(...).length <= 4_294_967_295
    //#post(void addError(ErrorLevel, String, Throwable, bool)): com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &new File(getErrorFile#1)}
    //#post(void addError(ErrorLevel, String, Throwable, bool)): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(void addError(ErrorLevel, String, Throwable, bool)): this.reportThread == One-of{old this.reportThread, &new ErrorReportingThread(sendError#1)}
    //#post(void addError(ErrorLevel, String, Throwable, bool)): init'ed(this.reportThread)
    //#post(void addError(ErrorLevel, String, Throwable, bool)): new ErrorReportingThread(sendError#1) num objects <= 1
    //#post(void addError(ErrorLevel, String, Throwable, bool)): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(void addError(ErrorLevel, String, Throwable, bool)): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(void addError(ErrorLevel, String, Throwable, bool)): new File(getErrorFile#1) num objects <= 1
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Date
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:getErrorManager
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Throwable:getStackTrace
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Throwable:toString
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.StackTraceElement:toString
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Throwable:getCause
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:getTrace
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.Object:equals
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:equals
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:getReportStatus
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:isReady
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:errorAdded
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.File
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void addError(ErrorLevel, String, Throwable, bool)): Effects-of-calling:java.util.Arrays:equals
    }
    //#ErrorManager.java:133: end of method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String, Throwable, bool)

    /**
     * Adds a new error to the manager with the specified details.
     *
     * @param level The severity of the error
     * @param message The error message
     * @param details The details of the exception
     * @param appError Whether or not this is an application error
     * @since 0.6.3m1
     */
    protected void addError(final ErrorLevel level, final String message,
            final String[] details, final boolean appError) {
        addError(level, message, details, appError, true);
    //#ErrorManager.java:146: method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String, String[], bool)
    //#input(void addError(ErrorLevel, String, String[], bool)): "&#09;"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "-"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): ".log"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): ": "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "A fatal error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "An error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "Date:"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "Description: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "ID must be a positive integer: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "Level: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): "errors"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): appError
    //#input(void addError(ErrorLevel, String, String[], bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(void addError(ErrorLevel, String, String[], bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(void addError(ErrorLevel, String, String[], bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(void addError(ErrorLevel, String, String[], bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void addError(ErrorLevel, String, String[], bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.errorDir
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.writingSem
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String, String[], bool)): details
    //#input(void addError(ErrorLevel, String, String[], bool)): details.length
    //#input(void addError(ErrorLevel, String, String[], bool)): java.lang.System.err
    //#input(void addError(ErrorLevel, String, String[], bool)): level
    //#input(void addError(ErrorLevel, String, String[], bool)): level._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): me
    //#input(void addError(ErrorLevel, String, String[], bool)): message
    //#input(void addError(ErrorLevel, String, String[], bool)): message._tainted
    //#input(void addError(ErrorLevel, String, String[], bool)): me.errorListeners
    //#input(void addError(ErrorLevel, String, String[], bool)): this
    //#input(void addError(ErrorLevel, String, String[], bool)): this.errorListeners
    //#input(void addError(ErrorLevel, String, String[], bool)): this.errors
    //#input(void addError(ErrorLevel, String, String[], bool)): this.logReports
    //#input(void addError(ErrorLevel, String, String[], bool)): this.nextErrorID
    //#input(void addError(ErrorLevel, String, String[], bool)): this.reportQueue
    //#input(void addError(ErrorLevel, String, String[], bool)): this.reportThread
    //#input(void addError(ErrorLevel, String, String[], bool)): this.sendReports
    //#output(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.errorDir
    //#output(void addError(ErrorLevel, String, String[], bool)): new ErrorReportingThread(sendError#1) num objects
    //#output(void addError(ErrorLevel, String, String[], bool)): new ErrorReportingThread(sendError#1).__Tag
    //#output(void addError(ErrorLevel, String, String[], bool)): new ErrorReportingThread(sendError#1).queue
    //#output(void addError(ErrorLevel, String, String[], bool)): new File(getErrorFile#1) num objects
    //#output(void addError(ErrorLevel, String, String[], bool)): this.reportThread
    //#new obj(void addError(ErrorLevel, String, String[], bool)): new ErrorReportingThread(sendError#1)
    //#new obj(void addError(ErrorLevel, String, String[], bool)): new File(getErrorFile#1)
    //#pre[3] (void addError(ErrorLevel, String, String[], bool)): details != null
    //#pre[4] (void addError(ErrorLevel, String, String[], bool)): details.length <= 4_294_967_295
    //#pre[5] (void addError(ErrorLevel, String, String[], bool)): level != null
    //#pre[7] (void addError(ErrorLevel, String, String[], bool)): message != null
    //#pre[14] (void addError(ErrorLevel, String, String[], bool)): this.errors != null
    //#pre[16] (void addError(ErrorLevel, String, String[], bool)): init'ed(this.logReports)
    //#pre[17] (void addError(ErrorLevel, String, String[], bool)): this.nextErrorID != null
    //#pre[2] (void addError(ErrorLevel, String, String[], 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] (void addError(ErrorLevel, String, String[], bool)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[11] (void addError(ErrorLevel, String, String[], bool)): (soft) init'ed(this.reportThread)
    //#pre[13] (void addError(ErrorLevel, String, String[], bool)): (soft) this.errorListeners != null
    //#pre[18] (void addError(ErrorLevel, String, String[], bool)): (soft) this.reportQueue != null
    //#pre[19] (void addError(ErrorLevel, String, String[], bool)): (soft) init'ed(this.sendReports)
    //#post(void addError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &new File(getErrorFile#1)}
    //#post(void addError(ErrorLevel, String, String[], bool)): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(void addError(ErrorLevel, String, String[], bool)): this.reportThread == One-of{old this.reportThread, &new ErrorReportingThread(sendError#1)}
    //#post(void addError(ErrorLevel, String, String[], bool)): init'ed(this.reportThread)
    //#post(void addError(ErrorLevel, String, String[], bool)): new ErrorReportingThread(sendError#1) num objects <= 1
    //#post(void addError(ErrorLevel, String, String[], bool)): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(void addError(ErrorLevel, String, String[], bool)): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(void addError(ErrorLevel, String, String[], bool)): new File(getErrorFile#1) num objects <= 1
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Date
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:getErrorManager
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:getReportStatus
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:isReady
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:errorAdded
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.File
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Arrays:equals
    }
    //#ErrorManager.java:147: end of method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String, String[], bool)

    /**
     * Adds a new error to the manager with the specified details.
     *
     * @param level The severity of the error
     * @param message The error message
     * @param details The details of the exception
     * @param appError Whether or not this is an application error
     * @param canReport Whether or not this error can be reported
     * @since 0.6.3m1
     */
    protected void addError(final ErrorLevel level, final String message,
            final String[] details, final boolean appError, final boolean canReport) {
        final ProgramError error = getError(level, message, details, appError);
    //#ErrorManager.java:161: method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String, String[], bool, bool)
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "&#09;"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "-"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): ".log"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): ": "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "A fatal error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "An error has occurred: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "Date:"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "Description: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "ID must be a positive integer: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "Level: "._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): "errors"._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): appError
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): canReport
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#1).terminal
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6).terminal
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorFixedStatus.UNREPORTED
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorLevel.FATAL
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorReportStatus.NOT_APPLICABLE
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.errorDir
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.java.lang.System.err
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.writingSem
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): details
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): details.length
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): java.lang.System.err
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): level
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): level._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): me
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): message
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): message._tainted
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): me.errorListeners
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.errorListeners
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.errors
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.logReports
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.nextErrorID
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.reportQueue
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.reportThread
    //#input(void addError(ErrorLevel, String, String[], bool, bool)): this.sendReports
    //#output(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.errorDir
    //#output(void addError(ErrorLevel, String, String[], bool, bool)): new ErrorReportingThread(sendError#1) num objects
    //#output(void addError(ErrorLevel, String, String[], bool, bool)): new ErrorReportingThread(sendError#1).__Tag
    //#output(void addError(ErrorLevel, String, String[], bool, bool)): new ErrorReportingThread(sendError#1).queue
    //#output(void addError(ErrorLevel, String, String[], bool, bool)): new File(getErrorFile#1) num objects
    //#output(void addError(ErrorLevel, String, String[], bool, bool)): this.reportThread
    //#new obj(void addError(ErrorLevel, String, String[], bool, bool)): new ErrorReportingThread(sendError#1)
    //#new obj(void addError(ErrorLevel, String, String[], bool, bool)): new File(getErrorFile#1)
    //#pre[4] (void addError(ErrorLevel, String, String[], bool, bool)): details != null
    //#pre[5] (void addError(ErrorLevel, String, String[], bool, bool)): details.length <= 4_294_967_295
    //#pre[6] (void addError(ErrorLevel, String, String[], bool, bool)): level != null
    //#pre[8] (void addError(ErrorLevel, String, String[], bool, bool)): message != null
    //#pre[15] (void addError(ErrorLevel, String, String[], bool, bool)): this.errors != null
    //#pre[17] (void addError(ErrorLevel, String, String[], bool, bool)): init'ed(this.logReports)
    //#pre[18] (void addError(ErrorLevel, String, String[], bool, bool)): this.nextErrorID != null
    //#pre[3] (void addError(ErrorLevel, String, String[], bool, bool)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[11] (void addError(ErrorLevel, String, String[], bool, bool)): (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#pre[12] (void addError(ErrorLevel, String, String[], bool, bool)): (soft) init'ed(this.reportThread)
    //#pre[14] (void addError(ErrorLevel, String, String[], bool, bool)): (soft) this.errorListeners != null
    //#pre[19] (void addError(ErrorLevel, String, String[], bool, bool)): (soft) this.reportQueue != null
    //#pre[20] (void addError(ErrorLevel, String, String[], bool, bool)): (soft) init'ed(this.sendReports)
    //#presumption(void addError(ErrorLevel, String, String[], bool, bool)): error.trace.length in {1..4_294_967_295}
    //#presumption(void addError(ErrorLevel, String, String[], bool, bool)): error.trace[0] != null
    //#presumption(void addError(ErrorLevel, String, String[], bool, bool)): error.trace[1..4_294_967_295] != null
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &new File(getErrorFile#1)}
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): init'ed(com/dmdirc/logger/ProgramError.errorDir)
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): this.reportThread == One-of{old this.reportThread, &new ErrorReportingThread(sendError#1)}
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): init'ed(this.reportThread)
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): new ErrorReportingThread(sendError#1) num objects <= 1
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): init'ed(new ErrorReportingThread(sendError#1).__Tag)
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): init'ed(new ErrorReportingThread(sendError#1).queue)
    //#post(void addError(ErrorLevel, String, String[], bool, bool)): new File(getErrorFile#1) num objects <= 1
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.concurrent.atomic.AtomicLong:getAndIncrement
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Date
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.List:contains
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:getErrorManager
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.concurrent.BlockingQueue:add
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Thread:isAlive
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.awt.GraphicsEnvironment:isHeadless
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Object:wait
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:getReportStatus
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:isReady
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:errorAdded
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.File:exists
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.File
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.OutputStream
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.PrintWriter
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.PrintWriter:println
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.io.PrintWriter:close
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void addError(ErrorLevel, String, String[], bool, bool)): Effects-of-calling:java.util.Arrays:equals
    //#test_vector(void addError(ErrorLevel, String, String[], bool, bool)): appError: {0}, {1}
    //#test_vector(void addError(ErrorLevel, String, String[], bool, bool)): canReport: {0}, {1}
    //#test_vector(void addError(ErrorLevel, String, String[], bool, bool)): this.logReports: {0}, {1}
    //#test_vector(void addError(ErrorLevel, String, String[], bool, bool)): this.sendReports: {0}, {1}

        if (addError(error) && canReport) {
            error.setReportStatus(ErrorReportStatus.NOT_APPLICABLE);
            error.setFixedStatus(ErrorFixedStatus.KNOWN);
        } else if (!canReport || (appError && !error.isValidSource())) {
    //#ErrorManager.java:166: ?precondition failure
    //#    com/dmdirc/logger/ProgramError.isValidSource: this.trace != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void addError(ErrorLevel, String, String[], bool, bool)
    //#    basic block: bb_6
    //#    assertion: new ProgramError(getError#1).trace != null
    //#    callee: bool com/dmdirc/logger/ProgramError.isValidSource()
    //#    callee assertion: this.trace != null
    //#    callee file: ProgramError.java
    //#    callee precondition index: [2]
    //#    callee srcpos: 357
    //#    VN: new ProgramError(getError#1).trace
    //#    Expected: Inverse{null}
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
            error.setReportStatus(ErrorReportStatus.NOT_APPLICABLE);
            error.setFixedStatus(ErrorFixedStatus.INVALID);
        } else if (!appError) {
            error.setReportStatus(ErrorReportStatus.NOT_APPLICABLE);
            error.setFixedStatus(ErrorFixedStatus.UNREPORTED);
        } else if (sendReports) {
            sendError(error);
        }

        if (logReports) {
            error.save();
    //#ErrorManager.java:177: ?precondition failure
    //#    com/dmdirc/logger/ProgramError.save: this.trace != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void addError(ErrorLevel, String, String[], bool, bool)
    //#    basic block: bb_13
    //#    assertion: new ProgramError(getError#1).trace != null
    //#    callee: void com/dmdirc/logger/ProgramError.save()
    //#    callee assertion: this.trace != null
    //#    callee file: ProgramError.java
    //#    callee precondition index: [8]
    //#    callee srcpos: 223
    //#    VN: new ProgramError(getError#1).trace
    //#    Expected: Inverse{null}
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
        }

        if (level == ErrorLevel.FATAL) {
            fireFatalError(error);
    //#ErrorManager.java:181: ?precondition failure
    //#    com/dmdirc/logger/ErrorManager.fireFatalError: (soft) error.trace != null
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void addError(ErrorLevel, String, String[], bool, bool)
    //#    basic block: bb_15
    //#    assertion: (soft) new ProgramError(getError#1).trace != null
    //#    callee: void com/dmdirc/logger/ErrorManager.fireFatalError(ProgramError)
    //#    callee assertion: (soft) error.trace != null
    //#    callee file: ErrorManager.java
    //#    callee precondition index: [6]
    //#    callee srcpos: 405
    //#    VN: new ProgramError(getError#1).trace
    //#    Expected: Inverse{null}
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad  Soft
        } else {
            fireErrorAdded(error);
    //#ErrorManager.java:183: ?precondition failure
    //#    com/dmdirc/logger/ErrorManager.fireErrorAdded: error.trace != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void addError(ErrorLevel, String, String[], bool, bool)
    //#    basic block: bb_16
    //#    assertion: new ProgramError(getError#1).trace != null
    //#    callee: void com/dmdirc/logger/ErrorManager.fireErrorAdded(ProgramError)
    //#    callee assertion: error.trace != null
    //#    callee file: ErrorManager.java
    //#    callee precondition index: [6]
    //#    callee srcpos: 380
    //#    VN: new ProgramError(getError#1).trace
    //#    Expected: Inverse{null}
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
        }
    }
    //#ErrorManager.java:185: end of method: void com.dmdirc.logger.ErrorManager.addError(ErrorLevel, String, String[], bool, bool)

    /**
     * Adds the specified error to the list of known errors and determines if
     * it was previously added.
     *
     * @param error The error to be added
     * @return True if a duplicate error has already been registered, false
     * otherwise
     */
    protected boolean addError(final ProgramError error) {
        boolean res = false;
    //#ErrorManager.java:196: method: bool com.dmdirc.logger.ErrorManager.addError(ProgramError)
    //#ErrorManager.java:196: Warning: unused assignment
    //#    Unused assignment into res
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: bool addError(ProgramError)
    //#    Attribs:  Uncertain
    //#input(bool addError(ProgramError)): error
    //#input(bool addError(ProgramError)): this
    //#input(bool addError(ProgramError)): this.errors
    //#input(bool addError(ProgramError)): this.errors.__Lock
    //#output(bool addError(ProgramError)): return_value
    //#pre[3] (bool addError(ProgramError)): this.errors != null
    //#post(bool addError(ProgramError)): init'ed(return_value)

        synchronized (errors) {
            res = errors.contains(error);
            errors.add(error);
        }

        return res;
    //#ErrorManager.java:203: end of method: bool com.dmdirc.logger.ErrorManager.addError(ProgramError)
    }

    /**
     * Retrieves a {@link ProgramError} that represents the specified details.
     *
     * @param level The severity of the error
     * @param message The error message
     * @param details The details of the exception
     * @param appError Whether or not this is an application error
     * @since 0.6.3m1
     * @return A corresponding ProgramError
     */
    protected ProgramError getError(final ErrorLevel level, final String message,
            final String[] details, final boolean appError) {
        return new ProgramError(nextErrorID.getAndIncrement(), level, message,
    //#ErrorManager.java:218: method: ProgramError com.dmdirc.logger.ErrorManager.getError(ErrorLevel, String, String[], bool)
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): "ID must be a positive integer: "._tainted
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): details
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): details.length
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): level
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): message
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): this
    //#input(ProgramError getError(ErrorLevel, String, String[], bool)): this.nextErrorID
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): new ProgramError(getError#1) num objects
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.__Tag
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.date
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.fixedStatus
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.id
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.level
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.message
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.reportStatus
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.trace
    //#output(ProgramError getError(ErrorLevel, String, String[], bool)): return_value
    //#new obj(ProgramError getError(ErrorLevel, String, String[], bool)): new ProgramError(getError#1)
    //#pre[1] (ProgramError getError(ErrorLevel, String, String[], bool)): details != null
    //#pre[2] (ProgramError getError(ErrorLevel, String, String[], bool)): details.length <= 4_294_967_295
    //#pre[3] (ProgramError getError(ErrorLevel, String, String[], bool)): level != null
    //#pre[4] (ProgramError getError(ErrorLevel, String, String[], bool)): message != null
    //#pre[6] (ProgramError getError(ErrorLevel, String, String[], bool)): this.nextErrorID != null
    //#presumption(ProgramError getError(ErrorLevel, String, String[], bool)): java.util.concurrent.atomic.AtomicLong:getAndIncrement(...)@218 >= 0
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value == &new ProgramError(getError#1)
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): new ProgramError(getError#1) num objects == 1
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.__Tag == com/dmdirc/logger/ProgramError
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.date != null
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.fixedStatus == &com.dmdirc.logger.ErrorFixedStatus__static_init.new ErrorFixedStatus(ErrorFixedStatus__static_init#7)
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.id >= 0
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.level == level
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.level != null
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.message == message
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.message != null
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): return_value.reportStatus == &com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6)
    //#post(ProgramError getError(ErrorLevel, String, String[], bool)): init'ed(return_value.trace)
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.IllegalArgumentException
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(ProgramError getError(ErrorLevel, String, String[], bool)): Effects-of-calling:java.util.Date:clone
    //#ErrorManager.java:218: end of method: ProgramError com.dmdirc.logger.ErrorManager.getError(ErrorLevel, String, String[], bool)
                details, new Date());
    }

    /**
     * Determines whether or not the specified exception is one that we are
     * willing to report.
     *
     * @param exception The exception to test
     * @since 0.6.3m1
     * @return True if the exception may be reported, false otherwise
     */
    protected boolean isValidError(final Throwable exception) {
        Throwable target = exception;
    //#ErrorManager.java:231: method: bool com.dmdirc.logger.ErrorManager.isValidError(Throwable)
    //#input(bool isValidError(Throwable)): BANNED_EXCEPTIONS
    //#input(bool isValidError(Throwable)): exception
    //#input(bool isValidError(Throwable)): BANNED_EXCEPTIONS.length
    //#input(bool isValidError(Throwable)): BANNED_EXCEPTIONS[0..4_294_967_295]
    //#output(bool isValidError(Throwable)): return_value
    //#pre[2] (bool isValidError(Throwable)): (soft) BANNED_EXCEPTIONS[0..4_294_967_295] != null
    //#post(bool isValidError(Throwable)): init'ed(return_value)
    //#test_vector(bool isValidError(Throwable)): java.lang.Object:equals(...)@235: {0}, {1}

        while (target != null) {
            for (Class bad : BANNED_EXCEPTIONS) {
                if (bad.equals(target.getClass())) {
                    return false;
                }
            }

            target = target.getCause();
        }

        return true;
    //#ErrorManager.java:243: end of method: bool com.dmdirc.logger.ErrorManager.isValidError(Throwable)
    }

    /**
     * Converts an exception into a string array.
     *
     * @param throwable Exception to convert
     * @since 0.6.3m1
     * @return Exception string array
     */
    protected String[] getTrace(final Throwable throwable) {
        String[] trace;

        if (throwable == null) {
    //#ErrorManager.java:256: method: String[] com.dmdirc.logger.ErrorManager.getTrace(Throwable)
    //#input(String[] getTrace(Throwable)): "&#10;Which caused: "._tainted
    //#input(String[] getTrace(Throwable)): this
    //#input(String[] getTrace(Throwable)): throwable
    //#input(String[] getTrace(Throwable)): throwable._tainted
    //#output(String[] getTrace(Throwable)): java.lang.StackTraceElement:toString(...)._tainted
    //#output(String[] getTrace(Throwable)): java.lang.StringBuilder:toString(...)._tainted
    //#output(String[] getTrace(Throwable)): java.lang.Throwable:toString(...)._tainted
    //#output(String[] getTrace(Throwable)): new String[](getTrace#1) num objects
    //#output(String[] getTrace(Throwable)): new String[](getTrace#1).length
    //#output(String[] getTrace(Throwable)): new String[](getTrace#1)[0]
    //#output(String[] getTrace(Throwable)): new String[](getTrace#1)[1..+Inf]
    //#output(String[] getTrace(Throwable)): new String[](getTrace#2) num objects
    //#output(String[] getTrace(Throwable)): new String[](getTrace#2).length
    //#output(String[] getTrace(Throwable)): new String[](getTrace#2)[0]
    //#output(String[] getTrace(Throwable)): new String[](getTrace#2)[1..+Inf]
    //#output(String[] getTrace(Throwable)): new String[](getTrace#3) num objects
    //#output(String[] getTrace(Throwable)): new String[](getTrace#3).length
    //#output(String[] getTrace(Throwable)): new String[](getTrace#3)[0..+Inf]
    //#output(String[] getTrace(Throwable)): return_value
    //#new obj(String[] getTrace(Throwable)): java.lang.StackTraceElement:toString(...)
    //#new obj(String[] getTrace(Throwable)): java.lang.StringBuilder:toString(...)
    //#new obj(String[] getTrace(Throwable)): java.lang.Throwable:toString(...)
    //#new obj(String[] getTrace(Throwable)): new String[](getTrace#1)
    //#new obj(String[] getTrace(Throwable)): new String[](getTrace#2)
    //#new obj(String[] getTrace(Throwable)): new String[](getTrace#3)
    //#presumption(String[] getTrace(Throwable)): java.lang.Throwable:getStackTrace(...)@259 != null
    //#presumption(String[] getTrace(Throwable)): traceElements.length@259 <= 4_294_967_295
    //#presumption(String[] getTrace(Throwable)): traceElements[i]@259 != null
    //#post(String[] getTrace(Throwable)): java.lang.StackTraceElement:toString(...)._tainted == 0
    //#post(String[] getTrace(Throwable)): possibly_updated(java.lang.StackTraceElement:toString(...)._tainted)
    //#post(String[] getTrace(Throwable)): init'ed(java.lang.StringBuilder:toString(...)._tainted)
    //#post(String[] getTrace(Throwable)): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(String[] getTrace(Throwable)): possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
    //#post(String[] getTrace(Throwable)): init'ed(java.lang.Throwable:toString(...)._tainted)
    //#post(String[] getTrace(Throwable)): java.lang.Throwable:toString(...)._tainted == 0
    //#post(String[] getTrace(Throwable)): possibly_updated(java.lang.Throwable:toString(...)._tainted)
    //#post(String[] getTrace(Throwable)): return_value == One-of{&new String[](getTrace#1), &new String[](getTrace#2), &new String[](getTrace#3)}
    //#post(String[] getTrace(Throwable)): return_value in Addr_Set{&new String[](getTrace#2),&new String[](getTrace#3),&new String[](getTrace#1)}
    //#post(String[] getTrace(Throwable)): new String[](getTrace#1) num objects <= 1
    //#post(String[] getTrace(Throwable)): new String[](getTrace#1).length == 0
    //#post(String[] getTrace(Throwable)): new String[](getTrace#1)[0] == null
    //#post(String[] getTrace(Throwable)): new String[](getTrace#1)[1..+Inf] == null
    //#post(String[] getTrace(Throwable)): new String[](getTrace#2) num objects <= 1
    //#post(String[] getTrace(Throwable)): new String[](getTrace#2).length in {1..4_294_967_296}
    //#post(String[] getTrace(Throwable)): new String[](getTrace#2)[0] in Addr_Set{&java.lang.Throwable:toString(...),&java.lang.StringBuilder:toString(...)}
    //#post(String[] getTrace(Throwable)): new String[](getTrace#2)[1..+Inf] in Addr_Set{null,&java.lang.StackTraceElement:toString(...)}
    //#post(String[] getTrace(Throwable)): new String[](getTrace#3) num objects <= 1
    //#post(String[] getTrace(Throwable)): new String[](getTrace#3).length >= 1
    //#post(String[] getTrace(Throwable)): possibly_updated(new String[](getTrace#3)[0..+Inf])
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.Throwable:getStackTrace
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.Throwable:toString
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.StackTraceElement:toString
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:java.lang.Throwable:getCause
    //#unanalyzed(String[] getTrace(Throwable)): Effects-of-calling:getTrace
    //#test_vector(String[] getTrace(Throwable)): throwable: Inverse{null}, Addr_Set{null}
    //#test_vector(String[] getTrace(Throwable)): java.lang.Throwable:getCause(...)@268: Addr_Set{null}, Inverse{null}
            trace = new String[0];
        } else {
            final StackTraceElement[] traceElements = throwable.getStackTrace();
            trace = new String[traceElements.length + 1];

            trace[0] = throwable.toString();

            for (int i = 0; i < traceElements.length; i++) {
                trace[i + 1] = traceElements[i].toString();
            }

            if (throwable.getCause() != null) {
                final String[] causeTrace = getTrace(throwable.getCause());
                final String[] newTrace = new String[trace.length + causeTrace.length];
                trace[0] = "\nWhich caused: " + trace[0];

                System.arraycopy(causeTrace, 0, newTrace, 0, causeTrace.length);
                System.arraycopy(trace, 0, newTrace, causeTrace.length, trace.length);

                trace = newTrace;
            }
        }

        return trace;
    //#ErrorManager.java:280: end of method: String[] com.dmdirc.logger.ErrorManager.getTrace(Throwable)
    }

    /**
     * Sends an error to the developers.
     *
     * @param error error to be sent
     */
    public void sendError(final ProgramError error) {
        if (error.getReportStatus() != ErrorReportStatus.ERROR
    //#ErrorManager.java:289: method: void com.dmdirc.logger.ErrorManager.sendError(ProgramError)
    //#input(void sendError(ProgramError)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5).terminal
    //#input(void sendError(ProgramError)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void sendError(ProgramError)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorReportStatus.QUEUED
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void sendError(ProgramError)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void sendError(ProgramError)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void sendError(ProgramError)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void sendError(ProgramError)): error
    //#input(void sendError(ProgramError)): error.__Tag
    //#input(void sendError(ProgramError)): error.level
    //#input(void sendError(ProgramError)): error.message
    //#input(void sendError(ProgramError)): error.reportStatus
    //#input(void sendError(ProgramError)): error.reportStatus.terminal
    //#input(void sendError(ProgramError)): error.trace
    //#input(void sendError(ProgramError)): me
    //#input(void sendError(ProgramError)): me.errorListeners
    //#input(void sendError(ProgramError)): this
    //#input(void sendError(ProgramError)): this.reportQueue
    //#input(void sendError(ProgramError)): this.reportThread
    //#output(void sendError(ProgramError)): error.reportStatus
    //#output(void sendError(ProgramError)): new ErrorReportingThread(sendError#1) num objects
    //#output(void sendError(ProgramError)): new ErrorReportingThread(sendError#1).__Tag
    //#output(void sendError(ProgramError)): new ErrorReportingThread(sendError#1).queue
    //#output(void sendError(ProgramError)): this.reportThread
    //#new obj(void sendError(ProgramError)): new ErrorReportingThread(sendError#1)
    //#pre[2] (void sendError(ProgramError)): error != null
    //#pre[10] (void sendError(ProgramError)): init'ed(error.reportStatus)
    //#pre[1] (void sendError(ProgramError)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[4] (void sendError(ProgramError)): (soft) error.__Tag == com/dmdirc/logger/ProgramError
    //#pre[11] (void sendError(ProgramError)): (soft) init'ed(this.reportThread)
    //#pre[13] (void sendError(ProgramError)): (soft) this.reportQueue != null
    //#post(void sendError(ProgramError)): error.reportStatus == One-of{old error.reportStatus, &com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5)}
    //#post(void sendError(ProgramError)): init'ed(error.reportStatus)
    //#post(void sendError(ProgramError)): this.reportThread == One-of{old this.reportThread, &new ErrorReportingThread(sendError#1)}
    //#post(void sendError(ProgramError)): init'ed(this.reportThread)
    //#post(void sendError(ProgramError)): new ErrorReportingThread(sendError#1) num objects <= 1
    //#post(void sendError(ProgramError)): new ErrorReportingThread(sendError#1).__Tag == com/dmdirc/logger/ErrorReportingThread
    //#post(void sendError(ProgramError)): new ErrorReportingThread(sendError#1).queue == this.reportQueue
    //#post(void sendError(ProgramError)): new ErrorReportingThread(sendError#1).queue != null
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:getErrorManager
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:com.dmdirc.logger.ErrorReportingThread:setDaemon
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:equals
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:getReportStatus
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:errorStatusChanged
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void sendError(ProgramError)): Effects-of-calling:java.util.Arrays:equals
    //#test_vector(void sendError(ProgramError)): this.reportThread: Addr_Set{null}, Inverse{null}
    //#test_vector(void sendError(ProgramError)): java.lang.Thread:isAlive(...)@298: {1}, {0}
                && error.getReportStatus() != ErrorReportStatus.WAITING) {
            return;
        }

        error.setReportStatus(ErrorReportStatus.QUEUED);

        reportQueue.add(error);

        if (reportThread == null || !reportThread.isAlive()) {
            reportThread = new ErrorReportingThread(reportQueue);
            reportThread.start();
        }
    }
    //#ErrorManager.java:302: end of method: void com.dmdirc.logger.ErrorManager.sendError(ProgramError)

    /**
     * Called when an error needs to be deleted from the list.
     *
     * @param error ProgramError that changed
     */
    public void deleteError(final ProgramError error) {
        synchronized (errors) {
    //#ErrorManager.java:310: method: void com.dmdirc.logger.ErrorManager.deleteError(ProgramError)
    //#input(void deleteError(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void deleteError(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void deleteError(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void deleteError(ProgramError)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void deleteError(ProgramError)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void deleteError(ProgramError)): error
    //#input(void deleteError(ProgramError)): this
    //#input(void deleteError(ProgramError)): this.errorListeners
    //#input(void deleteError(ProgramError)): this.errors
    //#input(void deleteError(ProgramError)): this.errors.__Lock
    //#pre[3] (void deleteError(ProgramError)): this.errorListeners != null
    //#pre[4] (void deleteError(ProgramError)): this.errors != null
    //#unanalyzed(void deleteError(ProgramError)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void deleteError(ProgramError)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void deleteError(ProgramError)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void deleteError(ProgramError)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void deleteError(ProgramError)): Effects-of-calling:errorDeleted
            errors.remove(error);
        }

        fireErrorDeleted(error);
    }
    //#ErrorManager.java:315: end of method: void com.dmdirc.logger.ErrorManager.deleteError(ProgramError)

    /**
     * Deletes all errors from the manager.
     *
     * @since 0.6.3m1
     */
    public void deleteAll() {
        synchronized (errors) {
    //#ErrorManager.java:323: method: void com.dmdirc.logger.ErrorManager.deleteAll()
    //#input(void deleteAll()): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void deleteAll()): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void deleteAll()): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void deleteAll()): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void deleteAll()): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void deleteAll()): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void deleteAll()): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void deleteAll()): this
    //#input(void deleteAll()): this.errorListeners
    //#input(void deleteAll()): this.errors
    //#input(void deleteAll()): this.errors.__Lock
    //#pre[3] (void deleteAll()): this.errors != null
    //#pre[2] (void deleteAll()): (soft) this.errorListeners != null
    //#presumption(void deleteAll()): java.util.Iterator:next(...).__Tag@324 == com/dmdirc/logger/ProgramError
    //#unanalyzed(void deleteAll()): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void deleteAll()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void deleteAll()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void deleteAll()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void deleteAll()): Effects-of-calling:errorDeleted
    //#test_vector(void deleteAll()): java.util.Iterator:hasNext(...)@324: {0}, {1}
            for (ProgramError error : errors) {
                fireErrorDeleted(error);
            }

            errors.clear();
        }
    }
    //#ErrorManager.java:330: end of method: void com.dmdirc.logger.ErrorManager.deleteAll()

    /**
     * Returns the number of errors.
     *
     * @return Number of ProgramErrors
     */
    public int getErrorCount() {
        return errors.size();
    //#ErrorManager.java:338: method: int com.dmdirc.logger.ErrorManager.getErrorCount()
    //#input(int getErrorCount()): this
    //#input(int getErrorCount()): this.errors
    //#output(int getErrorCount()): return_value
    //#pre[2] (int getErrorCount()): this.errors != null
    //#post(int getErrorCount()): init'ed(return_value)
    //#ErrorManager.java:338: end of method: int com.dmdirc.logger.ErrorManager.getErrorCount()
    }

    /**
     * Returns the list of program errors.
     *
     * @return Program error list
     */
    public List<ProgramError> getErrors() {
        synchronized (errors) {
    //#ErrorManager.java:347: method: List com.dmdirc.logger.ErrorManager.getErrors()
    //#input(List getErrors()): this
    //#input(List getErrors()): this.errors
    //#input(List getErrors()): this.errors.__Lock
    //#output(List getErrors()): new LinkedList(getErrors#1) num objects
    //#output(List getErrors()): return_value
    //#new obj(List getErrors()): new LinkedList(getErrors#1)
    //#post(List getErrors()): return_value == &new LinkedList(getErrors#1)
    //#post(List getErrors()): new LinkedList(getErrors#1) num objects == 1
            return new LinkedList<ProgramError>(errors);
        }
    //#ErrorManager.java:349: end of method: List com.dmdirc.logger.ErrorManager.getErrors()
    }

    /**
     * Adds an ErrorListener to the listener list.
     *
     * @param listener Listener to add
     */
    public void addErrorListener(final ErrorListener listener) {
        if (listener == null) {
    //#ErrorManager.java:358: method: void com.dmdirc.logger.ErrorManager.addErrorListener(ErrorListener)
    //#input(void addErrorListener(ErrorListener)): listener
    //#input(void addErrorListener(ErrorListener)): this
    //#input(void addErrorListener(ErrorListener)): this.errorListeners
    //#pre[3] (void addErrorListener(ErrorListener)): (soft) this.errorListeners != null
    //#test_vector(void addErrorListener(ErrorListener)): listener: Inverse{null}, Addr_Set{null}
            return;
        }

        errorListeners.add(ErrorListener.class, listener);
    //#ErrorManager.java:362: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.util.ListenerList:add(Class, Object)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void addErrorListener(ErrorListener)
    //#    unanalyzed callee: void com.dmdirc.util.ListenerList:add(Class, Object)
    }
    //#ErrorManager.java:363: end of method: void com.dmdirc.logger.ErrorManager.addErrorListener(ErrorListener)

    /**
     * Removes an ErrorListener from the listener list.
     *
     * @param listener Listener to remove
     */
    public void removeErrorListener(final ErrorListener listener) {
       errorListeners.remove(ErrorListener.class, listener);
    //#ErrorManager.java:371: method: void com.dmdirc.logger.ErrorManager.removeErrorListener(ErrorListener)
    //#ErrorManager.java:371: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.util.ListenerList:remove(Class, Object)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void removeErrorListener(ErrorListener)
    //#    unanalyzed callee: void com.dmdirc.util.ListenerList:remove(Class, Object)
    //#input(void removeErrorListener(ErrorListener)): listener
    //#input(void removeErrorListener(ErrorListener)): this
    //#input(void removeErrorListener(ErrorListener)): this.errorListeners
    //#pre[3] (void removeErrorListener(ErrorListener)): this.errorListeners != null
    }
    //#ErrorManager.java:372: end of method: void com.dmdirc.logger.ErrorManager.removeErrorListener(ErrorListener)

    /**
     * Fired when the program encounters an error.
     *
     * @param error Error that occurred
     */
    protected void fireErrorAdded(final ProgramError error) {
        int firedListeners = 0;
    //#ErrorManager.java:380: method: void com.dmdirc.logger.ErrorManager.fireErrorAdded(ProgramError)
    //#input(void fireErrorAdded(ProgramError)): "&#09;"._tainted
    //#input(void fireErrorAdded(ProgramError)): ": "._tainted
    //#input(void fireErrorAdded(ProgramError)): "An error has occurred: "._tainted
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.isReady()Z
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorAdded(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void fireErrorAdded(ProgramError)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.isReady()Z
    //#input(void fireErrorAdded(ProgramError)): error
    //#input(void fireErrorAdded(ProgramError)): error.level
    //#input(void fireErrorAdded(ProgramError)): error.level._tainted
    //#input(void fireErrorAdded(ProgramError)): error.message
    //#input(void fireErrorAdded(ProgramError)): error.message._tainted
    //#input(void fireErrorAdded(ProgramError)): error.trace
    //#input(void fireErrorAdded(ProgramError)): error.trace.length
    //#input(void fireErrorAdded(ProgramError)): java.lang.System.err
    //#input(void fireErrorAdded(ProgramError)): this
    //#input(void fireErrorAdded(ProgramError)): this.errorListeners
    //#pre[1] (void fireErrorAdded(ProgramError)): error != null
    //#pre[6] (void fireErrorAdded(ProgramError)): error.trace != null
    //#pre[7] (void fireErrorAdded(ProgramError)): error.trace.length <= 4_294_967_295
    //#pre[9] (void fireErrorAdded(ProgramError)): this.errorListeners != null
    //#presumption(void fireErrorAdded(ProgramError)): arr$.length <= 4_294_967_295
    //#presumption(void fireErrorAdded(ProgramError)): com.dmdirc.util.ListenerList:get(...)@382 != null
    //#presumption(void fireErrorAdded(ProgramError)): java.lang.System.err != null
    //#presumption(void fireErrorAdded(ProgramError)): java.util.Arrays:copyOf(...)@148 != null
    //#presumption(void fireErrorAdded(ProgramError)): java.util.Iterator:next(...).__Tag@382 in {com/dmdirc/logger/ErrorListener, com/dmdirc/ui/FatalErrorDialog}
    //#presumption(void fireErrorAdded(ProgramError)): java.util.Iterator:next(...)@382 != null
    //#unanalyzed(void fireErrorAdded(ProgramError)): Effects-of-calling:java.util.Arrays:copyOf
    //#test_vector(void fireErrorAdded(ProgramError)): java.util.Iterator:hasNext(...)@382: {0}, {1}

        for (ErrorListener listener : errorListeners.get(ErrorListener.class)) {
    //#ErrorManager.java:382: Warning: method not available - call not analyzed
    //#    call on List com.dmdirc.util.ListenerList:get(Class)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void fireErrorAdded(ProgramError)
    //#    unanalyzed callee: List com.dmdirc.util.ListenerList:get(Class)
            if (listener.isReady()) {
    //#ErrorManager.java:383: Warning: test always goes same way
    //#    Test predetermined because isReady(...) == 0
    //#    severity: LOW
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void fireErrorAdded(ProgramError)
    //#    from bb: bb_11
    //#    live edge: bb_11-->bb_5
    //#    tested vn: 0
    //#    tested vn values: {0}
                listener.errorAdded(error);
    //#ErrorManager.java:384: Warning: dead code
    //#    Dead code here because isReady(...) == 0
    //#    severity: LOW
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void fireErrorAdded(ProgramError)
    //#    dead bb: bb_4
                firedListeners++;
            }
        }

        if (firedListeners == 0) {
    //#ErrorManager.java:389: Warning: test always goes same way
    //#    Test predetermined because firedListeners == 0
    //#    severity: LOW
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void fireErrorAdded(ProgramError)
    //#    from bb: bb_6
    //#    live edge: bb_6-->bb_7
    //#    tested vn: 0
    //#    tested vn values: {0}
            System.err.println("An error has occurred: " + error.getLevel()
                    + ": " + error.getMessage());

            for (String line : error.getTrace()) {
                System.err.println("\t" + line);
            }
        }
    }
    //#ErrorManager.java:397: end of method: void com.dmdirc.logger.ErrorManager.fireErrorAdded(ProgramError)

    /**
     * Fired when the program encounters a fatal error.
     *
     * @param error Error that occurred
     */
    protected void fireFatalError(final ProgramError error) {
        if (GraphicsEnvironment.isHeadless()) {
    //#ErrorManager.java:405: method: void com.dmdirc.logger.ErrorManager.fireFatalError(ProgramError)
    //#ErrorManager.java:405: ?never returns: method always exits the program: void fireFatalError(ProgramError).
    //#input(void fireFatalError(ProgramError)): "&#09;"._tainted
    //#input(void fireFatalError(ProgramError)): "A fatal error has occurred: "._tainted
    //#input(void fireFatalError(ProgramError)): error
    //#input(void fireFatalError(ProgramError)): error.__Lock
    //#input(void fireFatalError(ProgramError)): error.message
    //#input(void fireFatalError(ProgramError)): error.message._tainted
    //#input(void fireFatalError(ProgramError)): error.reportStatus
    //#input(void fireFatalError(ProgramError)): error.reportStatus.terminal
    //#input(void fireFatalError(ProgramError)): error.trace
    //#input(void fireFatalError(ProgramError)): error.trace.length
    //#input(void fireFatalError(ProgramError)): java.lang.System.err
    //#pre[1] (void fireFatalError(ProgramError)): error != null
    //#pre[4] (void fireFatalError(ProgramError)): error.reportStatus != null
    //#pre[6] (void fireFatalError(ProgramError)): (soft) error.trace != null
    //#pre[7] (void fireFatalError(ProgramError)): (soft) error.trace.length <= 4_294_967_295
    //#presumption(void fireFatalError(ProgramError)): arr$.length <= 4_294_967_295
    //#presumption(void fireFatalError(ProgramError)): java.lang.System.err != null
    //#presumption(void fireFatalError(ProgramError)): java.util.Arrays:copyOf(...)@148 != null
    //#unanalyzed(void fireFatalError(ProgramError)): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void fireFatalError(ProgramError)): Effects-of-calling:javax.swing.SwingUtilities:invokeLater
    //#unanalyzed(void fireFatalError(ProgramError)): Effects-of-calling:java.util.concurrent.Semaphore
    //#unanalyzed(void fireFatalError(ProgramError)): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#test_vector(void fireFatalError(ProgramError)): java.awt.GraphicsEnvironment:isHeadless(...)@405: {0}, {1}
            System.err.println("A fatal error has occurred: " + error.getMessage());
            for (String line : error.getTrace()) {
                System.err.println("\t" + line);
            }
        } else {
            FatalErrorDialog.displayBlocking(error);
        }

        while (!error.getReportStatus().isTerminal()) {
            try {
                synchronized (error) {
                    error.wait();
                }
            } catch (InterruptedException ex) {
                // Do nothing
            }
        }

        System.exit(-1);
    }
    //#ErrorManager.java:425: end of method: void com.dmdirc.logger.ErrorManager.fireFatalError(ProgramError)

    /**
     * Fired when an error is deleted.
     *
     * @param error Error that has been deleted
     */
    protected void fireErrorDeleted(final ProgramError error) {
        for (ErrorListener listener : errorListeners.get(ErrorListener.class)) {
    //#ErrorManager.java:433: method: void com.dmdirc.logger.ErrorManager.fireErrorDeleted(ProgramError)
    //#ErrorManager.java:433: Warning: method not available - call not analyzed
    //#    call on List com.dmdirc.util.ListenerList:get(Class)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void fireErrorDeleted(ProgramError)
    //#    unanalyzed callee: List com.dmdirc.util.ListenerList:get(Class)
    //#input(void fireErrorDeleted(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void fireErrorDeleted(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void fireErrorDeleted(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void fireErrorDeleted(ProgramError)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void fireErrorDeleted(ProgramError)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorDeleted(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void fireErrorDeleted(ProgramError)): error
    //#input(void fireErrorDeleted(ProgramError)): this
    //#input(void fireErrorDeleted(ProgramError)): this.errorListeners
    //#pre[3] (void fireErrorDeleted(ProgramError)): this.errorListeners != null
    //#presumption(void fireErrorDeleted(ProgramError)): com.dmdirc.util.ListenerList:get(...)@433 != null
    //#presumption(void fireErrorDeleted(ProgramError)): java.util.Iterator:next(...).__Tag@433 in {com/dmdirc/logger/ErrorListener, com/dmdirc/ui/FatalErrorDialog}
    //#presumption(void fireErrorDeleted(ProgramError)): java.util.Iterator:next(...)@433 != null
    //#test_vector(void fireErrorDeleted(ProgramError)): java.util.Iterator:hasNext(...)@433: {0}, {1}
            listener.errorDeleted(error);
        }
    }
    //#ErrorManager.java:436: end of method: void com.dmdirc.logger.ErrorManager.fireErrorDeleted(ProgramError)

    /**
     * Fired when an error's status is changed.
     *
     * @param error Error that has been altered
     */
    protected void fireErrorStatusChanged(final ProgramError error) {
        for (ErrorListener listener : errorListeners.get(ErrorListener.class)) {
    //#ErrorManager.java:444: method: void com.dmdirc.logger.ErrorManager.fireErrorStatusChanged(ProgramError)
    //#ErrorManager.java:444: Warning: method not available - call not analyzed
    //#    call on List com.dmdirc.util.ListenerList:get(Class)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void fireErrorStatusChanged(ProgramError)
    //#    unanalyzed callee: List com.dmdirc.util.ListenerList:get(Class)
    //#input(void fireErrorStatusChanged(ProgramError)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void fireErrorStatusChanged(ProgramError)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/logger/ProgramError.__Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/logger/ProgramError.__Descendant_Table[others]
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void fireErrorStatusChanged(ProgramError)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void fireErrorStatusChanged(ProgramError)): error
    //#input(void fireErrorStatusChanged(ProgramError)): error.__Tag
    //#input(void fireErrorStatusChanged(ProgramError)): error.level
    //#input(void fireErrorStatusChanged(ProgramError)): error.message
    //#input(void fireErrorStatusChanged(ProgramError)): error.reportStatus
    //#input(void fireErrorStatusChanged(ProgramError)): error.reportStatus.terminal
    //#input(void fireErrorStatusChanged(ProgramError)): error.trace
    //#input(void fireErrorStatusChanged(ProgramError)): this
    //#input(void fireErrorStatusChanged(ProgramError)): this.errorListeners
    //#pre[10] (void fireErrorStatusChanged(ProgramError)): this.errorListeners != null
    //#pre[1] (void fireErrorStatusChanged(ProgramError)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[3] (void fireErrorStatusChanged(ProgramError)): (soft) error.__Tag == com/dmdirc/logger/ProgramError
    //#pre[6] (void fireErrorStatusChanged(ProgramError)): (soft) error.reportStatus != null
    //#presumption(void fireErrorStatusChanged(ProgramError)): com.dmdirc.util.ListenerList:get(...)@444 != null
    //#presumption(void fireErrorStatusChanged(ProgramError)): java.util.Iterator:next(...).__Tag@444 in {com/dmdirc/logger/ErrorListener, com/dmdirc/ui/FatalErrorDialog}
    //#presumption(void fireErrorStatusChanged(ProgramError)): java.util.Iterator:next(...)@444 != null
    //#presumption(void fireErrorStatusChanged(ProgramError)): listener.error.message@444 != null
    //#presumption(void fireErrorStatusChanged(ProgramError)): listener.error@444 != null
    //#presumption(void fireErrorStatusChanged(ProgramError)): listener.okButton@444 != null
    //#presumption(void fireErrorStatusChanged(ProgramError)): listener.sendButton@444 != null
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:equals
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:getReportStatus
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void fireErrorStatusChanged(ProgramError)): Effects-of-calling:java.util.Arrays:equals
    //#test_vector(void fireErrorStatusChanged(ProgramError)): java.util.Iterator:hasNext(...)@444: {0}, {1}
            listener.errorStatusChanged(error);
        }
    }
    //#ErrorManager.java:447: end of method: void com.dmdirc.logger.ErrorManager.fireErrorStatusChanged(ProgramError)

    /** {@inheritDoc} */
    @Override
    public void configChanged(final String domain, final String key) {
        updateSettings();
    //#ErrorManager.java:452: method: void com.dmdirc.logger.ErrorManager.configChanged(String, String)
    //#input(void configChanged(String, String)): this
    //#output(void configChanged(String, String)): this.logReports
    //#output(void configChanged(String, String)): this.sendReports
    //#post(void configChanged(String, String)): init'ed(this.logReports)
    //#post(void configChanged(String, String)): init'ed(this.sendReports)
    //#unanalyzed(void configChanged(String, String)): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(void configChanged(String, String)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionBool
    //#unanalyzed(void configChanged(String, String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    }
    //#ErrorManager.java:453: end of method: void com.dmdirc.logger.ErrorManager.configChanged(String, String)

    /** Updates the settings used by this error manager. */
    protected void updateSettings() {
        final ConfigManager config = IdentityManager.getGlobalConfig();
    //#ErrorManager.java:457: method: void com.dmdirc.logger.ErrorManager.updateSettings()
    //#ErrorManager.java:457: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void updateSettings()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#input(void updateSettings()): this
    //#output(void updateSettings()): this.logReports
    //#output(void updateSettings()): this.sendReports
    //#presumption(void updateSettings()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@457 != null
    //#post(void updateSettings()): init'ed(this.logReports)
    //#post(void updateSettings()): init'ed(this.sendReports)

        try {
            sendReports = config.getOptionBool("general", "submitErrors")
    //#ErrorManager.java:460: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void updateSettings()
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
                    && !config.getOptionBool("temp", "noerrorreporting");
            logReports = config.getOptionBool("general", "logerrors");
    //#ErrorManager.java:462: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ErrorManager
    //#    method: void updateSettings()
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
        } catch (IllegalArgumentException ex) {
            sendReports = false;
            logReports = true;
        }
    }
    //#ErrorManager.java:467: end of method: void com.dmdirc.logger.ErrorManager.updateSettings()

}
    //#ErrorManager.java:: end of class: com.dmdirc.logger.ErrorManager
