//# 9 errors, 938 messages
//#
/*
    //#UpdateChecker.java:1:1: class: com.dmdirc.updater.UpdateChecker$2
    //#UpdateChecker.java:1:1: method: com.dmdirc.updater.UpdateChecker$2.com.dmdirc.updater.UpdateChecker$2__static_init
    //#UpdateChecker.java:1:1: class: com.dmdirc.updater.UpdateChecker$STATE
    //#UpdateChecker.java:1:1: class: com.dmdirc.updater.UpdateChecker$1
    //#UpdateChecker.java:1:1: method: com.dmdirc.updater.UpdateChecker$1.com.dmdirc.updater.UpdateChecker$1__static_init
    //#UpdateChecker.java:1:1: class: com.dmdirc.updater.UpdateChecker
 * 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.updater;

import com.dmdirc.Precondition;
import com.dmdirc.config.ConfigManager;
import com.dmdirc.config.IdentityManager;
import com.dmdirc.logger.ErrorLevel;
import com.dmdirc.logger.Logger;
import com.dmdirc.updater.components.ClientComponent;
import com.dmdirc.updater.components.DefaultsComponent;
import com.dmdirc.updater.components.ModeAliasesComponent;
import com.dmdirc.util.Downloader;
import com.dmdirc.util.ListenerList;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Semaphore;

/**
 * The update checker contacts the DMDirc website to check to see if there
 * are any updates available.
 *
 * @author chris
 */
public final class UpdateChecker implements Runnable {
    //#UpdateChecker.java:51: method: UpdateChecker$STATE com.dmdirc.updater.UpdateChecker.access$000()
    //#input(UpdateChecker$STATE access$000()): status
    //#output(UpdateChecker$STATE access$000()): return_value
    //#pre[1] (UpdateChecker$STATE access$000()): init'ed(status)
    //#post(UpdateChecker$STATE access$000()): return_value == status
    //#post(UpdateChecker$STATE access$000()): init'ed(return_value)
    //#UpdateChecker.java:51: end of method: UpdateChecker$STATE com.dmdirc.updater.UpdateChecker.access$000()
    //#UpdateChecker.java:51: method: void com.dmdirc.updater.UpdateChecker.access$100()
    //#UpdateChecker.java:51: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void access$100()
    //#    suspicious precondition index: [1]
    //#    Attribs:  Soft
    //#input(void access$100()): com/dmdirc/updater/Update.__Descendant_Table[com/dmdirc/updater/Update]
    //#input(void access$100()): com/dmdirc/updater/Update.__Descendant_Table[others]
    //#input(void access$100()): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#input(void access$100()): com/dmdirc/updater/UpdateChecker$STATE.RESTART_REQUIRED
    //#input(void access$100()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void access$100()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void access$100()): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void access$100()): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void access$100()): com/dmdirc/updater/UpdateStatus.RESTART_NEEDED
    //#input(void access$100()): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void access$100()): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void access$100()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void access$100()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void access$100()): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void access$100()): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void access$100()): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void access$100()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void access$100()): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void access$100()): listeners
    //#input(void access$100()): listeners.__Tag
    //#input(void access$100()): listeners.listeners
    //#input(void access$100()): listeners.listeners.__Tag
    //#input(void access$100()): listeners.listeners.map
    //#input(void access$100()): new MapList(ListenerList#1).__Tag
    //#input(void access$100()): new MapList(ListenerList#1).map
    //#input(void access$100()): updates
    //#output(void access$100()): status
    //#pre[1] (void access$100()): (soft) new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[2] (void access$100()): (soft) new MapList(ListenerList#1).map != null
    //#post(void access$100()): status == One-of{old status, &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5), &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1)}
    //#unanalyzed(void access$100()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void access$100()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void access$100()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void access$100()): Effects-of-calling:getStatus
    //#unanalyzed(void access$100()): Effects-of-calling:doUpdate
    //#unanalyzed(void access$100()): Effects-of-calling:setStatus
    //#unanalyzed(void access$100()): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void access$100()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void access$100()): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void access$100()): Effects-of-calling:statusChanged
    //#unanalyzed(void access$100()): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void access$100()): Effects-of-calling:java.lang.Thread:start
    //#UpdateChecker.java:51: end of method: void com.dmdirc.updater.UpdateChecker.access$100()
    //#UpdateChecker.java:51: method: com.dmdirc.updater.UpdateChecker.com.dmdirc.updater.UpdateChecker__static_init
    //#input(com.dmdirc.updater.UpdateChecker__static_init): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#output(com.dmdirc.updater.UpdateChecker__static_init): $assertionsDisabled
    //#output(com.dmdirc.updater.UpdateChecker__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker]
    //#output(com.dmdirc.updater.UpdateChecker__static_init): __Dispatch_Table.checkLine(Ljava/lang/String;)V
    //#output(com.dmdirc.updater.UpdateChecker__static_init): __Dispatch_Table.doUpdateAvailable(Ljava/lang/String;)V
    //#output(com.dmdirc.updater.UpdateChecker__static_init): __Dispatch_Table.run()V
    //#output(com.dmdirc.updater.UpdateChecker__static_init): components
    //#output(com.dmdirc.updater.UpdateChecker__static_init): listener
    //#output(com.dmdirc.updater.UpdateChecker__static_init): listeners
    //#output(com.dmdirc.updater.UpdateChecker__static_init): mutex
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new ArrayList(UpdateChecker__static_init#2) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new ArrayList(UpdateChecker__static_init#4) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new HashMap(MapList#1) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new ListenerList(UpdateChecker__static_init#5) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): listeners.__Tag
    //#output(com.dmdirc.updater.UpdateChecker__static_init): listeners.listeners
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1).__Tag
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1).map
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new Semaphore(UpdateChecker__static_init#1) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new Timer(UpdateChecker__static_init#3) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): new UpdateChecker$1(UpdateChecker__static_init#6) num objects
    //#output(com.dmdirc.updater.UpdateChecker__static_init): listener.__Tag
    //#output(com.dmdirc.updater.UpdateChecker__static_init): status
    //#output(com.dmdirc.updater.UpdateChecker__static_init): timer
    //#output(com.dmdirc.updater.UpdateChecker__static_init): updates
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new ArrayList(UpdateChecker__static_init#2)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new ArrayList(UpdateChecker__static_init#4)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new HashMap(MapList#1)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new ListenerList(UpdateChecker__static_init#5)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new Semaphore(UpdateChecker__static_init#1)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new Timer(UpdateChecker__static_init#3)
    //#new obj(com.dmdirc.updater.UpdateChecker__static_init): new UpdateChecker$1(UpdateChecker__static_init#6)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): $assertionsDisabled == 0
    //#post(com.dmdirc.updater.UpdateChecker__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker] == &__Dispatch_Table
    //#post(com.dmdirc.updater.UpdateChecker__static_init): __Dispatch_Table.checkLine(Ljava/lang/String;)V == &checkLine
    //#post(com.dmdirc.updater.UpdateChecker__static_init): __Dispatch_Table.doUpdateAvailable(Ljava/lang/String;)V == &doUpdateAvailable
    //#post(com.dmdirc.updater.UpdateChecker__static_init): __Dispatch_Table.run()V == &run
    //#post(com.dmdirc.updater.UpdateChecker__static_init): components == &new ArrayList(UpdateChecker__static_init#2)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): listener == &new UpdateChecker$1(UpdateChecker__static_init#6)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): listeners == &new ListenerList(UpdateChecker__static_init#5)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): mutex == &new Semaphore(UpdateChecker__static_init#1)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): status == &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): timer == &new Timer(UpdateChecker__static_init#3)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): updates == &new ArrayList(UpdateChecker__static_init#4)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new ArrayList(UpdateChecker__static_init#2) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new ArrayList(UpdateChecker__static_init#4) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new HashMap(MapList#1) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new ListenerList(UpdateChecker__static_init#5) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new Semaphore(UpdateChecker__static_init#1) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new Timer(UpdateChecker__static_init#3) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new UpdateChecker$1(UpdateChecker__static_init#6) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker__static_init): listeners.__Tag == com/dmdirc/util/ListenerList
    //#post(com.dmdirc.updater.UpdateChecker__static_init): listeners.listeners == &new MapList(ListenerList#1)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1).__Tag == com/dmdirc/util/MapList
    //#post(com.dmdirc.updater.UpdateChecker__static_init): new MapList(ListenerList#1).map == &new HashMap(MapList#1)
    //#post(com.dmdirc.updater.UpdateChecker__static_init): listener.__Tag == com/dmdirc/updater/UpdateChecker$1
    //#unanalyzed(com.dmdirc.updater.UpdateChecker__static_init): Effects-of-calling:java.util.HashMap
    //#UpdateChecker.java:51: ?unlocked shared daemon update: com/dmdirc/updater/UpdateChecker.status is subject to an unlocked shared daemon access via com.dmdirc.updater.Update$1:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: UpdateChecker$STATE access$000()
    //#UpdateChecker.java:51: ?unlocked shared daemon update: status is subject to an unlocked shared daemon access via com.dmdirc.updater.UpdateChecker:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: UpdateChecker$STATE access$000()

    /** The possible states for the checker. */
    public static enum STATE {
    //#UpdateChecker.java:54: method: UpdateChecker$STATE[] com.dmdirc.updater.UpdateChecker$STATE.values()
    //#input(UpdateChecker$STATE[] values()): $VALUES
    //#input(UpdateChecker$STATE[] values()): $VALUES.length
    //#input(UpdateChecker$STATE[] values()): $VALUES[0..5]
    //#output(UpdateChecker$STATE[] values()): new UpdateChecker$STATE[](values#1) num objects
    //#output(UpdateChecker$STATE[] values()): return_value.length
    //#output(UpdateChecker$STATE[] values()): return_value[0..5]
    //#output(UpdateChecker$STATE[] values()): return_value
    //#new obj(UpdateChecker$STATE[] values()): new UpdateChecker$STATE[](values#1)
    //#pre[1] (UpdateChecker$STATE[] values()): (soft) init'ed($VALUES[0..5])
    //#post(UpdateChecker$STATE[] values()): return_value == &new UpdateChecker$STATE[](values#1)
    //#post(UpdateChecker$STATE[] values()): new UpdateChecker$STATE[](values#1) num objects == 1
    //#post(UpdateChecker$STATE[] values()): return_value.length == 5
    //#post(UpdateChecker$STATE[] values()): return_value[0..5] == One-of{$VALUES[0..5], undefined}
    //#UpdateChecker.java:54: end of method: UpdateChecker$STATE[] com.dmdirc.updater.UpdateChecker$STATE.values()
    //#UpdateChecker.java:54: method: UpdateChecker$STATE com.dmdirc.updater.UpdateChecker$STATE.valueOf(String)
    //#input(UpdateChecker$STATE valueOf(String)): __Descendant_Table[com/dmdirc/updater/UpdateChecker$STATE]
    //#input(UpdateChecker$STATE valueOf(String)): __Descendant_Table[others]
    //#input(UpdateChecker$STATE valueOf(String)): name
    //#output(UpdateChecker$STATE valueOf(String)): return_value
    //#presumption(UpdateChecker$STATE valueOf(String)): java.lang.Enum:valueOf(...).__Tag@54 == com/dmdirc/updater/UpdateChecker$STATE
    //#post(UpdateChecker$STATE valueOf(String)): init'ed(return_value)
    //#UpdateChecker.java:54: end of method: UpdateChecker$STATE com.dmdirc.updater.UpdateChecker$STATE.valueOf(String)
    //#UpdateChecker.java:54: method: void com.dmdirc.updater.UpdateChecker$STATE.com.dmdirc.updater.UpdateChecker$STATE(String, int)
    //#input(void com.dmdirc.updater.UpdateChecker$STATE(String, int)): Param_1
    //#input(void com.dmdirc.updater.UpdateChecker$STATE(String, int)): Param_2
    //#input(void com.dmdirc.updater.UpdateChecker$STATE(String, int)): this
    //#UpdateChecker.java:54: end of method: void com.dmdirc.updater.UpdateChecker$STATE.com.dmdirc.updater.UpdateChecker$STATE(String, int)
        /** Nothing's happening. */
        IDLE,
    //#UpdateChecker.java:56: method: com.dmdirc.updater.UpdateChecker$STATE.com.dmdirc.updater.UpdateChecker$STATE__static_init
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): CHECKING
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): IDLE
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): RESTART_REQUIRED
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATES_AVAILABLE
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATING
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker$STATE]
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1) num objects
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): IDLE.__Tag
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#2) num objects
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): CHECKING.__Tag
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#3) num objects
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATING.__Tag
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#4) num objects
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATES_AVAILABLE.__Tag
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5) num objects
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): RESTART_REQUIRED.__Tag
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE[](UpdateChecker$STATE__static_init#6) num objects
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES.length
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[0]
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[1]
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[2]
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[3]
    //#output(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[4]
    //#new obj(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1)
    //#new obj(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#2)
    //#new obj(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#3)
    //#new obj(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#4)
    //#new obj(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5)
    //#new obj(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE[](UpdateChecker$STATE__static_init#6)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES == &new UpdateChecker$STATE[](UpdateChecker$STATE__static_init#6)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): CHECKING == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#2)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[1] == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#2)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): IDLE == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[0] == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): RESTART_REQUIRED == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[4] == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATES_AVAILABLE == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#4)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[3] == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#4)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATING == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#3)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES[2] == &new UpdateChecker$STATE(UpdateChecker$STATE__static_init#3)
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker$STATE] == &__Dispatch_Table
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#2) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#3) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#4) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): new UpdateChecker$STATE[](UpdateChecker$STATE__static_init#6) num objects == 1
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): IDLE.__Tag == com/dmdirc/updater/UpdateChecker$STATE
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): CHECKING.__Tag == com/dmdirc/updater/UpdateChecker$STATE
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATING.__Tag == com/dmdirc/updater/UpdateChecker$STATE
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): UPDATES_AVAILABLE.__Tag == com/dmdirc/updater/UpdateChecker$STATE
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): RESTART_REQUIRED.__Tag == com/dmdirc/updater/UpdateChecker$STATE
    //#post(com.dmdirc.updater.UpdateChecker$STATE__static_init): $VALUES.length == 5
    //#unanalyzed(com.dmdirc.updater.UpdateChecker$STATE__static_init): Effects-of-calling:java.lang.Enum
        /** Currently checking for updates. */
        CHECKING,
        /** Currently updating. */
        UPDATING,
        /** New updates are available. */
        UPDATES_AVAILABLE,
        /** Updates installed but restart needed. */
        RESTART_REQUIRED,
    //#UpdateChecker.java:64: end of method: com.dmdirc.updater.UpdateChecker$STATE.com.dmdirc.updater.UpdateChecker$STATE__static_init
    }

    /** Semaphore used to prevent multiple invocations. */
    private static final Semaphore mutex = new Semaphore(1);

    /** A list of components that we're to check. */
    private static final List<UpdateComponent> components
            = new ArrayList<UpdateComponent>();

    /** Our timer. */
    private static Timer timer = new Timer("Update Checker Timer");

    /** The list of updates that are available. */
    private static final List<Update> updates = new ArrayList<Update>();

    /** A list of our listeners. */
    private static final ListenerList listeners = new ListenerList();

    /** Our current state. */
    private static STATE status = STATE.IDLE;

    /** A reference to the listener we use for update status changes. */
    private static final UpdateListener listener = new UpdateListener() {
    //#UpdateChecker.java:87: method: void com.dmdirc.updater.UpdateChecker$1.com.dmdirc.updater.UpdateChecker$1()
    //#UpdateChecker.java:87: end of method: void com.dmdirc.updater.UpdateChecker$1.com.dmdirc.updater.UpdateChecker$1()
        @Override
        public void updateStatusChange(final Update update, final UpdateStatus status) {
            if (status == UpdateStatus.INSTALLED
    //#UpdateChecker.java:90: method: void com.dmdirc.updater.UpdateChecker$1.updateStatusChange(Update, UpdateStatus)
    //#UpdateChecker.java:90: Warning: suspicious precondition
    //#    The precondition for com.dmdirc.util.ListenerList.new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker$1
    //#    method: void updateStatusChange(Update, UpdateStatus)
    //#    suspicious precondition index: [1]
    //#    Attribs:  Soft
    //#input(void updateStatusChange(Update, UpdateStatus)): com.dmdirc.updater.UpdateChecker__static_init.new ListenerList(UpdateChecker__static_init#5).__Tag
    //#input(void updateStatusChange(Update, UpdateStatus)): com.dmdirc.updater.UpdateChecker__static_init.new ListenerList(UpdateChecker__static_init#5).listeners
    //#input(void updateStatusChange(Update, UpdateStatus)): com.dmdirc.updater.UpdateChecker__static_init.new ListenerList(UpdateChecker__static_init#5).listeners.__Tag
    //#input(void updateStatusChange(Update, UpdateStatus)): com.dmdirc.updater.UpdateChecker__static_init.new ListenerList(UpdateChecker__static_init#5).listeners.map
    //#input(void updateStatusChange(Update, UpdateStatus)): com.dmdirc.util.ListenerList.new MapList(ListenerList#1).__Tag
    //#input(void updateStatusChange(Update, UpdateStatus)): com.dmdirc.util.ListenerList.new MapList(ListenerList#1).map
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/Update.__Descendant_Table[com/dmdirc/updater/Update]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/Update.__Descendant_Table[others]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker$STATE.RESTART_REQUIRED
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker$STATE.UPDATING
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker.listener
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker.listeners
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker.status
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker.updates
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateStatus.ERROR
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateStatus.INSTALLED
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateStatus.RESTART_NEEDED
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void updateStatusChange(Update, UpdateStatus)): status
    //#input(void updateStatusChange(Update, UpdateStatus)): update
    //#input(void updateStatusChange(Update, UpdateStatus)): update.listeners
    //#output(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker.status
    //#pre[1] (void updateStatusChange(Update, UpdateStatus)): (soft) com.dmdirc.util.ListenerList.new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[2] (void updateStatusChange(Update, UpdateStatus)): (soft) com.dmdirc.util.ListenerList.new MapList(ListenerList#1).map != null
    //#pre[3] (void updateStatusChange(Update, UpdateStatus)): (soft) init'ed(com/dmdirc/updater/UpdateChecker.status)
    //#pre[5] (void updateStatusChange(Update, UpdateStatus)): (soft) update != null
    //#pre[6] (void updateStatusChange(Update, UpdateStatus)): (soft) update.listeners != null
    //#post(void updateStatusChange(Update, UpdateStatus)): com/dmdirc/updater/UpdateChecker.status == One-of{&com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1), old com/dmdirc/updater/UpdateChecker.status, &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker...
    //#post(void updateStatusChange(Update, UpdateStatus)): init'ed(com/dmdirc/updater/UpdateChecker.status)
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:getStatus
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:doUpdate
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:setStatus
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.List:isEmpty
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:statusChanged
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.util.List:remove
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:removeUpdateListener
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void updateStatusChange(Update, UpdateStatus)): Effects-of-calling:java.lang.Thread:start
                || status == UpdateStatus.ERROR) {
                removeUpdate(update);
            } else if (status == UpdateStatus.RESTART_NEEDED && UpdateChecker.status
                    == STATE.UPDATING) {
                doNextUpdate();
            }
        }
    //#UpdateChecker.java:97: end of method: void com.dmdirc.updater.UpdateChecker$1.updateStatusChange(Update, UpdateStatus)

        @Override
        public void updateProgressChange(final Update update, final float progress) {
            // Don't care
        }
    //#UpdateChecker.java:102: method: void com.dmdirc.updater.UpdateChecker$1.updateProgressChange(Update, float)
    //#UpdateChecker.java:102: end of method: void com.dmdirc.updater.UpdateChecker$1.updateProgressChange(Update, float)
    };

    static {
        components.add(new ClientComponent());
        components.add(new ModeAliasesComponent());
        components.add(new DefaultsComponent());
    }
    //#UpdateChecker.java:109: end of method: com.dmdirc.updater.UpdateChecker.com.dmdirc.updater.UpdateChecker__static_init

    /**
     * Instantiates an Updatechecker.
     */
    public UpdateChecker() {
    //#UpdateChecker.java:114: method: void com.dmdirc.updater.UpdateChecker.com.dmdirc.updater.UpdateChecker()
        //Ignore
    }
    //#UpdateChecker.java:116: end of method: void com.dmdirc.updater.UpdateChecker.com.dmdirc.updater.UpdateChecker()

    /** {@inheritDoc} */
    @Override
    public void run() {
        if (!mutex.tryAcquire()) {
    //#UpdateChecker.java:121: method: void com.dmdirc.updater.UpdateChecker.run()
    //#UpdateChecker.java:121: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    suspicious precondition index: [1]
    //#    Attribs:  Soft
    //#input(void run()): ", rescheduling."._tainted
    //#input(void run()): "Attempted to schedule update check "._tainted
    //#input(void run()): "Error when checking for updates: "._tainted
    //#input(void run()): "I.O error when checking for updates: "._tainted
    //#input(void run()): "Unknown update line received from server: "._tainted
    //#input(void run()): "data="._tainted
    //#input(void run()): "in the past"._tainted
    //#input(void run()): "line: "._tainted
    //#input(void run()): "too far in the future"._tainted
    //#input(void run()): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void run()): com/dmdirc/updater/Update.__Descendant_Table[com/dmdirc/updater/Update]
    //#input(void run()): com/dmdirc/updater/Update.__Descendant_Table[others]
    //#input(void run()): com/dmdirc/updater/Update.com.dmdirc.logger.ErrorLevel.LOW
    //#input(void run()): com/dmdirc/updater/UpdateChecker$STATE.CHECKING
    //#input(void run()): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#input(void run()): com/dmdirc/updater/UpdateChecker$STATE.RESTART_REQUIRED
    //#input(void run()): com/dmdirc/updater/UpdateChecker$STATE.UPDATES_AVAILABLE
    //#input(void run()): com/dmdirc/updater/UpdateChecker$STATE.UPDATING
    //#input(void run()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void run()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void run()): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/UpdateComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ActionGroupComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ClientComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/DefaultsComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/LauncherComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ModeAliasesComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/PluginComponent]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Descendant_Table[others]
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void run()): com/dmdirc/updater/UpdateStatus.RESTART_NEEDED
    //#input(void run()): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void run()): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getVersion()Lcom/dmdirc/updater/Version;
    //#input(void run()): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void run()): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void run()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void run()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void run()): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void run()): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void run()): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void run()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void run()): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void run()): components
    //#input(void run()): listener
    //#input(void run()): listeners
    //#input(void run()): mutex
    //#input(void run()): listeners.__Tag
    //#input(void run()): listeners.listeners
    //#input(void run()): listeners.listeners.__Tag
    //#input(void run()): listeners.listeners.map
    //#input(void run()): new MapList(ListenerList#1).__Tag
    //#input(void run()): new MapList(ListenerList#1).map
    //#input(void run()): status
    //#input(void run()): this
    //#input(void run()): timer
    //#input(void run()): updates
    //#output(void run()): new Timer(init#3) num objects
    //#output(void run()): status
    //#output(void run()): timer
    //#new obj(void run()): new Timer(init#3)
    //#pre[1] (void run()): (soft) new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[2] (void run()): (soft) new MapList(ListenerList#1).map != null
    //#pre[3] (void run()): (soft) init'ed(status)
    //#pre[4] (void run()): (soft) timer != null
    //#presumption(void run()): com.dmdirc.config.IdentityManager:getConfigIdentity(...)@131 != null
    //#presumption(void run()): com.dmdirc.config.IdentityManager:getConfigIdentity(...)@198 != null
    //#presumption(void run()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@127 != null
    //#presumption(void run()): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void run()): java.util.ArrayList:iterator(...)@142 != null
    //#presumption(void run()): java.util.Date:getTime(...)@131 in {-2_147_483_648_999..4_294_967_295_999}
    //#presumption(void run()): java.util.Date:getTime(...)@198 in {-2_147_483_648_999..4_294_967_295_999}
    //#presumption(void run()): java.util.Iterator:next(...).__Tag@142 == com/dmdirc/updater/Update
    //#presumption(void run()): java.util.Iterator:next(...).__Tag@152 in {com/dmdirc/updater/UpdateComponent, com/dmdirc/updater/components/ActionGroupComponent, com/dmdirc/updater/components/ClientComponent, com/dmdirc/updater/components/DefaultsComponent, com/dmdirc/updater/components/LauncherComponent, com/dmdirc/updater/components/ModeAliasesComponent, com/dmdirc/updater/components/PluginComponent}
    //#presumption(void run()): java.util.Iterator:next(...).__Tag@187 == com/dmdirc/updater/Update
    //#presumption(void run()): java.util.Iterator:next(...)@142 != null
    //#presumption(void run()): java.util.Iterator:next(...)@152 != null
    //#presumption(void run()): java.util.Iterator:next(...)@169 != null
    //#presumption(void run()): java.util.Iterator:next(...)@187 != null
    //#post(void run()): status == One-of{old status, &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1), &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#4), &com.dmdi...
    //#post(void run()): timer == One-of{old timer, &new Timer(init#3)}
    //#post(void run()): timer != null
    //#post(void run()): new Timer(init#3) num objects <= 1
    //#unanalyzed(void run()): Effects-of-calling:java.util.Timer
    //#unanalyzed(void run()): Effects-of-calling:java.util.List:add
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionInt
    //#unanalyzed(void run()): Effects-of-calling:java.util.Date
    //#unanalyzed(void run()): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void run()): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void run()): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void run()): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.logger.Logger:userError
    //#unanalyzed(void run()): Effects-of-calling:java.util.Timer:cancel
    //#unanalyzed(void run()): Effects-of-calling:java.util.TimerTask
    //#unanalyzed(void run()): Effects-of-calling:java.util.Timer:schedule
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.updater.Update
    //#unanalyzed(void run()): Effects-of-calling:getUrl
    //#unanalyzed(void run()): Effects-of-calling:addUpdateListener
    //#unanalyzed(void run()): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void run()): Effects-of-calling:java.lang.String:substring
    //#unanalyzed(void run()): Effects-of-calling:getName
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.config.ConfigManager:hasOptionString
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionBool
    //#unanalyzed(void run()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void run()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void run()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void run()): Effects-of-calling:getStatus
    //#unanalyzed(void run()): Effects-of-calling:doUpdate
    //#unanalyzed(void run()): Effects-of-calling:setStatus
    //#unanalyzed(void run()): Effects-of-calling:java.util.List:isEmpty
    //#unanalyzed(void run()): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void run()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void run()): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void run()): Effects-of-calling:statusChanged
    //#unanalyzed(void run()): Effects-of-calling:java.net.URL
    //#unanalyzed(void run()): Effects-of-calling:java.net.URL:openConnection
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:setUseCaches
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:setDoInput
    //#unanalyzed(void run()): Effects-of-calling:java.lang.String:length
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:setDoOutput
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:setConnectTimeout
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:setRequestProperty
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:getOutputStream
    //#unanalyzed(void run()): Effects-of-calling:java.io.DataOutputStream
    //#unanalyzed(void run()): Effects-of-calling:java.io.DataOutputStream:writeBytes
    //#unanalyzed(void run()): Effects-of-calling:java.io.DataOutputStream:flush
    //#unanalyzed(void run()): Effects-of-calling:java.io.DataOutputStream:close
    //#unanalyzed(void run()): Effects-of-calling:java.net.URLConnection:getInputStream
    //#unanalyzed(void run()): Effects-of-calling:java.io.InputStreamReader
    //#unanalyzed(void run()): Effects-of-calling:java.io.BufferedReader
    //#unanalyzed(void run()): Effects-of-calling:java.io.BufferedReader:readLine
    //#unanalyzed(void run()): Effects-of-calling:java.io.BufferedReader:close
    //#unanalyzed(void run()): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void run()): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void run()): Effects-of-calling:java.lang.UnsupportedOperationException
    //#unanalyzed(void run()): Effects-of-calling:com.dmdirc.logger.Logger:appError
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Thread:start
    //#test_vector(void run()): com.dmdirc.config.ConfigManager:getOptionBool(...)@129: {0}, {1}
    //#test_vector(void run()): com.dmdirc.config.ConfigManager:getOptionBool(...)@203: {0}, {1}
    //#test_vector(void run()): java.lang.StringBuilder:length(...)@164: {-2_147_483_648..0}, {1..4_294_967_295}
    //#test_vector(void run()): java.util.Iterator:hasNext(...)@142: {0}, {1}
    //#test_vector(void run()): java.util.Iterator:hasNext(...)@152: {0}, {1}
    //#test_vector(void run()): java.util.Iterator:hasNext(...)@187: {0}, {1}
    //#test_vector(void run()): java.util.List:isEmpty(...)@180: {0}, {1}
    //#test_vector(void run()): java.util.concurrent.Semaphore:tryAcquire(...)@121: {1}, {0}
    //#test_vector(void run()): update.status@142: Addr_Set{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#6)}, Inverse{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#6)}
    //#test_vector(void run()): update.status@187: Inverse{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#1)}, Addr_Set{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#1)}
            // Duplicate invocation

            return;
        }

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

        if (!config.getOptionBool("updater", "enable")
    //#UpdateChecker.java:129: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#UpdateChecker.java:129: ?unlocked shared daemon update: com/dmdirc/updater/UpdateChecker.status is subject to an unlocked shared daemon access via com.dmdirc.updater.Update$1:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#UpdateChecker.java:129: ?unlocked shared daemon update: status is subject to an unlocked shared daemon access via com.dmdirc.updater.UpdateChecker:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
                || status == STATE.UPDATING) {
            IdentityManager.getConfigIdentity().setOption("updater",
    //#UpdateChecker.java:131: Warning: method not available - call not analyzed
    //#    call on Identity com.dmdirc.config.IdentityManager:getConfigIdentity()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: Identity com.dmdirc.config.IdentityManager:getConfigIdentity()
    //#UpdateChecker.java:131: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.config.Identity:setOption(String, String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: void com.dmdirc.config.Identity:setOption(String, String, String)
                    "lastcheck", String.valueOf((int) (new Date().getTime() / 1000)));
        
            mutex.release();
            init();
            return;
        }

        setStatus(STATE.CHECKING);

        // Remove any existing update that isn't waiting for a restart.
        for (Update update : new ArrayList<Update>(updates)) {
            if (update.getStatus() != UpdateStatus.RESTART_NEEDED) {
                updates.remove(update);
            }
        }

        final StringBuilder data = new StringBuilder();
        final String updateChannel = config.getOption("updater", "channel");
    //#UpdateChecker.java:149: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.config.ConfigManager:getOption(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: String com.dmdirc.config.ConfigManager:getOption(String, String)

        // Build the data string to send to the server
        for (UpdateComponent component : components) {
            if (isEnabled(component)) {
                data.append(component.getName());
    //#UpdateChecker.java:154: Warning: call too complex - analysis skipped
    //#    call on String getName()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: String getName()
                data.append(',');
                data.append(updateChannel);
                data.append(',');
                data.append(component.getVersion());
    //#UpdateChecker.java:158: Warning: call too complex - analysis skipped
    //#    call on Version getVersion()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: Version getVersion()
                data.append(';');
            }
        }

        // If we actually have components to check
        if (data.length() > 0) {
            try {
                final List<String> response
                    = Downloader.getPage("http://updates.dmdirc.com/", "data=" + data);

                for (String line : response) {
                    checkLine(line);
                }
            } catch (MalformedURLException ex) {
                Logger.appError(ErrorLevel.LOW, "Error when checking for updates", ex);
    //#UpdateChecker.java:173: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:appError(ErrorLevel, String, Throwable)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:appError(ErrorLevel, String, Throwable)
            } catch (IOException ex) {
                Logger.userError(ErrorLevel.LOW,
    //#UpdateChecker.java:175: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                        "I/O error when checking for updates: " + ex.getMessage());
            }
        }

        if (updates.isEmpty()) {
            setStatus(STATE.IDLE);
        } else {
            boolean available = false;

            // Check to see if the updates are outstanding or just waiting for
            // a restart
            for (Update update : updates) {
                if (update.getStatus() == UpdateStatus.PENDING) {
                    available = true;
                }
            }
            
            setStatus(available ? STATE.UPDATES_AVAILABLE : STATE.RESTART_REQUIRED);
        }

        mutex.release();
        
        IdentityManager.getConfigIdentity().setOption("updater",
    //#UpdateChecker.java:198: Warning: method not available - call not analyzed
    //#    call on Identity com.dmdirc.config.IdentityManager:getConfigIdentity()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: Identity com.dmdirc.config.IdentityManager:getConfigIdentity()
    //#UpdateChecker.java:198: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.config.Identity:setOption(String, String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: void com.dmdirc.config.Identity:setOption(String, String, String)
                "lastcheck", String.valueOf((int) (new Date().getTime() / 1000)));
        
        UpdateChecker.init();
        
        if (config.getOptionBool("updater", "autoupdate")) {
    //#UpdateChecker.java:203: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void run()
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
            applyUpdates();
        }        
    }
    //#UpdateChecker.java:206: end of method: void com.dmdirc.updater.UpdateChecker.run()

    /**
     * Checks the specified line to determine the message from the update server.
     *
     * @param line The line to be checked
     */
    private void checkLine(final String line) {
        if (line.startsWith("outofdate")) {
    //#UpdateChecker.java:214: method: void com.dmdirc.updater.UpdateChecker.checkLine(String)
    //#input(void checkLine(String)): "Error when checking for updates: "._tainted
    //#input(void checkLine(String)): "Unknown update line received from server: "._tainted
    //#input(void checkLine(String)): "line: "._tainted
    //#input(void checkLine(String)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void checkLine(String)): com/dmdirc/updater/Update.com.dmdirc.logger.ErrorLevel.LOW
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/UpdateComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ActionGroupComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ClientComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/DefaultsComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/LauncherComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ModeAliasesComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/PluginComponent]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[others]
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void checkLine(String)): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void checkLine(String)): components
    //#input(void checkLine(String)): line
    //#input(void checkLine(String)): line._tainted
    //#input(void checkLine(String)): listener
    //#input(void checkLine(String)): this
    //#input(void checkLine(String)): updates
    //#pre[1] (void checkLine(String)): line != null
    //#presumption(void checkLine(String)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void checkLine(String)): Effects-of-calling:com.dmdirc.updater.Update
    //#unanalyzed(void checkLine(String)): Effects-of-calling:getUrl
    //#unanalyzed(void checkLine(String)): Effects-of-calling:addUpdateListener
    //#unanalyzed(void checkLine(String)): Effects-of-calling:getName
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void checkLine(String)): Effects-of-calling:java.lang.UnsupportedOperationException
    //#unanalyzed(void checkLine(String)): Effects-of-calling:com.dmdirc.logger.Logger:appError
    //#test_vector(void checkLine(String)): java.lang.String:startsWith(...)@214: {0}, {1}
    //#test_vector(void checkLine(String)): java.lang.String:startsWith(...)@216: {0}, {1}
    //#test_vector(void checkLine(String)): java.lang.String:startsWith(...)@219: {1}, {0}
            doUpdateAvailable(line);
        } else if (line.startsWith("error")) {
            Logger.userError(ErrorLevel.LOW, "Error when checking for updates: "
    //#UpdateChecker.java:217: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void checkLine(String)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                    + line.substring(6));
        } else if (!line.startsWith("uptodate")) {
            Logger.userError(ErrorLevel.LOW, "Unknown update line received from server: "
    //#UpdateChecker.java:220: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void checkLine(String)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                    + line);
        }
    }
    //#UpdateChecker.java:223: end of method: void com.dmdirc.updater.UpdateChecker.checkLine(String)

    /**
     * Informs the user that there's an update available.
     *
     * @param line The line that was received from the update server
     */
    private void doUpdateAvailable(final String line) {
        final Update update = new Update(line);
    //#UpdateChecker.java:231: method: void com.dmdirc.updater.UpdateChecker.doUpdateAvailable(String)
    //#input(void doUpdateAvailable(String)): "line: "._tainted
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/Update.com.dmdirc.logger.ErrorLevel.LOW
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/UpdateComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ActionGroupComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ClientComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/DefaultsComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/LauncherComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ModeAliasesComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/PluginComponent]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[others]
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void doUpdateAvailable(String)): components
    //#input(void doUpdateAvailable(String)): line
    //#input(void doUpdateAvailable(String)): line._tainted
    //#input(void doUpdateAvailable(String)): listener
    //#input(void doUpdateAvailable(String)): updates
    //#pre[1] (void doUpdateAvailable(String)): line != null
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:getName
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.lang.UnsupportedOperationException
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:com.dmdirc.logger.Logger:appError
    //#unanalyzed(void doUpdateAvailable(String)): Effects-of-calling:java.util.List:add

        if (update.getUrl() != null) {
    //#UpdateChecker.java:233: Warning: test always goes same way
    //#    Test predetermined because getUrl(...)@233 == null
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void doUpdateAvailable(String)
    //#    from bb: Entry_BB_1
    //#    live edge: Entry_BB_1-->bb_3
    //#    tested vn: com.dmdirc.updater.Update.Param_0.versionName == null
    //#    tested vn values: {1}
            updates.add(update);
    //#UpdateChecker.java:234: Warning: dead code
    //#    Dead code here because getUrl(...)@233 == null
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void doUpdateAvailable(String)
    //#    dead bb: bb_2
            update.addUpdateListener(listener);
        }
    }
    //#UpdateChecker.java:237: end of method: void com.dmdirc.updater.UpdateChecker.doUpdateAvailable(String)

    /**
     * Initialises the update checker. Sets a timer to check based on the
     * frequency specified in the config.
     */
    public static void init() {
        final int last = IdentityManager.getGlobalConfig()
    //#UpdateChecker.java:244: method: void com.dmdirc.updater.UpdateChecker.init()
    //#UpdateChecker.java:244: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void init()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#UpdateChecker.java:244: Warning: method not available - call not analyzed
    //#    call on int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void init()
    //#    unanalyzed callee: int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
    //#input(void init()): ", rescheduling."._tainted
    //#input(void init()): "Attempted to schedule update check "._tainted
    //#input(void init()): "in the past"._tainted
    //#input(void init()): "too far in the future"._tainted
    //#input(void init()): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void init()): timer
    //#output(void init()): new Timer(init#3) num objects
    //#output(void init()): timer
    //#new obj(void init()): new Timer(init#3)
    //#pre[1] (void init()): timer != null
    //#presumption(void init()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@244 != null
    //#presumption(void init()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@246 != null
    //#presumption(void init()): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void init()): java.util.Date:getTime(...)@248 in {-2_147_483_648_999..4_294_967_295_999}
    //#presumption(void init()): java.util.Date:getTime(...)@248/1_000 - (com.dmdirc.config.ConfigManager:getOptionInt(...)@244 + com.dmdirc.config.ConfigManager:getOptionInt(...)@246) in {-4_294_967_295..8_589_934_591}
    //#post(void init()): timer == &new Timer(init#3)
    //#post(void init()): new Timer(init#3) num objects == 1
    //#unanalyzed(void init()): Effects-of-calling:java.util.TimerTask
    //#test_vector(void init()): java.util.Date:getTime(...)@248/1_000 - (com.dmdirc.config.ConfigManager:getOptionInt(...)@244 + com.dmdirc.config.ConfigManager:getOptionInt(...)@246): {0..8_589_934_591}, {-4_294_967_295..-1}
                .getOptionInt("updater", "lastcheck");
        final int freq = IdentityManager.getGlobalConfig()
    //#UpdateChecker.java:246: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void init()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#UpdateChecker.java:246: Warning: method not available - call not analyzed
    //#    call on int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void init()
    //#    unanalyzed callee: int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
                .getOptionInt("updater", "frequency");
        final int timestamp = (int) (new Date().getTime() / 1000);
        int time = 0;

        if (last + freq > timestamp) {
            time = last + freq - timestamp;
        }

        if (time > freq || time < 0) {
            Logger.userError(ErrorLevel.LOW, "Attempted to schedule update check "
    //#UpdateChecker.java:256: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void init()
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                    + (time < 0 ? "in the past" : "too far in the future")
                    + ", rescheduling.");
            time = 1;
        }

        timer.cancel();
        timer = new Timer("Update Checker Timer");
        timer.schedule(new TimerTask() {
    //#UpdateChecker.java:264: method: void com.dmdirc.updater.UpdateChecker$2.com.dmdirc.updater.UpdateChecker$2()
    //#input(void com.dmdirc.updater.UpdateChecker$2()): this
    //#UpdateChecker.java:264: end of method: void com.dmdirc.updater.UpdateChecker$2.com.dmdirc.updater.UpdateChecker$2()
            /** {@inheritDoc} */
            @Override
            public void run() {
                checkNow();
    //#UpdateChecker.java:268: method: void com.dmdirc.updater.UpdateChecker$2.run()
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void run()): Effects-of-calling:java.lang.Thread:start
            }
    //#UpdateChecker.java:269: end of method: void com.dmdirc.updater.UpdateChecker$2.run()
        }, time * 1000);
    }
    //#UpdateChecker.java:271: end of method: void com.dmdirc.updater.UpdateChecker.init()

    /**
     * Checks for updates now.
     */
    public static void checkNow() {
        new Thread(new UpdateChecker(), "Update Checker thread").start();
    //#UpdateChecker.java:277: method: void com.dmdirc.updater.UpdateChecker.checkNow()
    }
    //#UpdateChecker.java:278: end of method: void com.dmdirc.updater.UpdateChecker.checkNow()

    /**
     * Registers an update component.
     *
     * @param component The component to be registered
     */
    public static void registerComponent(final UpdateComponent component) {
        components.add(component);
    //#UpdateChecker.java:286: method: void com.dmdirc.updater.UpdateChecker.registerComponent(UpdateComponent)
    //#input(void registerComponent(UpdateComponent)): component
    //#input(void registerComponent(UpdateComponent)): components
    }
    //#UpdateChecker.java:287: end of method: void com.dmdirc.updater.UpdateChecker.registerComponent(UpdateComponent)

    /**
     * Unregisters an update component with the specified name.
     *
     * @param name The name of the component to be removed
     */
    public static void removeComponent(final String name) {
        UpdateComponent target = null;
    //#UpdateChecker.java:295: method: void com.dmdirc.updater.UpdateChecker.removeComponent(String)
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/UpdateComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ActionGroupComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ClientComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/DefaultsComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/LauncherComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ModeAliasesComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/PluginComponent]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[others]
    //#input(void removeComponent(String)): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(void removeComponent(String)): components
    //#input(void removeComponent(String)): name
    //#pre[1] (void removeComponent(String)): (soft) name != null
    //#presumption(void removeComponent(String)): java.util.Iterator:next(...).__Tag@297 in {com/dmdirc/updater/UpdateComponent, com/dmdirc/updater/components/ActionGroupComponent, com/dmdirc/updater/components/ClientComponent, com/dmdirc/updater/components/DefaultsComponent, com/dmdirc/updater/components/LauncherComponent, com/dmdirc/updater/components/ModeAliasesComponent, com/dmdirc/updater/components/PluginComponent}
    //#presumption(void removeComponent(String)): java.util.Iterator:next(...)@297 != null
    //#test_vector(void removeComponent(String)): java.lang.String:equals(...)@298: {0}, {1}
    //#test_vector(void removeComponent(String)): java.util.Iterator:hasNext(...)@297: {0}, {1}

        for (UpdateComponent component : components) {
            if (name.equals(component.getName())) {
    //#UpdateChecker.java:298: Warning: call too complex - analysis skipped
    //#    call on String getName()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void removeComponent(String)
    //#    unanalyzed callee: String getName()
                target = component;
            }
        }

        if (target != null) {
            components.remove(target);
        }
    }
    //#UpdateChecker.java:306: end of method: void com.dmdirc.updater.UpdateChecker.removeComponent(String)

    /**
     * Finds and returns the component with the specified name.
     *
     * @param name The name of the component that we're looking for
     * @return The corresponding UpdateComponent, or null if it's not found
     */
    @Precondition("The specified name is not null")
    public static UpdateComponent findComponent(final String name) {
        assert(name != null);
    //#UpdateChecker.java:316: method: UpdateComponent com.dmdirc.updater.UpdateChecker.findComponent(String)
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/UpdateComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ActionGroupComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ClientComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/DefaultsComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/LauncherComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ModeAliasesComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/PluginComponent]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[others]
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(UpdateComponent findComponent(String)): components
    //#input(UpdateComponent findComponent(String)): name
    //#output(UpdateComponent findComponent(String)): return_value
    //#pre[1] (UpdateComponent findComponent(String)): name != null
    //#presumption(UpdateComponent findComponent(String)): java.util.Iterator:next(...).__Tag@318 in {com/dmdirc/updater/UpdateComponent, com/dmdirc/updater/components/ActionGroupComponent, com/dmdirc/updater/components/ClientComponent, com/dmdirc/updater/components/DefaultsComponent, com/dmdirc/updater/components/LauncherComponent, com/dmdirc/updater/components/ModeAliasesComponent, com/dmdirc/updater/components/PluginComponent}
    //#presumption(UpdateComponent findComponent(String)): java.util.Iterator:next(...)@318 != null
    //#post(UpdateComponent findComponent(String)): init'ed(return_value)
    //#test_vector(UpdateComponent findComponent(String)): java.lang.String:equals(...)@319: {0}, {1}
    //#test_vector(UpdateComponent findComponent(String)): java.util.Iterator:hasNext(...)@318: {0}, {1}

        for (UpdateComponent component : components) {
            if (name.equals(component.getName())) {
    //#UpdateChecker.java:319: Warning: call too complex - analysis skipped
    //#    call on String getName()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: UpdateComponent findComponent(String)
    //#    unanalyzed callee: String getName()
                return component;
            }
        }

        return null;
    //#UpdateChecker.java:324: end of method: UpdateComponent com.dmdirc.updater.UpdateChecker.findComponent(String)
    }

    /**
     * Removes the specified update from the list. This should be called when
     * the update has finished, has encountered an error, or the user does not
     * want the update to be performed.
     *
     * @param update The update to be removed
     */
    public static void removeUpdate(final Update update) {
        update.removeUpdateListener(listener);
    //#UpdateChecker.java:335: method: void com.dmdirc.updater.UpdateChecker.removeUpdate(Update)
    //#UpdateChecker.java:335: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void removeUpdate(Update)
    //#    suspicious precondition index: [1]
    //#    Attribs:  Soft
    //#input(void removeUpdate(Update)): com/dmdirc/updater/Update.__Descendant_Table[com/dmdirc/updater/Update]
    //#input(void removeUpdate(Update)): com/dmdirc/updater/Update.__Descendant_Table[others]
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateChecker$STATE.RESTART_REQUIRED
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateChecker$STATE.UPDATING
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void removeUpdate(Update)): com/dmdirc/updater/UpdateStatus.RESTART_NEEDED
    //#input(void removeUpdate(Update)): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void removeUpdate(Update)): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void removeUpdate(Update)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void removeUpdate(Update)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void removeUpdate(Update)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void removeUpdate(Update)): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void removeUpdate(Update)): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void removeUpdate(Update)): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void removeUpdate(Update)): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void removeUpdate(Update)): listener
    //#input(void removeUpdate(Update)): listeners
    //#input(void removeUpdate(Update)): listeners.__Tag
    //#input(void removeUpdate(Update)): listeners.listeners
    //#input(void removeUpdate(Update)): listeners.listeners.__Tag
    //#input(void removeUpdate(Update)): listeners.listeners.map
    //#input(void removeUpdate(Update)): new MapList(ListenerList#1).__Tag
    //#input(void removeUpdate(Update)): new MapList(ListenerList#1).map
    //#input(void removeUpdate(Update)): status
    //#input(void removeUpdate(Update)): update
    //#input(void removeUpdate(Update)): update.listeners
    //#input(void removeUpdate(Update)): updates
    //#output(void removeUpdate(Update)): status
    //#pre[4] (void removeUpdate(Update)): update != null
    //#pre[5] (void removeUpdate(Update)): update.listeners != null
    //#pre[1] (void removeUpdate(Update)): (soft) new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[2] (void removeUpdate(Update)): (soft) new MapList(ListenerList#1).map != null
    //#pre[3] (void removeUpdate(Update)): (soft) init'ed(status)
    //#post(void removeUpdate(Update)): status == One-of{&com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1), old status, &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5)}
    //#post(void removeUpdate(Update)): init'ed(status)
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:getStatus
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:doUpdate
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:setStatus
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:statusChanged
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.lang.Thread:start
    //#unanalyzed(void removeUpdate(Update)): Effects-of-calling:java.util.List:remove
    //#test_vector(void removeUpdate(Update)): java.util.List:isEmpty(...)@338: {0}, {1}
        updates.remove(update);

        if (updates.isEmpty()) {
            setStatus(STATE.IDLE);
        } else if (status == STATE.UPDATING) {
    //#UpdateChecker.java:340: ?unlocked shared daemon update: com/dmdirc/updater/UpdateChecker.status is subject to an unlocked shared daemon access via com.dmdirc.updater.Update$1:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void removeUpdate(Update)
    //#UpdateChecker.java:340: ?unlocked shared daemon update: status is subject to an unlocked shared daemon access via com.dmdirc.updater.UpdateChecker:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void removeUpdate(Update)
            doNextUpdate();
        }
    }
    //#UpdateChecker.java:343: end of method: void com.dmdirc.updater.UpdateChecker.removeUpdate(Update)
    
    /**
     * Downloads and installs all known updates.
     */
    public static void applyUpdates() {
        if (!updates.isEmpty()) {
    //#UpdateChecker.java:349: method: void com.dmdirc.updater.UpdateChecker.applyUpdates()
    //#UpdateChecker.java:349: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void applyUpdates()
    //#    suspicious precondition index: [1]
    //#    Attribs:  Soft
    //#input(void applyUpdates()): com/dmdirc/updater/Update.__Descendant_Table[com/dmdirc/updater/Update]
    //#input(void applyUpdates()): com/dmdirc/updater/Update.__Descendant_Table[others]
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateChecker$STATE.RESTART_REQUIRED
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateChecker$STATE.UPDATING
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void applyUpdates()): com/dmdirc/updater/UpdateStatus.RESTART_NEEDED
    //#input(void applyUpdates()): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void applyUpdates()): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void applyUpdates()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void applyUpdates()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void applyUpdates()): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void applyUpdates()): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void applyUpdates()): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void applyUpdates()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void applyUpdates()): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void applyUpdates()): listeners
    //#input(void applyUpdates()): listeners.__Tag
    //#input(void applyUpdates()): listeners.listeners
    //#input(void applyUpdates()): listeners.listeners.__Tag
    //#input(void applyUpdates()): listeners.listeners.map
    //#input(void applyUpdates()): new MapList(ListenerList#1).__Tag
    //#input(void applyUpdates()): new MapList(ListenerList#1).map
    //#input(void applyUpdates()): updates
    //#output(void applyUpdates()): status
    //#pre[1] (void applyUpdates()): (soft) new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[2] (void applyUpdates()): (soft) new MapList(ListenerList#1).map != null
    //#post(void applyUpdates()): status == One-of{old status, &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#3), &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5), &com.dmdi...
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void applyUpdates()): Effects-of-calling:getStatus
    //#unanalyzed(void applyUpdates()): Effects-of-calling:doUpdate
    //#unanalyzed(void applyUpdates()): Effects-of-calling:setStatus
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void applyUpdates()): Effects-of-calling:statusChanged
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void applyUpdates()): Effects-of-calling:java.lang.Thread:start
    //#test_vector(void applyUpdates()): java.util.List:isEmpty(...)@349: {1}, {0}
            setStatus(STATE.UPDATING);
            doNextUpdate();
        }
    }
    //#UpdateChecker.java:353: end of method: void com.dmdirc.updater.UpdateChecker.applyUpdates()
    
    /**
     * Finds and applies the next pending update, or sets the state to idle
     * / restart needed if appropriate.
     */
    private static void doNextUpdate() {
        boolean restart = false;
    //#UpdateChecker.java:360: method: void com.dmdirc.updater.UpdateChecker.doNextUpdate()
    //#UpdateChecker.java:360: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void doNextUpdate()
    //#    suspicious precondition index: [1]
    //#    Attribs:  Soft
    //#input(void doNextUpdate()): com/dmdirc/updater/Update.__Descendant_Table[com/dmdirc/updater/Update]
    //#input(void doNextUpdate()): com/dmdirc/updater/Update.__Descendant_Table[others]
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateChecker$STATE.IDLE
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateChecker$STATE.RESTART_REQUIRED
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateStatus.PENDING
    //#input(void doNextUpdate()): com/dmdirc/updater/UpdateStatus.RESTART_NEEDED
    //#input(void doNextUpdate()): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void doNextUpdate()): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void doNextUpdate()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void doNextUpdate()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void doNextUpdate()): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void doNextUpdate()): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void doNextUpdate()): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void doNextUpdate()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void doNextUpdate()): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void doNextUpdate()): listeners
    //#input(void doNextUpdate()): listeners.__Tag
    //#input(void doNextUpdate()): listeners.listeners
    //#input(void doNextUpdate()): listeners.listeners.__Tag
    //#input(void doNextUpdate()): listeners.listeners.map
    //#input(void doNextUpdate()): new MapList(ListenerList#1).__Tag
    //#input(void doNextUpdate()): new MapList(ListenerList#1).map
    //#input(void doNextUpdate()): updates
    //#output(void doNextUpdate()): status
    //#pre[1] (void doNextUpdate()): (soft) new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[2] (void doNextUpdate()): (soft) new MapList(ListenerList#1).map != null
    //#presumption(void doNextUpdate()): java.util.Iterator:next(...).__Tag@362 == com/dmdirc/updater/Update
    //#presumption(void doNextUpdate()): java.util.Iterator:next(...)@362 != null
    //#post(void doNextUpdate()): status == One-of{old status, &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#5), &com.dmdirc.updater.UpdateChecker$STATE__static_init.new UpdateChecker$STATE(UpdateChecker$STATE__static_init#1)}
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:statusChanged
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.lang.Thread
    //#unanalyzed(void doNextUpdate()): Effects-of-calling:java.lang.Thread:start
    //#test_vector(void doNextUpdate()): java.util.Iterator:hasNext(...)@362: {0}, {1}
    //#test_vector(void doNextUpdate()): update.status@362: Inverse{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#1),&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#6)}, Addr_Set{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#1)}, Addr_Set{&com.dmdirc.updater.UpdateStatus__static_init.new UpdateStatus(UpdateStatus__static_init#6)}
        
        for (Update update : updates) {
            if (update.getStatus() == UpdateStatus.PENDING) {
                update.doUpdate();
                return;
            } else if (update.getStatus() == UpdateStatus.RESTART_NEEDED) {
                restart = true;
            }
        }
        
        setStatus(restart ? STATE.RESTART_REQUIRED : STATE.IDLE);
    }
    //#UpdateChecker.java:372: end of method: void com.dmdirc.updater.UpdateChecker.doNextUpdate()

    /**
     * Retrieves a list of components registered with the checker.
     *
     * @return A list of registered components
     */
    public static List<UpdateComponent> getComponents() {
        return components;
    //#UpdateChecker.java:380: method: List com.dmdirc.updater.UpdateChecker.getComponents()
    //#input(List getComponents()): components
    //#output(List getComponents()): return_value
    //#post(List getComponents()): return_value == &new ArrayList(UpdateChecker__static_init#2)
    //#UpdateChecker.java:380: end of method: List com.dmdirc.updater.UpdateChecker.getComponents()
    }

    /**
     * Retrives a list of available updates from the checker.
     *
     * @return A list of available updates
     */
    public static List<Update> getAvailableUpdates() {
        return updates;
    //#UpdateChecker.java:389: method: List com.dmdirc.updater.UpdateChecker.getAvailableUpdates()
    //#input(List getAvailableUpdates()): updates
    //#output(List getAvailableUpdates()): return_value
    //#post(List getAvailableUpdates()): return_value == &new ArrayList(UpdateChecker__static_init#4)
    //#UpdateChecker.java:389: end of method: List com.dmdirc.updater.UpdateChecker.getAvailableUpdates()
    }


    /**
     * Adds a new status listener to the update checker.
     *
     * @param listener The listener to be added
     */
    public static void addListener(final UpdateCheckerListener listener) {
        listeners.add(UpdateCheckerListener.class, listener);
    //#UpdateChecker.java:399: method: void com.dmdirc.updater.UpdateChecker.addListener(UpdateCheckerListener)
    //#UpdateChecker.java:399: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void addListener(UpdateCheckerListener)
    //#    suspicious precondition index: [5]
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/ListenerList.__Dispatch_Table.add(Ljava/lang/Class;Ljava/lang/Object;)V
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Dispatch_Table.add(Ljava/lang/Object;Ljava/lang/Object;)V
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Dispatch_Table.safeGet(Ljava/lang/Object;)Ljava/util/List;
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/WeakMapList.__Dispatch_Table.add(Ljava/lang/Object;Ljava/lang/Object;)V
    //#input(void addListener(UpdateCheckerListener)): com/dmdirc/util/WeakMapList.__Dispatch_Table.safeGet(Ljava/lang/Object;)Ljava/util/List;
    //#input(void addListener(UpdateCheckerListener)): listener
    //#input(void addListener(UpdateCheckerListener)): listeners
    //#input(void addListener(UpdateCheckerListener)): listeners.__Tag
    //#input(void addListener(UpdateCheckerListener)): listeners.listeners
    //#input(void addListener(UpdateCheckerListener)): listeners.listeners.__Tag
    //#input(void addListener(UpdateCheckerListener)): listeners.listeners.map
    //#input(void addListener(UpdateCheckerListener)): new MapList(ListenerList#1).__Tag
    //#input(void addListener(UpdateCheckerListener)): new MapList(ListenerList#1).map
    //#pre[5] (void addListener(UpdateCheckerListener)): new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[6] (void addListener(UpdateCheckerListener)): new MapList(ListenerList#1).map != null
    //#unanalyzed(void addListener(UpdateCheckerListener)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void addListener(UpdateCheckerListener)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void addListener(UpdateCheckerListener)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void addListener(UpdateCheckerListener)): Effects-of-calling:java.util.Map:put
    //#unanalyzed(void addListener(UpdateCheckerListener)): Effects-of-calling:java.util.List:add
    }
    //#UpdateChecker.java:400: end of method: void com.dmdirc.updater.UpdateChecker.addListener(UpdateCheckerListener)

    /**
     * Removes a status listener from the update checker.
     *
     * @param listener The listener to be removed
     */
    public static void removeListener(final UpdateCheckerListener listener) {
        listeners.remove(UpdateCheckerListener.class, listener);
    //#UpdateChecker.java:408: method: void com.dmdirc.updater.UpdateChecker.removeListener(UpdateCheckerListener)
    //#UpdateChecker.java:408: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void removeListener(UpdateCheckerListener)
    //#    suspicious precondition index: [5]
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/ListenerList.__Dispatch_Table.remove(Ljava/lang/Class;Ljava/lang/Object;)V
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/MapList.__Dispatch_Table.remove(Ljava/lang/Object;Ljava/lang/Object;)V
    //#input(void removeListener(UpdateCheckerListener)): com/dmdirc/util/WeakMapList.__Dispatch_Table.remove(Ljava/lang/Object;Ljava/lang/Object;)V
    //#input(void removeListener(UpdateCheckerListener)): listener
    //#input(void removeListener(UpdateCheckerListener)): listeners
    //#input(void removeListener(UpdateCheckerListener)): listeners.__Tag
    //#input(void removeListener(UpdateCheckerListener)): listeners.listeners
    //#input(void removeListener(UpdateCheckerListener)): listeners.listeners.__Tag
    //#input(void removeListener(UpdateCheckerListener)): listeners.listeners.map
    //#input(void removeListener(UpdateCheckerListener)): new MapList(ListenerList#1).__Tag
    //#input(void removeListener(UpdateCheckerListener)): new MapList(ListenerList#1).map
    //#pre[5] (void removeListener(UpdateCheckerListener)): new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[6] (void removeListener(UpdateCheckerListener)): new MapList(ListenerList#1).map != null
    //#unanalyzed(void removeListener(UpdateCheckerListener)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void removeListener(UpdateCheckerListener)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void removeListener(UpdateCheckerListener)): Effects-of-calling:java.util.List:remove
    }
    //#UpdateChecker.java:409: end of method: void com.dmdirc.updater.UpdateChecker.removeListener(UpdateCheckerListener)

    /**
     * Retrieves the current status of the update checker.
     *
     * @return The update checker's current status
     */
    public static STATE getStatus() {
        return status;
    //#UpdateChecker.java:417: method: UpdateChecker$STATE com.dmdirc.updater.UpdateChecker.getStatus()
    //#input(UpdateChecker$STATE getStatus()): status
    //#output(UpdateChecker$STATE getStatus()): return_value
    //#pre[1] (UpdateChecker$STATE getStatus()): init'ed(status)
    //#post(UpdateChecker$STATE getStatus()): return_value == status
    //#post(UpdateChecker$STATE getStatus()): init'ed(return_value)
    //#UpdateChecker.java:417: end of method: UpdateChecker$STATE com.dmdirc.updater.UpdateChecker.getStatus()
    }

    /**
     * Sets the status of the update checker to the specified new status.
     *
     * @param newStatus The new status of this checker
     */
    private static void setStatus(final STATE newStatus) {
        status = newStatus;
    //#UpdateChecker.java:426: method: void com.dmdirc.updater.UpdateChecker.setStatus(UpdateChecker$STATE)
    //#UpdateChecker.java:426: Warning: suspicious precondition
    //#    The precondition for new MapList(ListenerList#1).__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void setStatus(UpdateChecker$STATE)
    //#    suspicious precondition index: [4]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[com/dmdirc/updater/UpdateCheckerListener]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/updater/UpdateCheckerListener.__Descendant_Table[others]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/updater/UpdateCheckerListener.__Dispatch_Table.statusChanged(Lcom/dmdirc/updater/UpdateChecker$STATE;)V
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/ListenerList.__Descendant_Table[com/dmdirc/util/ListenerList]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/ListenerList.__Dispatch_Table.get(Ljava/lang/Class;)Ljava/util/List;
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void setStatus(UpdateChecker$STATE)): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void setStatus(UpdateChecker$STATE)): listeners
    //#input(void setStatus(UpdateChecker$STATE)): listeners.__Tag
    //#input(void setStatus(UpdateChecker$STATE)): listeners.listeners
    //#input(void setStatus(UpdateChecker$STATE)): listeners.listeners.__Tag
    //#input(void setStatus(UpdateChecker$STATE)): listeners.listeners.map
    //#input(void setStatus(UpdateChecker$STATE)): new MapList(ListenerList#1).__Tag
    //#input(void setStatus(UpdateChecker$STATE)): new MapList(ListenerList#1).map
    //#input(void setStatus(UpdateChecker$STATE)): newStatus
    //#output(void setStatus(UpdateChecker$STATE)): status
    //#pre[4] (void setStatus(UpdateChecker$STATE)): new MapList(ListenerList#1).__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[5] (void setStatus(UpdateChecker$STATE)): new MapList(ListenerList#1).map != null
    //#presumption(void setStatus(UpdateChecker$STATE)): java.util.Iterator:next(...).__Tag@428 == com/dmdirc/updater/UpdateCheckerListener
    //#presumption(void setStatus(UpdateChecker$STATE)): java.util.Iterator:next(...)@428 != null
    //#post(void setStatus(UpdateChecker$STATE)): status == newStatus
    //#post(void setStatus(UpdateChecker$STATE)): init'ed(status)
    //#unanalyzed(void setStatus(UpdateChecker$STATE)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void setStatus(UpdateChecker$STATE)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void setStatus(UpdateChecker$STATE)): Effects-of-calling:java.util.ArrayList
    //#test_vector(void setStatus(UpdateChecker$STATE)): java.util.Iterator:hasNext(...)@428: {0}, {1}
    //#UpdateChecker.java:426: ?unlocked shared daemon update: com/dmdirc/updater/UpdateChecker.status is subject to an unlocked shared daemon access via com.dmdirc.updater.Update$1:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void setStatus(UpdateChecker$STATE)
    //#UpdateChecker.java:426: ?unlocked shared daemon update: status is subject to an unlocked shared daemon access via com.dmdirc.updater.UpdateChecker:run().
    //#    severity: LOW
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void setStatus(UpdateChecker$STATE)

        for (UpdateCheckerListener myListener : listeners.get(UpdateCheckerListener.class)) {
    //#UpdateChecker.java:428: ?null dereference
    //#    get(...) != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void setStatus(UpdateChecker$STATE)
    //#    basic block: Entry_BB_1
    //#    assertion: get(...) != null
    //#    VN: get(...)
    //#    Expected: Inverse{null} or Invalid
    //#    Bad: Addr_Set{null}
    //#    Attribs:  Ptr  null in Bad
            myListener.statusChanged(newStatus);
    //#UpdateChecker.java:429: Warning: method not available - call not analyzed
    //#    call on void statusChanged(UpdateChecker$STATE)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: void setStatus(UpdateChecker$STATE)
    //#    unanalyzed callee: void statusChanged(UpdateChecker$STATE)
        }
    }
    //#UpdateChecker.java:431: end of method: void com.dmdirc.updater.UpdateChecker.setStatus(UpdateChecker$STATE)

    /**
     * Checks is a specified component is enabled.
     *
     * @param component Update component to check state
     *
     * @return true iif the update component is enabled
     */
    public static boolean isEnabled(final UpdateComponent component) {
        return !IdentityManager.getGlobalConfig().hasOptionString("updater",
    //#UpdateChecker.java:441: method: bool com.dmdirc.updater.UpdateChecker.isEnabled(UpdateComponent)
    //#UpdateChecker.java:441: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: bool isEnabled(UpdateComponent)
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#UpdateChecker.java:441: Warning: call too complex - analysis skipped
    //#    call on String getName()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: bool isEnabled(UpdateComponent)
    //#    unanalyzed callee: String getName()
    //#UpdateChecker.java:441: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:hasOptionString(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: bool isEnabled(UpdateComponent)
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:hasOptionString(String, String)
    //#UpdateChecker.java:441: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: bool isEnabled(UpdateComponent)
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#UpdateChecker.java:441: Warning: suspicious precondition
    //#    The precondition for component.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.updater.UpdateChecker
    //#    method: bool isEnabled(UpdateComponent)
    //#    suspicious precondition index: [2]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/UpdateComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ActionGroupComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ClientComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/DefaultsComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/LauncherComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/ModeAliasesComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[com/dmdirc/updater/components/PluginComponent]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Descendant_Table[others]
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/UpdateComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/components/ActionGroupComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/components/ClientComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/components/DefaultsComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/components/LauncherComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/components/ModeAliasesComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): com/dmdirc/updater/components/PluginComponent.__Dispatch_Table.getName()Ljava/lang/String;
    //#input(bool isEnabled(UpdateComponent)): component
    //#input(bool isEnabled(UpdateComponent)): component.__Tag
    //#output(bool isEnabled(UpdateComponent)): return_value
    //#pre[1] (bool isEnabled(UpdateComponent)): component != null
    //#pre[2] (bool isEnabled(UpdateComponent)): component.__Tag in {com/dmdirc/updater/UpdateComponent, com/dmdirc/updater/components/ActionGroupComponent, com/dmdirc/updater/components/ClientComponent, com/dmdirc/updater/components/DefaultsComponent, com/dmdirc/updater/components/LauncherComponent, com/dmdirc/updater/components/ModeAliasesComponent, com/dmdirc/updater/components/PluginComponent}
    //#presumption(bool isEnabled(UpdateComponent)): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@441 != null
    //#presumption(bool isEnabled(UpdateComponent)): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@441 != null
    //#post(bool isEnabled(UpdateComponent)): init'ed(return_value)
    //#UpdateChecker.java:441: end of method: bool com.dmdirc.updater.UpdateChecker.isEnabled(UpdateComponent)
                component.getName()) || IdentityManager.getGlobalConfig()
                .getOptionBool("updater", component.getName());
    }

}
    //#output(com.dmdirc.updater.UpdateChecker$2__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker$2]
    //#output(com.dmdirc.updater.UpdateChecker$2__static_init): __Dispatch_Table.run()V
    //#post(com.dmdirc.updater.UpdateChecker$2__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker$2] == &__Dispatch_Table
    //#post(com.dmdirc.updater.UpdateChecker$2__static_init): __Dispatch_Table.run()V == &run
    //#UpdateChecker.java:: end of method: com.dmdirc.updater.UpdateChecker$2.com.dmdirc.updater.UpdateChecker$2__static_init
    //#UpdateChecker.java:: end of class: com.dmdirc.updater.UpdateChecker$2
    //#UpdateChecker.java:: end of class: com.dmdirc.updater.UpdateChecker$STATE
    //#output(com.dmdirc.updater.UpdateChecker$1__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker$1]
    //#output(com.dmdirc.updater.UpdateChecker$1__static_init): __Dispatch_Table.updateProgressChange(Lcom/dmdirc/updater/Update;F)V
    //#output(com.dmdirc.updater.UpdateChecker$1__static_init): __Dispatch_Table.updateStatusChange(Lcom/dmdirc/updater/Update;Lcom/dmdirc/updater/UpdateStatus;)V
    //#output(com.dmdirc.updater.UpdateChecker$1__static_init): com/dmdirc/updater/UpdateListener.__Descendant_Table[com/dmdirc/updater/UpdateChecker$1]
    //#post(com.dmdirc.updater.UpdateChecker$1__static_init): __Descendant_Table[com/dmdirc/updater/UpdateChecker$1] == &__Dispatch_Table
    //#post(com.dmdirc.updater.UpdateChecker$1__static_init): com/dmdirc/updater/UpdateListener.__Descendant_Table[com/dmdirc/updater/UpdateChecker$1] == &__Dispatch_Table
    //#post(com.dmdirc.updater.UpdateChecker$1__static_init): __Dispatch_Table.updateProgressChange(Lcom/dmdirc/updater/Update;F)V == &updateProgressChange
    //#post(com.dmdirc.updater.UpdateChecker$1__static_init): __Dispatch_Table.updateStatusChange(Lcom/dmdirc/updater/Update;Lcom/dmdirc/updater/UpdateStatus;)V == &updateStatusChange
    //#UpdateChecker.java:: end of method: com.dmdirc.updater.UpdateChecker$1.com.dmdirc.updater.UpdateChecker$1__static_init
    //#UpdateChecker.java:: end of class: com.dmdirc.updater.UpdateChecker$1
    //#UpdateChecker.java:: end of class: com.dmdirc.updater.UpdateChecker
