You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2014/04/26 05:39:35 UTC

[14/27] fdb with worker support

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/a3765ae5/modules/fdbworkers/src/flex/tools/debugger/cli/DebugCLI.java
----------------------------------------------------------------------
diff --git a/modules/fdbworkers/src/flex/tools/debugger/cli/DebugCLI.java b/modules/fdbworkers/src/flex/tools/debugger/cli/DebugCLI.java
new file mode 100644
index 0000000..588a977
--- /dev/null
+++ b/modules/fdbworkers/src/flex/tools/debugger/cli/DebugCLI.java
@@ -0,0 +1,7567 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package flex.tools.debugger.cli;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import flash.localization.LocalizationManager;
+import flash.tools.debugger.Bootstrap;
+import flash.tools.debugger.DebuggerLocalizer;
+import flash.tools.debugger.Frame;
+import flash.tools.debugger.InProgressException;
+import flash.tools.debugger.Isolate;
+import flash.tools.debugger.IsolateSession;
+import flash.tools.debugger.Location;
+import flash.tools.debugger.NoResponseException;
+import flash.tools.debugger.NotConnectedException;
+import flash.tools.debugger.NotSupportedException;
+import flash.tools.debugger.NotSuspendedException;
+import flash.tools.debugger.PlayerDebugException;
+import flash.tools.debugger.Session;
+import flash.tools.debugger.SessionManager;
+import flash.tools.debugger.SourceFile;
+import flash.tools.debugger.SourceLocator;
+import flash.tools.debugger.SuspendReason;
+import flash.tools.debugger.SuspendedException;
+import flash.tools.debugger.SwfInfo;
+import flash.tools.debugger.Value;
+import flash.tools.debugger.Variable;
+import flash.tools.debugger.VariableAttribute;
+import flash.tools.debugger.VariableType;
+import flash.tools.debugger.VersionException;
+import flash.tools.debugger.Watch;
+import flash.tools.debugger.WatchKind;
+import flash.tools.debugger.concrete.DProtocol;
+import flash.tools.debugger.events.BreakEvent;
+import flash.tools.debugger.events.ConsoleErrorFault;
+import flash.tools.debugger.events.DebugEvent;
+import flash.tools.debugger.events.ExceptionFault;
+import flash.tools.debugger.events.FaultEvent;
+import flash.tools.debugger.events.FileListModifiedEvent;
+import flash.tools.debugger.events.FunctionMetaDataAvailableEvent;
+import flash.tools.debugger.events.IsolateCreateEvent;
+import flash.tools.debugger.events.IsolateExitEvent;
+import flash.tools.debugger.events.SwfLoadedEvent;
+import flash.tools.debugger.events.SwfUnloadedEvent;
+import flash.tools.debugger.events.TraceEvent;
+import flash.tools.debugger.expression.ECMA;
+import flash.tools.debugger.expression.NoSuchVariableException;
+import flash.tools.debugger.expression.PlayerFaultException;
+import flash.tools.debugger.expression.ValueExp;
+import flash.util.FieldFormat;
+import flash.util.Trace;
+import flex.tools.debugger.cli.ExpressionCache.EvaluationResult;
+import flex.tools.debugger.cli.FaultActions.FaultActionsBuilder;
+
+/**
+ * This is a front end command line interface to the Flash Debugger
+ * Player.
+ *<p>
+ * This tool utilizes the Debugger Java API (DJAPI) for Flash 
+ * Player that exists in flash.tools.debuggger.
+ *<p> 
+ * This tool is not completely compliant with the API, since
+ * some commands expose implementation specific information for
+ * debugging purposes.  Instances where this occurs are kept to a
+ * minimum and are isolated in a special class called Extensions.  
+ * If you wish to build a version that is completely API 
+ * compatible.  Replace Extensions with ExtensionsDisabled in 
+ * the static method calls at the end of this file. 
+ */
+public class DebugCLI implements Runnable, SourceLocator
+{
+	public static final String VERSION			= "82"; //$NON-NLS-1$
+
+	public static final int CMD_UNKNOWN			= 0;
+	public static final int CMD_QUIT			= 1;
+	public static final int CMD_CONTINUE		= 2;
+	public static final int CMD_STEP			= 3;
+	public static final int CMD_NEXT			= 4;
+	public static final int CMD_FINISH			= 5;
+	public static final int CMD_BREAK			= 6;
+	public static final int CMD_SET				= 7;
+	public static final int CMD_LIST			= 8;
+	public static final int CMD_PRINT			= 9;
+	public static final int CMD_TUTORIAL		= 10;
+	public static final int CMD_INFO			= 11;
+	public static final int CMD_HOME			= 12;
+	public static final int CMD_RUN				= 13;
+	public static final int CMD_FILE			= 14;
+	public static final int CMD_DELETE			= 15;
+	public static final int CMD_SOURCE			= 16;
+	public static final int CMD_COMMENT			= 17;
+	public static final int CMD_CLEAR			= 18;
+	public static final int CMD_HELP			= 19;
+	public static final int CMD_SHOW			= 20;
+	public static final int CMD_KILL			= 21;
+	public static final int CMD_HANDLE			= 22;
+	public static final int CMD_ENABLE			= 23;
+	public static final int CMD_DISABLE			= 24;
+	public static final int CMD_DISPLAY			= 25;
+	public static final int CMD_UNDISPLAY		= 26;
+ 	public static final int CMD_COMMANDS		= 27;
+    public static final int CMD_PWD             = 28;
+    public static final int CMD_CF              = 29;
+    public static final int CMD_CONDITION		= 30;
+	public static final int CMD_AWATCH			= 31;
+	public static final int CMD_WATCH			= 32;
+	public static final int CMD_RWATCH			= 33;
+	public static final int CMD_WHAT			= 34;
+	public static final int CMD_DISASSEMBLE		= 35;
+	public static final int CMD_HALT			= 36;
+	public static final int CMD_MCTREE			= 37;
+	public static final int CMD_VIEW_SWF		= 38;
+	public static final int CMD_DOWN			= 39;
+	public static final int CMD_UP				= 40;
+	public static final int CMD_FRAME			= 41;
+	public static final int CMD_DIRECTORY		= 42;
+	public static final int CMD_CATCH			= 43;
+	public static final int CMD_CONNECT			= 44;
+	public static final int CMD_WORKER			= 45;
+
+	/* info sub commands */
+	public static final int INFO_UNKNOWN_CMD	= 100;
+	public static final int INFO_ARGS_CMD		= 101;
+	public static final int INFO_BREAK_CMD		= 102;
+	public static final int INFO_FILES_CMD		= 103;
+	public static final int INFO_HANDLE_CMD		= 104;
+	public static final int INFO_FUNCTIONS_CMD	= 105;
+	public static final int INFO_LOCALS_CMD		= 106;
+	public static final int INFO_SCOPECHAIN_CMD	= 107;
+	public static final int INFO_SOURCES_CMD	= 108;
+	public static final int INFO_STACK_CMD		= 109;
+	public static final int INFO_VARIABLES_CMD	= 110;
+	public static final int INFO_DISPLAY_CMD	= 111;
+    public static final int INFO_TARGETS_CMD    = 112;
+    public static final int INFO_SWFS_CMD		= 113;
+    public static final int INFO_WORKERS_CMD	= 114;
+
+	/* show subcommands */
+	public static final int SHOW_UNKNOWN_CMD	= 200;
+	public static final int SHOW_NET_CMD		= 201;
+	public static final int SHOW_FUNC_CMD		= 202;
+	public static final int SHOW_URI_CMD		= 203;
+	public static final int SHOW_PROPERTIES_CMD	= 204;
+	public static final int SHOW_FILES_CMD		= 205;
+	public static final int SHOW_BREAK_CMD		= 206;
+	public static final int SHOW_VAR_CMD		= 207;
+	public static final int SHOW_MEM_CMD		= 208;
+	public static final int SHOW_LOC_CMD		= 209;
+	public static final int SHOW_DIRS_CMD		= 210;
+
+	/* misc subcommands */
+	public static final int ENABLE_ONCE_CMD		= 301;
+
+    // default metadata retry count 8 attempts per waitForMetadata() call * 5 calls
+    public static final int METADATA_RETRIES    = 8*5;
+    
+    /* Enum for the state of the initial prompt shown when a swf is loaded */
+    public static enum InitialPromptState { NEVER_SHOWN, SHOWN_ONCE, DONE }  
+
+	Stack<LineNumberReader> m_readerStack = new Stack<LineNumberReader>();
+	public PrintStream m_err;
+	public PrintStream m_out;
+	Session		m_session;
+	String		m_launchURI;
+	boolean		m_fullnameOption; // emacs mode
+	String		m_cdPath;
+	String		m_mruURI;
+	String m_connectPort;
+	public final static String m_newline = System.getProperty("line.separator"); //$NON-NLS-1$
+
+	private final static LocalizationManager m_localizationManager = new LocalizationManager();
+	private final static FaultActionsBuilder faultActionsBuilder = new FaultActionsBuilder(m_localizationManager);
+	
+	List<String>	m_sourceDirectories; // List of String
+	int				m_sourceDirectoriesChangeCount;
+	private File	m_flexHomeDirectory; // <application.home>/frameworks/projects/*/src always goes in m_sourceDirectories
+	private boolean	m_initializedFlexHomeDirectory;
+
+	// context information for our current session
+	FileInfoCache	m_fileInfo;
+	FaultActions	m_faultTable;
+	Vector<Integer> m_breakIsolates;
+	ExpressionCache m_exprCache;
+	Vector<BreakAction>	        m_breakpoints;
+	Vector<WatchAction>			m_watchpoints;
+	Vector<CatchAction>			m_catchpoints;
+	ArrayList<DisplayAction>	m_displays;
+//	boolean			m_requestResume;
+//	boolean			m_requestHalt;
+//	boolean			m_stepResume;
+	int m_activeIsolate;
+	DebugCLIIsolateState m_mainState;
+	
+	/* This indicates the isolate for which we have been showing prompts for setting 
+	 * breakpoints( so that we don't switch worker while the user is setting breakpoints) */
+	int m_lastPromptIsolate;
+	
+	private HashMap<Integer, DebugCLIIsolateState> m_isolateState;
+	
+	class DebugCLIIsolateState
+	{
+//		public FileInfoCache	m_fileInfo;
+//		public ExpressionCache m_exprCache;
+		public boolean			m_requestResume;
+		public boolean			m_requestHalt;
+		public boolean			m_stepResume;
+		/* Indicates whether the prompt for setting initial breakpoints has been displayed for this isolate */
+		public InitialPromptState			m_promptState;
+//		public Vector<BreakAction>	        m_breakpoints;
+//		public Vector<WatchAction>			m_watchpoints;
+//		public Vector<CatchAction>			m_catchpoints;
+//		public ArrayList<DisplayAction>	m_displays;
+
+		
+		public DebugCLIIsolateState(DebugCLI debugcli) {
+//			m_exprCache = new ExpressionCache(debugcli);
+			m_faultTable = faultActionsBuilder.build();//new FaultActions();
+//			m_breakpoints = new Vector<BreakAction>();
+//			m_watchpoints = new Vector<WatchAction>();
+//			m_catchpoints = new Vector<CatchAction>();
+//			m_displays = new ArrayList<DisplayAction>();
+		}
+	}
+	
+	private DebugCLIIsolateState getIsolateState(int isolateId) {
+		if (isolateId == Isolate.DEFAULT_ID)
+			return m_mainState;
+		DebugCLIIsolateState isolateState = null;
+		if (!m_isolateState.containsKey(isolateId)) {
+			isolateState = new DebugCLIIsolateState(this);
+			m_isolateState.put(isolateId, isolateState);
+		}
+		else
+			isolateState = m_isolateState.get(isolateId);
+		return isolateState;
+	}
+	
+	public int getActiveIsolateId() {
+		return m_activeIsolate;
+	}
+	
+	private boolean getRequestResume(int isolateId) {
+		return getIsolateState(isolateId).m_requestResume;
+	}
+	
+	private void setRequestResume(boolean value, int isolateId) {
+		getIsolateState(isolateId).m_requestResume = value;
+	}
+	
+	private boolean getStepResume(int isolateId) {
+		return getIsolateState(isolateId).m_stepResume;
+	}
+	
+	private void setStepResume(boolean value, int isolateId) {
+		getIsolateState(isolateId).m_stepResume = value;
+	}
+	
+	private boolean getRequestHalt(int isolateId) {
+		return getIsolateState(isolateId).m_requestHalt;
+	}
+	
+	private void setRequestHalt(boolean value, int isolateId) {
+		getIsolateState(isolateId).m_requestHalt = value;
+	}
+	
+	private InitialPromptState getPromptState(int isolateId) {
+		return getIsolateState(isolateId).m_promptState;
+	}
+	
+	private void setPromptState(InitialPromptState value, int isolateId) {
+		getIsolateState(isolateId).m_promptState = value;
+	}
+
+	/* our current input processing context */
+	LineNumberReader	m_in;
+	public LineNumberReader	m_keyboardStream;
+	Vector<String>		m_keyboardInput;
+	boolean				m_keyboardReadRequest;
+	StringTokenizer		m_currentTokenizer;
+	String				m_currentToken;
+	String				m_currentLine;
+	public String		m_repeatLine;	
+
+	/**
+	 * The module that the next "list" command should display if no
+	 * module is explicitly specified.
+	 */
+	public static final String LIST_MODULE = "$listmodule"; //$NON-NLS-1$
+
+	/**
+	 * The line number at which the next "list" command should begin if no
+	 * line number is explicitly specified.
+	 */
+	public static final String LIST_LINE = "$listline"; //$NON-NLS-1$
+	
+	public static final String LIST_WORKER = "$listworker"; //$NON-NLS-1$
+
+	/**
+	 * The number of lines displayed by the "list" command.
+	 */
+	private static final String LIST_SIZE = "$listsize"; //$NON-NLS-1$
+
+	private static final String COLUMN_WIDTH = "$columnwidth"; //$NON-NLS-1$
+
+	private static final String UPDATE_DELAY = "$updatedelay"; //$NON-NLS-1$
+
+	private static final String HALT_TIMEOUT = "$halttimeout"; //$NON-NLS-1$
+
+	/**
+	 * Current breakpoint number.
+	 */
+	private static final String BPNUM = "$bpnum"; //$NON-NLS-1$
+
+	/**
+	 * Used to determine how much context information should be displayed.
+	 */
+	private static final String LAST_FRAME_DEPTH = "$lastframedepth"; //$NON-NLS-1$
+
+	/**
+	 * Used to determine how much context information should be displayed.
+	 */
+	private static final String CURRENT_FRAME_DEPTH = "$currentframedepth"; //$NON-NLS-1$
+
+	/**
+	 * The current frame we are viewing -- controlled by the "up", "down", and "frame" commands.
+	 */
+	public static final String DISPLAY_FRAME_NUMBER = "$displayframenumber"; //$NON-NLS-1$
+
+	private static final String FILE_LIST_WRAP = "$filelistwrap"; //$NON-NLS-1$
+
+	private static final String NO_WAITING = "$nowaiting"; //$NON-NLS-1$
+
+	/**
+	 * Show this pointer for info stack.
+	 */
+	private static final String INFO_STACK_SHOW_THIS = "$infostackshowthis"; //$NON-NLS-1$
+
+	/**
+	 * Number of milliseconds to wait for metadata.
+	 */
+	private static final String METADATA_ATTEMPTS_PERIOD = "$metadataattemptsperiod"; //$NON-NLS-1$
+
+	private static final String METADATA_NOT_AVAILABLE = "$metadatanotavailable"; //$NON-NLS-1$
+
+	/**
+	 * How many times we should try to get metadata.
+	 */
+	private static final String METADATA_ATTEMPTS = "$metadataattempts"; //$NON-NLS-1$
+
+	private static final String PLAYER_FULL_SUPPORT = "$playerfullsupport"; //$NON-NLS-1$
+
+	/**
+	 * Whether the "print" command will display attributes of members.
+	 */
+	public static final String DISPLAY_ATTRIBUTES = "$displayattributes"; //$NON-NLS-1$
+	
+	/* class's static init */
+	static
+	{
+        // set up for localizing messages
+        m_localizationManager.addLocalizer( new DebuggerLocalizer("flex.tools.debugger.cli.fdb.") ); //$NON-NLS-1$
+	}
+
+	public static void main(String[] args)
+	{
+		DebugCLI cli = new DebugCLI();
+
+		/* attach our 'main' input method and out/err*/
+		cli.m_err = System.err;
+		cli.m_out = System.out;
+
+		// get the default <application.home>/projects/frameworks/*/src entries into the source path
+		cli.initSourceDirectoriesList();
+
+		// a big of wrangling for our keyboard input stream since its special
+		cli.m_keyboardStream = new LineNumberReader(new InputStreamReader(System.in));
+		cli.pushStream(cli.m_keyboardStream);
+
+		/* iterate through the args list */
+		cli.processArgs(args);
+
+		/* figure out $HOME and the current directory */
+		String userHome = System.getProperty("user.home"); //$NON-NLS-1$
+		String userDir = System.getProperty("user.dir"); //$NON-NLS-1$
+
+		/*
+		 * If the current directory is not $HOME, and a .fdbinit file exists in the current directory,
+		 * then push it onto the stack of files to read.
+		 * 
+		 * Note, we want ./.fdbinit to be read AFTER $HOME/.fdbinit, but we push them in reverse
+		 * order, because they're going onto a stack.  If we push them in reverse order, then they
+		 * will be read in the correct order (last one pushed is the first one read).
+		 */
+		if (userDir != null && !userDir.equals(userHome))
+		{
+			try
+			{
+				FileReader sr = new FileReader(new File(userDir, ".fdbinit")); //$NON-NLS-1$
+				cli.pushStream( new LineNumberReader(sr) );
+			}
+			catch(FileNotFoundException fnf) {}
+		}
+
+		/*
+		 * If a .fdbinit file exists in the $HOME directory, then push it onto the stack of files
+		 * to read.
+		 * 
+		 * Note, we want ./.fdbinit to be read AFTER $HOME/.fdbinit, but we push them in reverse
+		 * order, because they're going onto a stack.  If we push them in reverse order, then they
+		 * will be read in the correct order (last one pushed is the first one read).
+		 */
+		if (userHome != null)
+		{
+			try
+			{
+				FileReader sr = new FileReader(new File(userHome, ".fdbinit")); //$NON-NLS-1$
+				cli.pushStream( new LineNumberReader(sr) );
+			}
+			catch(FileNotFoundException fnf) {}
+		}
+
+		cli.execute();
+	}
+
+	public DebugCLI()
+	{
+		m_fullnameOption = false;
+		m_faultTable = faultActionsBuilder.build();
+		m_exprCache = new ExpressionCache(this);
+		m_breakpoints = new Vector<BreakAction>();
+		m_watchpoints = new Vector<WatchAction>();
+		m_catchpoints = new Vector<CatchAction>();
+		m_displays = new ArrayList<DisplayAction>();
+		m_keyboardInput = new Vector<String>();
+		m_mruURI = null;
+		m_sourceDirectories = new LinkedList<String>();
+		
+		initProperties();
+		m_mainState = new DebugCLIIsolateState(this);
+		m_lastPromptIsolate = -1;
+		initIsolateState();
+	}
+
+	public static LocalizationManager getLocalizationManager() { return m_localizationManager; }
+	public Session				getSession()	{ return m_session; }
+	
+	public FileInfoCache getFileCache()	{ 
+			return m_fileInfo;
+	}
+
+	/**
+	 * Convert a module to class name.  This is used
+	 * by the ExpressionCache to find variables
+	 * that live at royale package scope.   That
+	 * is variables such as mx.core.Component.
+	 */
+	public String module2ClassName(int moduleId)
+	{
+		String pkg = null;
+		try
+		{
+			SourceFile file = m_fileInfo.getFile(moduleId);
+			pkg = file.getPackageName();
+		}
+		catch(Exception npe)
+		{
+			// didn't work ignore it.
+		}
+		return pkg;
+	}
+
+	LineNumberReader	popStream()						{ return m_readerStack.pop(); }
+	public void				pushStream(LineNumberReader r)  { m_readerStack.push(r); }
+	boolean				haveStreams()					{ return !m_readerStack.empty(); }
+
+	public void processArgs(String[] args)
+	{
+		for(int i=0; i<args.length; i++)
+		{
+			String arg = args[i];
+//			System.out.println("arg["+i+"]= '"+arg+"'");
+			if (arg.charAt(0) == '-')
+			{
+				// its an option
+				if (arg.equals("-unit")) // unit-testing mode //$NON-NLS-1$
+				{
+					System.setProperty("fdbunit", ""); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+				else if (arg.equals("-fullname") || arg.equals("-f")) //$NON-NLS-1$ //$NON-NLS-2$
+				{
+					m_fullnameOption = true; // emacs mode
+				}
+				else if (arg.equals("-cd")) //$NON-NLS-1$
+				{
+					// consume the path
+					if (i+1 < args.length)
+						m_cdPath = args[i++];
+				}
+				else if (arg.equals("-p")) //$NON-NLS-1$
+				{
+					// consume the port
+					if (i+1 < args.length)
+						m_connectPort = args[++i];
+				}
+				else
+				{
+					err("Unknown command-line argument: " + arg); //$NON-NLS-1$
+				}
+			}
+			else
+			{
+				// its a URI to run
+				StringReader sr = new StringReader("run "+arg+m_newline); //$NON-NLS-1$
+				pushStream( new LineNumberReader(sr) );
+			}
+		}
+	}
+
+	/**
+	 * Dispose of the current line and read the next from the current stream, if its an empty
+	 * line and we are console then repeat last line.
+	 */
+	protected String readLine() throws IOException
+	{
+		String line = null;
+		if (haveStreams())
+			line = m_in.readLine();
+		else
+			line = keyboardReadLine();
+
+		setCurrentLine(line);
+		return line;
+	}
+
+	/**
+	 * The reader portion of our keyboard input routine
+	 * Block until input arrives.
+	 */
+	synchronized String keyboardReadLine()
+	{
+		// enable a request then block on the queue
+		m_keyboardReadRequest = true;
+		try { wait(); } catch(InterruptedException ie) {}
+
+		// pull from the front of the queue
+		return m_keyboardInput.remove(0);
+	}
+
+	/**
+	 * A seperate thread collects our input so that we can
+	 * block in the doContinue on the main thread and then
+	 * allow the user to interrupt us via keyboard input
+	 * on this thread.
+	 *
+	 * We built the stupid thing in this manner, since readLine()
+	 * will block no matter what and if we 'quit' we can't
+	 * seem to kill this thread.  .close() doesn't work
+	 * and Thread.stop(), etc. all fail to do the job.
+	 *
+	 * Thus we needed to take a request response approach
+	 * so that we only block when requested to do so.
+	 */
+	public void run()
+	{
+		// while we have this stream
+		while(m_keyboardStream != null)
+		{
+			try
+			{
+				// only if someone is requesting us to read do we do so...
+				if (m_keyboardReadRequest)
+				{
+					// block on keyboard input and put it onto the end of the queue
+					String s = m_keyboardStream.readLine();
+					m_keyboardInput.add(s);
+
+					// fullfilled request, now notify blocking thread.
+					m_keyboardReadRequest = false;
+					synchronized(this) { notifyAll(); }
+				}
+				else
+					try { Thread.sleep(50); } catch(InterruptedException ie) {}
+			}
+			catch(IOException io)
+			{
+//				io.printStackTrace();
+			}
+		}
+	}
+
+	public void setCurrentLine(String s)
+	{
+		m_currentLine = s;
+		if (m_currentLine == null)
+			m_currentTokenizer = null;   /* eof */
+		else
+		{
+			m_currentLine = m_currentLine.trim();
+
+			/* if nothing provided on this command then pull our 'repeat' command  */
+			if (m_repeatLine != null && !haveStreams() && m_currentLine.length() == 0)
+				m_currentLine = m_repeatLine;
+
+			m_currentTokenizer = new StringTokenizer(m_currentLine, " \n\r\t"); //$NON-NLS-1$
+		}
+	}
+
+	/* Helpers for extracting tokens from the current line */
+	public boolean		hasMoreTokens()									{ return m_currentTokenizer.hasMoreTokens(); }
+	public String		nextToken()										{ m_currentToken = m_currentTokenizer.nextToken(); return m_currentToken; }
+	public int			nextIntToken() throws NumberFormatException		{ nextToken(); return Integer.parseInt(m_currentToken);	}
+	public long			nextLongToken() throws NumberFormatException	{ nextToken(); return Long.parseLong(m_currentToken);	}
+	public String		restOfLine()									{ return m_currentTokenizer.nextToken("").trim(); } //$NON-NLS-1$
+
+	public void execute()
+	{
+		/* dump console message */
+		displayStartMessage();
+		
+		/* now fire our keyboard input thread */
+		Thread t = new Thread(this, "Keyboard input"); //$NON-NLS-1$
+		t.start();
+
+		/* keep processing streams until we have no more to do */
+		while(haveStreams())
+		{
+			try
+			{
+				m_in = popStream();
+				process();
+			}
+			catch(EOFException eof)
+			{
+				; /* quite allright */
+			}
+			catch(IOException io)
+			{
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("exceptionMessage", io); //$NON-NLS-1$
+				err(getLocalizationManager().getLocalizedTextString("errorWhileProcessingFile", args)); //$NON-NLS-1$
+			}
+		}
+
+		/* we done kill everything */
+		exitSession();
+
+		// clear this thing, which also halts our other thread.
+		m_keyboardStream = null;
+	}
+
+	public PrintStream getOut() { return m_out; }
+
+	private void displayStartMessage()
+	{
+        String build = getLocalizationManager().getLocalizedTextString("defaultBuildName"); //$NON-NLS-1$
+
+        try
+        {
+            Properties p = new Properties();
+            p.load(this.getClass().getResourceAsStream("version.properties")); //$NON-NLS-1$
+            String buildString = p.getProperty("build"); //$NON-NLS-1$
+            if ((buildString != null) && (! buildString.equals(""))) //$NON-NLS-1$
+            {
+                build = buildString;
+            }
+        }
+        catch (Throwable t)
+        {
+            // ignore
+        }
+
+        Map<String, Object> aboutMap = new HashMap<String, Object>(); aboutMap.put("build", build); //$NON-NLS-1$
+        out(getLocalizationManager().getLocalizedTextString("about", aboutMap)); //$NON-NLS-1$
+		out(getLocalizationManager().getLocalizedTextString("copyright")); //$NON-NLS-1$
+	}
+
+	void displayPrompt()
+	{
+		m_out.print("(fdb) "); //$NON-NLS-1$
+	}
+
+	void displayCommandPrompt()
+	{
+		m_out.print(">"); //$NON-NLS-1$
+	}
+
+	// add the given character n times to sb
+	void repeat(StringBuilder sb, char c, int n)
+	{
+		while(n-- > 0)
+			sb.append(c);
+	}
+
+	// Prompt the user to respond to a yes or no type question
+	boolean yesNoQuery(String prompt) throws IOException
+	{
+		boolean result = false;
+		m_out.print(prompt);
+		m_out.print(getLocalizationManager().getLocalizedTextString("yesOrNoAppendedToAllQuestions")); //$NON-NLS-1$
+
+		String in = readLine();
+		if (in != null && in.equals(getLocalizationManager().getLocalizedTextString("singleCharacterUserTypesForYes"))) //$NON-NLS-1$
+			result = true;
+		else if (in != null && in.equals("escape")) //$NON-NLS-1$
+			throw new IllegalArgumentException("escape"); //$NON-NLS-1$
+		else
+			out(getLocalizationManager().getLocalizedTextString("yesNoQueryNotConfirmed")); //$NON-NLS-1$
+		return result;
+	}
+
+	public void err(String s)
+	{
+		// Doesn't make sense to send messages to stderr, because this is
+		// an interactive application; and besides that, sending a combination
+		// of interwoven but related messages to both stdout and stderr causes
+		// the output to be in the wrong order sometimes.
+		out(s);
+	}
+
+	public void out(String s)
+	{
+		if (s.length() > 0 && (s.charAt(s.length()-1) == '\n') )
+			m_out.print(s);
+		else
+			m_out.println(s);
+	}
+
+	static String uft()
+	{
+		Runtime rt = Runtime.getRuntime();
+		long free = rt.freeMemory(), total = rt.totalMemory(), used =  total - free;
+//		long max = rt.maxMemory();
+		java.text.NumberFormat nf = java.text.NumberFormat.getInstance() ;
+//        System.out.println("used: "+nf.format(used)+" free: "+nf.format(free)+" total: "+nf.format(total)+" max: "+nf.format(max));
+        return "Used "+nf.format(used)+" - free "+nf.format(free)+" - total "+nf.format(total); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+	/**
+	 * Add all properties that we know about
+	 */
+	void initProperties()
+	{
+		propertyPut(LIST_SIZE, 10);
+		propertyPut(LIST_LINE, 1);
+		propertyPut(LIST_MODULE, 1);  // default to module #1
+		propertyPut(LIST_WORKER, Isolate.DEFAULT_ID);
+		propertyPut(COLUMN_WIDTH, 70);
+		propertyPut(UPDATE_DELAY, 25);
+		propertyPut(HALT_TIMEOUT, 7000);
+		propertyPut(BPNUM, 0);				// set current breakpoint number as something bad
+		propertyPut(LAST_FRAME_DEPTH, 0);		// used to determine how much context information should be displayed
+		propertyPut(CURRENT_FRAME_DEPTH, 0);   // used to determine how much context information should be displayed
+		propertyPut(DISPLAY_FRAME_NUMBER, 0);  // houses the current frame we are viewing
+		propertyPut(FILE_LIST_WRAP, 999999);   // default 1 file name per line
+		propertyPut(NO_WAITING, 0);
+		propertyPut(INFO_STACK_SHOW_THIS, 1); // show this pointer for info stack
+	}
+
+	// getter/setter for properties; in the expression cache, so that they can be used in expressions!
+	public void propertyPut(String k, int v)  { m_exprCache.put(k,v); }
+	public int  propertyGet(String k)		  { return ((Integer)m_exprCache.get(k)).intValue(); }
+	public Set<String>  propertyKeys()		  { return m_exprCache.keySet(); }
+
+	/**
+	 * Process this reader until its done
+	 */
+	void process() throws IOException
+	{
+		boolean done = false;
+		while(!done)
+		{
+			try
+			{
+				/**
+				 * Now if we are in a session and that session is suspended then we go
+				 * into a state where we wait for some user interaction to get us out
+				 */
+				runningLoop();
+
+				/* if we are in the stdin then put out a prompt */
+				if (!haveStreams())
+					displayPrompt();
+
+				/* now read in the next line */
+				readLine();
+				if (m_currentLine == null)
+					break;
+
+				done = processLine();
+			}
+			catch(NoResponseException nre)
+			{
+				err(getLocalizationManager().getLocalizedTextString("noResponseException")); //$NON-NLS-1$
+			}
+			catch(NotSuspendedException nse)
+			{
+				err(getLocalizationManager().getLocalizedTextString("notSuspendedException")); //$NON-NLS-1$
+			}
+			catch(AmbiguousException ae)
+			{
+				// we already put up a warning for the user
+			}
+			catch(IllegalStateException ise)
+			{
+				err(getLocalizationManager().getLocalizedTextString("illegalStateException")); //$NON-NLS-1$
+			}
+			catch(IllegalMonitorStateException ime)
+			{
+				err(getLocalizationManager().getLocalizedTextString("illegalMonitorStateException")); //$NON-NLS-1$
+			}
+			catch(NoSuchElementException nse)
+			{
+				err(getLocalizationManager().getLocalizedTextString("noSuchElementException")); //$NON-NLS-1$
+			}
+			catch(NumberFormatException nfe)
+			{
+				err(getLocalizationManager().getLocalizedTextString("numberFormatException")); //$NON-NLS-1$
+			}
+			catch(SocketException se)
+			{
+				Map<String, Object> socketArgs = new HashMap<String, Object>();
+				socketArgs.put("message", se.getMessage()); //$NON-NLS-1$
+				err(getLocalizationManager().getLocalizedTextString("socketException", socketArgs)); //$NON-NLS-1$
+			}
+			catch(VersionException ve)
+			{
+				err(getLocalizationManager().getLocalizedTextString("versionException")); //$NON-NLS-1$
+			}
+			catch(NotConnectedException nce)
+			{
+				// handled by isConnectionLost()
+			}
+			catch(Exception e)
+			{
+				err(getLocalizationManager().getLocalizedTextString("unexpectedError")); //$NON-NLS-1$
+				err(getLocalizationManager().getLocalizedTextString("stackTraceFollows")); //$NON-NLS-1$
+				e.printStackTrace();
+			}
+
+			// check for a lost connection and if it is clean-up!
+			if (isConnectionLost())
+			{
+				try
+				{
+					dumpHaltState(false);
+				}
+				catch(PlayerDebugException pde)
+				{
+					err(getLocalizationManager().getLocalizedTextString("sessionEndedAbruptly")); //$NON-NLS-1$
+				}
+			}
+		}
+	}
+
+	// check if we have lost the connect without our help...
+	boolean isConnectionLost()
+	{
+		boolean lost = false;
+
+		if (m_session != null && !m_session.isConnected())
+			lost = true;
+
+		return lost;
+	}
+
+	boolean haveConnection()
+	{
+		boolean have = false;
+
+		if (m_session != null && m_session.isConnected())
+			have = true;
+
+		return have;
+	}
+
+	void doShow() throws AmbiguousException, PlayerDebugException
+	{
+		/* show without any args brings up help */
+		if (!hasMoreTokens())
+			out( getHelpTopic("show") ); //$NON-NLS-1$
+		else
+		{
+			/* otherwise we have a boatload of options */
+			String subCmdString = nextToken();
+			int subCmd = showCommandFor(subCmdString);
+			switch(subCmd)
+			{
+				case SHOW_NET_CMD:
+					doShowStats();
+					break;
+
+				case SHOW_FUNC_CMD:
+					doShowFuncs();
+					break;
+
+				case SHOW_URI_CMD:
+					doShowUri();
+					break;
+
+				case SHOW_PROPERTIES_CMD:
+					doShowProperties();
+					break;
+
+				case SHOW_FILES_CMD:
+					doShowFiles();
+					break;
+
+				case SHOW_BREAK_CMD:
+					doShowBreak();
+					break;
+
+				case SHOW_VAR_CMD:
+					doShowVariable();
+					break;
+
+				case SHOW_MEM_CMD:
+					doShowMemory();
+					break;
+
+				case SHOW_LOC_CMD:
+					doShowLocations();
+					break;
+
+				case SHOW_DIRS_CMD:
+					doShowDirectories();
+					break;
+
+				default:
+					doUnknown("show", subCmdString); //$NON-NLS-1$
+					break;
+			}
+		}
+	}
+
+	void doShowUri()
+	{
+		// dump the URI that the player has sent us
+		try
+		{
+			StringBuilder sb = new StringBuilder();
+			sb.append("URI = "); //$NON-NLS-1$
+			sb.append( m_session.getURI() );
+			out( sb.toString() );
+		}
+		catch(Exception e)
+		{
+			err(getLocalizationManager().getLocalizedTextString("noUriReceived")); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Dump the content of files in a raw format
+	 */
+	void doShowFiles()
+	{
+		try
+		{
+			StringBuilder sb = new StringBuilder();
+			for (Isolate isolate : m_session.getWorkers()) {
+			
+				Iterator itr = m_fileInfo.getAllFiles(isolate.getId());
+
+				while(itr.hasNext())
+				{
+					SourceFile m = (SourceFile) ((Map.Entry)itr.next()).getValue();
+
+					String name = m.getName();
+					int id = m.getId();
+					String path = m.getFullPath();
+
+					sb.append(id);
+					sb.append(' ');
+					sb.append(path);
+					sb.append(", "); //$NON-NLS-1$
+					sb.append(name);
+					sb.append(" ("); //$NON-NLS-1$
+					if (isolate.getId() == Isolate.DEFAULT_ID) {
+						sb.append(getLocalizationManager().getLocalizedTextString("mainThread")); //$NON-NLS-1$
+					}
+					else {
+						HashMap<String, Object> wArgs = new HashMap<String, Object>();
+						wArgs.put("worker", isolate.getId() - 1); //$NON-NLS-1$
+						sb.append(getLocalizationManager().getLocalizedTextString("inWorker", wArgs)); //$NON-NLS-1$
+					}
+					sb.append(")"); //$NON-NLS-1$
+					sb.append(m_newline);
+				}
+			}
+			out( sb.toString() );
+		}
+		catch(NullPointerException npe)
+		{
+			err(getLocalizationManager().getLocalizedTextString("noSourceFilesFound")); //$NON-NLS-1$
+		}
+	}
+
+	void doShowMemory()
+	{
+		out(uft());
+	}
+
+	void doShowLocations()
+	{
+		StringBuilder sb = new StringBuilder();
+		sb.append("Num Type           Disp Enb Address    What"+m_newline); //$NON-NLS-1$
+
+		// our list of breakpoints
+		int count = breakpointCount();
+		for(int i=0; i<count; i++)
+		{
+			BreakAction b = breakpointAt(i);
+			int num = b.getId();
+
+			FieldFormat.formatLong(sb, num, 3);
+			sb.append(" breakpoint     "); //$NON-NLS-1$
+
+			if (b.isAutoDisable())
+				sb.append("dis  "); //$NON-NLS-1$
+			else if (b.isAutoDelete())
+				sb.append("del  "); //$NON-NLS-1$
+			else
+				sb.append("keep "); //$NON-NLS-1$
+
+			if (b.isEnabled())
+				sb.append("y   "); //$NON-NLS-1$
+			else
+				sb.append("n   "); //$NON-NLS-1$
+
+			Iterator<Location> itr = b.getLocations().iterator();
+			while(itr.hasNext())
+			{
+				Location l = itr.next();
+				SourceFile file = l.getFile();
+				String funcName = (file == null)
+						? getLocalizationManager().getLocalizedTextString("unknownBreakpointLocation") //$NON-NLS-1$
+								: file.getFunctionNameForLine(m_session, l.getLine()) ;
+						int offset = adjustOffsetForUnitTests((file == null) ? 0 : file.getOffsetForLine(l.getLine()));
+
+						sb.append("0x"); //$NON-NLS-1$
+						FieldFormat.formatLongToHex(sb, offset, 8);
+						sb.append(' ');
+
+						if (funcName != null)
+						{
+							Map<String, Object> funcArgs = new HashMap<String, Object>();
+							funcArgs.put("functionName", funcName); //$NON-NLS-1$
+							sb.append(getLocalizationManager().getLocalizedTextString("inFunctionAt", funcArgs)); //$NON-NLS-1$
+						}
+
+						sb.append(file.getName());
+						if (file != null)
+						{
+							sb.append("#"); //$NON-NLS-1$
+							sb.append(file.getId());
+						}
+						sb.append(':');
+						sb.append(l.getLine());
+
+						try
+						{
+							SwfInfo info = m_fileInfo.swfForFile(file, l.getIsolateId());
+							Map<String, Object> swfArgs = new HashMap<String, Object>();
+							swfArgs.put("swf", FileInfoCache.shortNameOfSwf(info)); //$NON-NLS-1$
+							sb.append(getLocalizationManager().getLocalizedTextString("inSwf", swfArgs)); //$NON-NLS-1$
+							if (l.getIsolateId() == Isolate.DEFAULT_ID) {
+								sb.append(" ("); //$NON-NLS-1$
+								sb.append(getLocalizationManager().getLocalizedTextString("mainThread")); //$NON-NLS-1$
+								sb.append(")"); //$NON-NLS-1$
+							}
+							else {
+								swfArgs = new HashMap<String, Object>();
+								swfArgs.put("worker", l.getIsolateId() - 1); //$NON-NLS-1$
+								sb.append(" ("); //$NON-NLS-1$
+								sb.append(getLocalizationManager().getLocalizedTextString("inWorker", swfArgs)); //$NON-NLS-1$
+								sb.append(")"); //$NON-NLS-1$
+							}
+						}
+						catch(NullPointerException npe)
+						{
+							// can't find the swf
+							sb.append(getLocalizationManager().getLocalizedTextString("nonRestorable")); //$NON-NLS-1$
+						}
+						sb.append(m_newline);
+						if (itr.hasNext())
+							sb.append("                            "); //$NON-NLS-1$
+			}
+		}
+		out(sb.toString());
+	}
+
+	/**
+	 * When running unit tests, we want byte offsets into the file to
+	 * always be displayed as zero, so that the unit test expected
+	 * results will match up with the actual results.  This is just a
+	 * simple helper function that deals with that.
+	 */
+	private int adjustOffsetForUnitTests(int offset)
+	{
+		if (System.getProperty("fdbunit")==null) //$NON-NLS-1$
+			return offset;
+		else
+			return 0;
+	}
+
+	void doShowDirectories()
+	{
+		out(getLocalizationManager().getLocalizedTextString("sourceDirectoriesSearched")); //$NON-NLS-1$
+		Iterator<String> iter = m_sourceDirectories.iterator();
+		while (iter.hasNext())
+		{
+			String dir = iter.next();
+			out("  " + dir); //$NON-NLS-1$
+		}
+	}
+
+	void doHalt() throws SuspendedException, NotConnectedException, NoResponseException
+	{
+		out(getLocalizationManager().getLocalizedTextString("attemptingToSuspend")); //$NON-NLS-1$
+		IsolateSession session = m_session.getWorkerSession(getActiveIsolateId());
+		if (!session.isSuspended())
+			session.suspend();
+		if (session.isSuspended())
+			out(getLocalizationManager().getLocalizedTextString("playerStopped")); //$NON-NLS-1$
+		else
+			out(getLocalizationManager().getLocalizedTextString("playerRunning")); //$NON-NLS-1$
+	}
+
+	public void appendReason(StringBuilder sb, int reason)
+	{
+		switch(reason)
+		{
+			case SuspendReason.Unknown:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_Unknown")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.Breakpoint:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_HitBreakpoint")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.Watch:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_HitWatchpoint")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.Fault:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_ProgramThrewException")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.StopRequest:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_StopRequest")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.Step:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_ProgramFinishedStepping")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.HaltOpcode:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_HaltOpcode")); //$NON-NLS-1$
+				break;
+
+			case SuspendReason.ScriptLoaded:
+				sb.append(getLocalizationManager().getLocalizedTextString("suspendReason_ScriptHasLoadedIntoFlashPlayer")); //$NON-NLS-1$
+				break;
+		}
+	}
+
+	/**
+	 * The big ticket item, where all your questions are answered.
+	 *
+	 */
+	void doInfo() throws AmbiguousException, PlayerDebugException
+	{
+		/* info without any args brings up help */
+		if (!hasMoreTokens())
+			out( getHelpTopic("info") ); //$NON-NLS-1$
+		else
+		{
+			/* otherwise we have a boatload of options */
+			String subCmdString = nextToken();
+			int subCmd = infoCommandFor(subCmdString);
+			switch(subCmd)
+			{
+				case INFO_ARGS_CMD:
+					doInfoArgs();
+					break;
+
+				case INFO_BREAK_CMD:
+					doInfoBreak();
+					break;
+
+				case INFO_FILES_CMD:
+					doInfoFiles();
+					break;
+
+				case INFO_FUNCTIONS_CMD:
+					doInfoFuncs();
+					break;
+
+				case INFO_HANDLE_CMD:
+					doInfoHandle();
+					break;
+
+				case INFO_LOCALS_CMD:
+					doInfoLocals();
+					break;
+
+				case INFO_SCOPECHAIN_CMD:
+					doInfoScopeChain();
+					break;
+					
+				case INFO_SOURCES_CMD:
+					doInfoSources();
+					break;
+
+				case INFO_STACK_CMD:
+					doInfoStack();
+					break;
+
+				case INFO_VARIABLES_CMD:
+					doInfoVariables();
+					break;
+
+				case INFO_DISPLAY_CMD:
+					doInfoDisplay();
+					break;
+
+                case INFO_TARGETS_CMD:
+                    doInfoTargets();
+                    break;
+
+                case INFO_SWFS_CMD:
+                    doInfoSwfs();
+                    break;
+                    
+                case INFO_WORKERS_CMD:
+                	doInfoWorkers();
+                	break;
+
+				default:
+					doUnknown("info", subCmdString); //$NON-NLS-1$
+					break;
+			}
+		}
+	}
+	
+	void doInfoWorkers() throws NotConnectedException, NotSupportedException, NotSuspendedException, NoResponseException
+	{
+//		waitTilHalted();
+		Isolate[] isolates = m_session.getWorkers();
+		if (isolates == null || isolates.length == 0) {
+			out(getLocalizationManager().getLocalizedTextString("noWorkersRunning")); //$NON-NLS-1$
+			return;
+		}
+		StringBuilder sb = new StringBuilder();
+		for (Isolate t : isolates) {
+			String status = getLocalizationManager().getLocalizedTextString("workerRunning"); //$NON-NLS-1$
+			if (m_session.getWorkerSession(t.getId()).isSuspended()) {
+				status = getLocalizationManager().getLocalizedTextString("workerSuspended"); //$NON-NLS-1$
+			}
+			if (m_activeIsolate == t.getId()) {
+				status += " " + getLocalizationManager().getLocalizedTextString("workerSelected"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			if (t.getId() == Isolate.DEFAULT_ID) {
+				sb.append(getLocalizationManager().getLocalizedTextString("mainThread")); //$NON-NLS-1$
+				sb.append(" "); //$NON-NLS-1$
+				sb.append(Isolate.DEFAULT_ID - 1);
+			}
+			else {
+				HashMap<String, Object> workArgs = new HashMap<String, Object>();
+				workArgs.put("worker", (t.getId() - 1)); //$NON-NLS-1$
+				sb.append(getLocalizationManager().getLocalizedTextString("inWorker", workArgs)); //$NON-NLS-1$
+			}
+			sb.append(" - " + status + m_newline); //$NON-NLS-1$
+		}
+		out(sb.toString());
+	}
+
+
+	void doInfoStack() throws PlayerDebugException
+	{
+		waitTilHalted(m_activeIsolate);
+
+		StringBuilder sb = new StringBuilder();
+		Frame[] stack = m_session.getWorkerSession(m_activeIsolate).getFrames();
+		if (stack == null || stack.length == 0)
+			sb.append(getLocalizationManager().getLocalizedTextString("noStackAvailable")); //$NON-NLS-1$
+		else
+		{
+			boolean showThis = propertyGet(INFO_STACK_SHOW_THIS) == 1;
+			for(int i=0; i<stack.length; i++)
+			{
+				// keep spitting out frames until we can't
+				Frame frame = stack[i];
+				boolean valid = appendFrameInfo(sb, frame, i, showThis, false);
+				sb.append(m_newline);
+                if (!valid)
+                    break;
+			}
+		}
+
+		/* dump it out */
+		out(sb.toString());
+	}
+	
+	/**
+	 * Spit out frame information for a given frame number 
+	 */
+	boolean appendFrameInfo(StringBuilder sb, Frame ctx, int frameNumber, boolean showThis, boolean showFileId) throws PlayerDebugException
+	{
+		boolean validFrame = true;
+
+		// some formatting properties
+		int i = frameNumber;
+
+		Location loc = ctx.getLocation();
+		SourceFile file = loc.getFile();
+		int line = loc.getLine();
+		String name = (file == null) ? "<null>" : file.getName(); //$NON-NLS-1$
+		String sig = ctx.getCallSignature();
+		String func = extractFunctionName(sig);
+
+		// file == null or line < 0 appears to be a terminator for stack info
+		if (file == null && line < 0)
+        {
+            validFrame = false;
+        }
+        else
+		{
+			Variable[] var = ctx.getArguments(m_session);
+			Variable dis = ctx.getThis(m_session);
+			boolean displayArgs = (func != null) || (var != null);
+
+			sb.append('#');
+			FieldFormat.formatLong(sb, i, 3);
+			sb.append(' ');
+
+			if (showThis && dis != null)
+			{
+				ExpressionCache.appendVariable(sb, dis, ctx.getIsolateId());
+				sb.append("."); //$NON-NLS-1$
+			}
+
+			if (func != null)
+				sb.append(func);
+
+			if (displayArgs)
+			{
+				sb.append('(');
+				for (int j=0; j<var.length; j++)
+				{
+					Variable v = var[j];
+					sb.append(v.getName());
+					sb.append('=');
+					ExpressionCache.appendVariableValue(sb, v.getValue(), ctx.getIsolateId());
+					if ((j+1)<var.length)
+						sb.append(", "); //$NON-NLS-1$
+				}
+				sb.append(")"); //$NON-NLS-1$
+				sb.append(getLocalizationManager().getLocalizedTextString("atFilename")); //$NON-NLS-1$
+			}
+
+			sb.append(name);
+
+			// if this file is currently being filtered put the source file id after it
+			if (file != null && (showFileId || !m_fileInfo.inFileList(file)))
+			{
+				sb.append('#');
+				sb.append( file.getId() );
+
+			}
+			sb.append(':');
+			sb.append(line);
+		}
+        return validFrame;
+	}
+
+	/** extract the function name from a signature */
+	public static String extractFunctionName(String sig)
+	{ 
+		// strip everything after the leading ( 
+		int at = sig.indexOf('(');
+		if (at > -1)
+			sig = sig.substring(0, at);
+
+		// trim the leading [object_name::] since it doesn't seem to add much
+		if (sig != null && (at = sig.indexOf("::")) > -1) //$NON-NLS-1$
+			sig = sig.substring(at+2);
+
+		return sig;
+	}
+
+	void doInfoVariables() throws PlayerDebugException
+	{
+		waitTilHalted(m_activeIsolate);
+
+		// dump a set of locals
+		StringBuilder sb = new StringBuilder();
+
+		// use our expression cache formatting routine
+		try
+		{
+			Variable[] vars = m_session.getWorkerSession(m_activeIsolate).getVariableList();
+			for(int i=0; i<vars.length; i++)
+			{
+				Variable v = vars[i];
+
+				// all non-local and non-arg variables
+				if ( !v.isAttributeSet(VariableAttribute.IS_LOCAL) &&
+					 !v.isAttributeSet(VariableAttribute.IS_ARGUMENT) )
+				{
+					ExpressionCache.appendVariable(sb, vars[i], m_activeIsolate);
+					sb.append(m_newline);
+				}
+			}
+		}
+		catch(NullPointerException npe)
+		{
+			sb.append(getLocalizationManager().getLocalizedTextString("noVariables")); //$NON-NLS-1$
+		}
+
+		out(sb.toString());
+	}
+
+	void doInfoDisplay()
+	{
+		StringBuilder sb = new StringBuilder();
+		sb.append("Num Enb Expression"+m_newline); //$NON-NLS-1$
+
+		// our list of displays
+		int count = displayCount();
+		for(int i=0; i<count; i++)
+		{
+			DisplayAction b = displayAt(i);
+			int num = b.getId();
+			String exp = b.getContent();
+
+			sb.append(':');
+			FieldFormat.formatLong(sb, num, 3);
+
+			if (b.isEnabled())
+				sb.append(" y  "); //$NON-NLS-1$
+			else
+				sb.append(" n  "); //$NON-NLS-1$
+
+			sb.append(exp);
+			sb.append(m_newline);
+		}
+
+		out(sb.toString());
+	}
+
+	void doInfoArgs() throws PlayerDebugException
+	{
+		waitTilHalted(m_activeIsolate);
+
+		// dump a set of locals
+		StringBuilder sb = new StringBuilder();
+
+		// use our expression cache formatting routine
+		try
+		{
+			int num = propertyGet(DISPLAY_FRAME_NUMBER);
+			Frame[] frames = m_session.getWorkerSession(m_activeIsolate).getFrames();
+			Variable[] vars = frames[num].getArguments(m_session);
+			for(int i=0; i<vars.length; i++)
+			{
+				ExpressionCache.appendVariable(sb, vars[i], m_activeIsolate);
+				sb.append(m_newline);
+			}
+		}
+		catch(NullPointerException npe)
+		{
+			sb.append(getLocalizationManager().getLocalizedTextString("noArguments")); //$NON-NLS-1$
+		}
+        catch(ArrayIndexOutOfBoundsException aix)
+        {
+            sb.append(getLocalizationManager().getLocalizedTextString("notInValidFrame")); //$NON-NLS-1$
+        }
+
+		out(sb.toString());
+	}
+
+	void doInfoLocals() throws PlayerDebugException
+	{
+		waitTilHalted(m_activeIsolate);
+
+		// dump a set of locals
+		StringBuilder sb = new StringBuilder();
+
+		// use our expression cache formatting routine
+		try
+		{
+			// get the variables from the requested frame
+			int num = propertyGet(DISPLAY_FRAME_NUMBER);
+			Frame[] ar = m_session.getWorkerSession(m_activeIsolate).getFrames();
+			Frame ctx = ar[num];
+			Variable[] vars = ctx.getLocals(m_session);
+
+			for(int i=0; i<vars.length; i++)
+			{
+				Variable v = vars[i];
+
+				// see if variable is local
+				if ( v.isAttributeSet(VariableAttribute.IS_LOCAL) )
+				{
+					ExpressionCache.appendVariable(sb, v, m_activeIsolate);
+					sb.append(m_newline);
+				}
+			}
+		}
+		catch(NullPointerException npe)
+		{
+			sb.append(getLocalizationManager().getLocalizedTextString("noLocals")); //$NON-NLS-1$
+		}
+        catch(ArrayIndexOutOfBoundsException aix)
+        {
+            sb.append(getLocalizationManager().getLocalizedTextString("notInValidFrame")); //$NON-NLS-1$
+        }
+
+		out(sb.toString());
+	}
+
+	void doInfoScopeChain() throws PlayerDebugException
+	{
+		waitTilHalted(m_activeIsolate);
+
+		// dump the scope chain
+		StringBuilder sb = new StringBuilder();
+
+		// use our expression cache formatting routine
+		try
+		{
+			// get the scope chainfrom the requested frame
+			int num = propertyGet(DISPLAY_FRAME_NUMBER);
+			Frame[] ar = m_session.getWorkerSession(m_activeIsolate).getFrames();
+			Frame ctx = ar[num];
+			Variable[] scopes = ctx.getScopeChain(m_session);
+
+			for(int i=0; i<scopes.length; i++)
+			{
+				Variable scope = scopes[i];
+				ExpressionCache.appendVariable(sb, scope, m_activeIsolate);
+				sb.append(m_newline);
+			}
+		}
+		catch(NullPointerException npe)
+		{
+			sb.append(getLocalizationManager().getLocalizedTextString("noScopeChain")); //$NON-NLS-1$
+		}
+        catch(ArrayIndexOutOfBoundsException aix)
+        {
+            sb.append(getLocalizationManager().getLocalizedTextString("notInValidFrame")); //$NON-NLS-1$
+        }
+
+		out(sb.toString());
+	}
+	
+	void doInfoTargets()
+    {
+        if (!haveConnection())
+		{
+			out(getLocalizationManager().getLocalizedTextString("noActiveSession")); //$NON-NLS-1$
+			if (m_launchURI != null)
+			{
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("uri", m_launchURI); //$NON-NLS-1$
+				out(getLocalizationManager().getLocalizedTextString("runWillLaunchUri", args)); //$NON-NLS-1$
+			}
+		}
+        else
+		{
+			String uri = m_session.getURI();
+			if (uri == null || uri.length() < 1)
+				err(getLocalizationManager().getLocalizedTextString("targetUnknown")); //$NON-NLS-1$
+			else
+				out(uri);
+		}
+    }
+
+	/**
+	 * Dump some stats about our currently loaded swfs.
+	 */
+    void doInfoSwfs()
+    {
+		try
+		{
+			StringBuilder sb = new StringBuilder();
+			SwfInfo[] swfs = m_fileInfo.getSwfs(m_activeIsolate);
+			for(int i=0; i<swfs.length; i++)
+			{
+				SwfInfo e = swfs[i];
+				if (e == null || e.isUnloaded())
+					continue;
+
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("swfName", FileInfoCache.nameOfSwf(e)); //$NON-NLS-1$
+				args.put("size", NumberFormat.getInstance().format(e.getSwfSize())); //$NON-NLS-1$
+
+				try
+				{
+					int size = e.getSwdSize(m_session);
+
+					// our swd is loaded so let's comb through our
+					// list of scripts and locate the range of ids.
+					SourceFile[] files = e.getSourceList(m_session);
+					int max = Integer.MIN_VALUE;
+					int min = Integer.MAX_VALUE;
+					for(int j=0; j<files.length; j++)
+					{
+						SourceFile f = files[j];
+						int id = f.getId();
+						max = (id > max) ? id : max;
+						min = (id < min) ? id : min;
+					}
+
+					args.put("scriptCount", Integer.toString(e.getSourceCount(m_session))); //$NON-NLS-1$
+					args.put("min", Integer.toString(min)); //$NON-NLS-1$
+					args.put("max", Integer.toString(max)); //$NON-NLS-1$
+					args.put("plus", (e.isProcessingComplete()) ? "+" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+					args.put("moreInfo", (size==0) ? getLocalizationManager().getLocalizedTextString("remainingSourceBeingLoaded") : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				}
+				catch(InProgressException ipe)
+				{
+					sb.append(getLocalizationManager().getLocalizedTextString("debugInfoBeingLoaded")); //$NON-NLS-1$
+				}
+				args.put("url", e.getUrl()); //$NON-NLS-1$
+				sb.append(getLocalizationManager().getLocalizedTextString("swfInfo", args)); //$NON-NLS-1$
+				sb.append(m_newline);
+			}
+			out( sb.toString() );
+		}
+		catch(NullPointerException npe)
+		{
+			err(getLocalizationManager().getLocalizedTextString("noSWFs")); //$NON-NLS-1$
+		}
+    }
+
+	private static final int AUTHORED_FILE = 1;		// a file that was created by the end user, e.g. MyApp.mxml
+	private static final int FRAMEWORK_FILE = 2;	// a file from the Flex framework, e.g. mx.controls.Button.as, see FRAMEWORK_FILE_PACKAGES
+	private static final int SYNTHETIC_FILE = 3;	// e.g. "<set up XML utilities.1>"
+	private static final int ACTIONS_FILE = 4;		// e.g. "Actions for UIComponent: Frame 1 of Layer Name Layer 1"
+
+    private static final String[] FRAMEWORK_FILE_PACKAGES // package prefixes that we consider FRAMEWORK_FILEs
+        = new String[] {"mx","flex","text"}; // 'text' is Vellum (temporary) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+	/**
+	 * Given a file, guesses what type it is -- e.g. a file created by the end user,
+	 * or a file from the Flex framework, etc.
+	 */
+	private int getFileType(SourceFile sourceFile)
+	{
+		String name = sourceFile.getName();
+		String pkg = sourceFile.getPackageName();
+
+		if (name.startsWith("<") && name.endsWith(">") || name.equals("GeneratedLocale")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			return SYNTHETIC_FILE;
+
+        for (final String frameworkPkg : FRAMEWORK_FILE_PACKAGES )
+        {
+            // look for packages starting with pkgName
+            if (pkg.startsWith(frameworkPkg + '\\') ||
+                pkg.startsWith(frameworkPkg + '/')  ||
+                pkg.equals(frameworkPkg))
+            {
+                return FRAMEWORK_FILE;
+            }
+        }
+
+        if (name.startsWith("Actions for")) //$NON-NLS-1$
+            return ACTIONS_FILE;
+
+        return AUTHORED_FILE;
+}
+
+	void buildFileList(StringBuilder sb, boolean authoredFilesOnly)
+	{
+		SourceFile[] ar = m_fileInfo.getFileList(m_activeIsolate);
+		if (ar == null)
+		{
+			err(getLocalizationManager().getLocalizedTextString("noSourceFilesFound")); //$NON-NLS-1$
+			return;
+		}
+
+		Vector<String> authoredFiles = new Vector<String>();
+		Vector<String> frameworkFiles = new Vector<String>();
+		Vector<String> syntheticFiles = new Vector<String>();
+		Vector<String> actionsFiles = new Vector<String>();
+
+		for (int i = 0; i < ar.length; i++)
+		{
+ 			SourceFile m = ar[i];
+			int fileType = getFileType(m);
+			int id = m.getId();
+//			int fakeId = m_fileInfo.getFakeId(m);
+			String entry = m.getName() + "#" + id; //$NON-NLS-1$
+
+			switch (fileType)
+			{
+			case SYNTHETIC_FILE:
+				syntheticFiles.add(entry);
+				break;
+			case FRAMEWORK_FILE:
+				frameworkFiles.add(entry);
+				break;
+			case ACTIONS_FILE:
+				actionsFiles.add(entry);
+				break;
+			case AUTHORED_FILE:
+				authoredFiles.add(entry);
+				break;
+			}
+		}
+
+		int wrapAt = propertyGet(FILE_LIST_WRAP);
+
+		if (!authoredFilesOnly)
+		{
+			if (actionsFiles.size() > 0)
+			{
+				appendStrings(sb, actionsFiles, (actionsFiles.size() > wrapAt) );
+			}
+
+			if (frameworkFiles.size() > 0)
+			{
+				sb.append("---"+m_newline); //$NON-NLS-1$
+				appendStrings(sb, frameworkFiles, (frameworkFiles.size() > wrapAt) );
+			}
+
+			if (syntheticFiles.size() > 0)
+			{
+				sb.append("---"+m_newline); //$NON-NLS-1$
+				appendStrings(sb, syntheticFiles, (syntheticFiles.size() > wrapAt) );
+			}
+
+			sb.append("---"+m_newline); //$NON-NLS-1$
+		}
+
+		appendStrings(sb, authoredFiles, (authoredFiles.size() > wrapAt) );
+	}
+
+	/**
+	 * Dump a list of strings contained a vector
+	 * If flow is set then the strings are placed
+	 * on a single line and wrapped at $columnwidth
+	 */
+	void appendStrings(StringBuilder sb, Vector<String> v, boolean flow)
+	{
+		int count = v.size();
+		int width = 0;
+		int maxCol = propertyGet(COLUMN_WIDTH);
+
+		for (int i = 0; i < count; i++)
+		{
+			String s = v.get(i);
+			sb.append(s);
+
+			// too many of them, then wrap according to columnwidth
+			if (flow)
+			{
+				width += (s.length() + 2);
+				if (width >= maxCol)
+				{
+					sb.append(m_newline);
+					width = 0;
+				}
+				else
+					sb.append(", "); //$NON-NLS-1$
+			}
+			else
+				sb.append(m_newline);
+		}
+
+		// add a line feed for flow based
+		if (flow && width > 0)
+			sb.append(m_newline);
+	}
+
+	void doInfoFiles()
+	{
+		try
+		{
+			StringBuilder sb = new StringBuilder();
+            if (hasMoreTokens())
+            {
+                String arg = nextToken();
+                listFilesMatching(sb, arg);
+            }
+            else
+            {
+			    buildFileList(sb, false);
+            }
+			out(sb.toString());
+		}
+		catch(NullPointerException npe)
+		{
+			throw new IllegalStateException();
+		}
+	}
+
+    public void waitForMetaData() throws InProgressException
+    {
+        // perform a query to see if our metadata has loaded
+        int metadatatries = propertyGet(METADATA_ATTEMPTS);
+        int maxPerCall = 8;   // cap on how many attempt we make per call
+
+        int tries = Math.min(maxPerCall, metadatatries);
+        if (tries > 0)
+        {
+            int remain = metadatatries - tries; // assume all get used up
+
+            // perform the call and then update our remaining number of attempts
+            try
+            {
+                tries = waitForMetaData(tries);
+                remain = metadatatries - tries; // update our used count
+            }
+            catch(InProgressException ipe)
+            {
+                propertyPut(METADATA_ATTEMPTS, remain);
+				throw ipe;
+            }
+        }
+    }
+
+	/**
+	 * Wait for the API to load function names, which
+	 * exist in the form of external meta-data.
+	 *
+	 * Only do this tries times, then give up
+	 *
+	 * We wait period * attempts
+	 */
+	public int waitForMetaData(int attempts) throws InProgressException
+	{
+        int start = attempts;
+        int period = propertyGet(METADATA_ATTEMPTS_PERIOD);
+		while(attempts > 0)
+		{
+			// are we done yet?
+			if (isMetaDataAvailable())
+				break;
+			else
+				try { attempts--; Thread.sleep(period); } catch(InterruptedException ie) {}
+		}
+
+		// throw exception if still not ready
+		if (!isMetaDataAvailable())
+			throw new InProgressException();
+
+        return start-attempts;  // remaining number of tries
+	}
+
+	/**
+	 * Ask each swf if metadata processing is complete
+	 */
+	public boolean isMetaDataAvailable()
+	{
+		boolean allLoaded = true;
+		try 
+		{
+			// we need to ask the session since our fileinfocache will hide the exception
+			SwfInfo[] swfs = m_session.getSwfs();
+			for(int i=0; i<swfs.length; i++)
+			{
+				// check if our processing is finished.
+				SwfInfo swf = swfs[i];
+				if (swf != null && !swf.isProcessingComplete())
+				{
+					allLoaded = false;
+					break;
+				}
+			}
+		}
+		catch(NoResponseException nre)
+		{
+			// ok we still need to wait for player to read the swd in
+			allLoaded = false;
+		}
+
+		// count the number of times we checked and it wasn't there
+		if (!allLoaded)
+		{
+			int count = propertyGet(METADATA_NOT_AVAILABLE);
+			count++;
+			propertyPut(METADATA_NOT_AVAILABLE, count);
+		}
+		else
+		{
+			// success so we reset our attempt counter
+			propertyPut(METADATA_ATTEMPTS, METADATA_RETRIES);
+		}
+		return allLoaded;
+	}
+
+	void doInfoHandle()
+	{
+		if (hasMoreTokens())
+		{
+			// user specified a fault
+			String faultName = nextToken();
+
+			// make sure we know about this one
+		    if (!m_faultTable.exists(faultName))
+				err(getLocalizationManager().getLocalizedTextString("unrecognizedFault")); //$NON-NLS-1$
+			else
+				listFault(faultName);
+		}
+		else
+		{
+			// dump them all
+			StringBuilder sb = new StringBuilder();
+
+			appendFaultTitles(sb);
+
+			Object names[]  = m_faultTable.names();
+			Arrays.sort(names);
+
+			for(int i=0; i<names.length; i++)
+				appendFault(sb, (String)names[i]);
+
+			out ( sb.toString() );
+		}
+	}
+
+	void doInfoFuncs()
+	{
+		StringBuilder sb = new StringBuilder();
+
+		String arg = null;
+
+		// we take an optional single arg which specifies a module
+		try
+		{
+			// let's wait a bit for the background load to complete
+			waitForMetaData();
+
+			if (hasMoreTokens())
+			{
+				arg = nextToken();
+                int id = arg.equals(".") ? propertyGet(LIST_MODULE) : parseFileArg(-1, arg); //$NON-NLS-1$
+
+				SourceFile m = m_fileInfo.getFile(id, m_activeIsolate);
+				listFunctionsFor(sb, m);
+			}
+			else
+			{
+				SourceFile[] ar = m_fileInfo.getFileList(m_activeIsolate);
+				if (ar == null)
+					err(getLocalizationManager().getLocalizedTextString("noSourceFilesFound")); //$NON-NLS-1$
+				else
+                {
+                    for(int i = 0; ar != null && i < ar.length; i++)
+                    {
+                        SourceFile m = ar[i];
+                        listFunctionsFor(sb, m);
+                    }
+                }
+			}
+
+			out(sb.toString());
+		}
+		catch(NullPointerException npe)
+		{
+			err(getLocalizationManager().getLocalizedTextString("noFunctionsFound")); //$NON-NLS-1$
+		}
+		catch(ParseException pe)
+		{
+			err(pe.getMessage());
+		}
+		catch(NoMatchException nme)
+		{
+			err(nme.getMessage());
+		}
+		catch(AmbiguousException ae)
+		{
+			err(ae.getMessage());
+		}
+		catch(InProgressException ipe)
+		{
+		    err(getLocalizationManager().getLocalizedTextString("functionListBeingPrepared")); //$NON-NLS-1$
+		}
+	}
+
+	void listFunctionsFor(StringBuilder sb, SourceFile m)
+	{
+		String[] names = m.getFunctionNames(m_session);
+		if (names == null)
+			return;
+
+		Arrays.sort(names);
+
+		Map<String, Object> args = new HashMap<String, Object>();
+		args.put("sourceFile", m.getName() + "#" + m.getId()); //$NON-NLS-1$ //$NON-NLS-2$
+		sb.append(getLocalizationManager().getLocalizedTextString("functionsInSourceFile", args)); //$NON-NLS-1$
+		sb.append(m_newline);
+
+        for (int j = 0; j < names.length; j++)
+		{
+			String fname = names[j];
+			sb.append(' ');
+			sb.append(fname);
+			sb.append(' ');
+			sb.append(m.getLineForFunctionName(m_session, fname));
+			sb.append(m_newline);
+		}
+	}
+
+    void listFilesMatching(StringBuilder sb, String match)
+    {
+        SourceFile[] sourceFiles = m_fileInfo.getFiles(match);
+
+        for (int j = 0; j < sourceFiles.length; j++)
+        {
+            SourceFile sourceFile = sourceFiles[j];
+            sb.append(sourceFile.getName());
+			sb.append('#');
+			sb.append(sourceFile.getId());
+			sb.append(m_newline);
+        }
+    }
+
+    void doInfoSources()
+	{
+		try
+		{
+			StringBuilder sb = new StringBuilder();
+			buildFileList(sb, true);
+			out(sb.toString());
+		}
+		catch(NullPointerException npe)
+		{
+			throw new IllegalStateException();
+		}
+	}
+
+	void doInfoBreak() throws NotConnectedException
+	{
+//		waitTilHalted();
+
+		StringBuilder sb = new StringBuilder();
+		sb.append("Num Type           Disp Enb Address    What"+m_newline); //$NON-NLS-1$
+
+		int count = breakpointCount();
+		for(int i=0; i<count; i++)
+		{
+			BreakAction b = breakpointAt(i);
+			int status = b.getStatus();
+			boolean isResolved = (status == BreakAction.RESOLVED);
+			Location l = b.getLocation();
+			SourceFile file = (l != null) ? l.getFile() : null;
+			String funcName = (file == null) ? null : file.getFunctionNameForLine(m_session, l.getLine()) ;
+			boolean singleSwf = b.isSingleSwf();
+			int cmdCount = b.getCommandCount();
+			int hits = b.getHits();
+			String cond = b.getConditionString();
+			boolean silent = b.isSilent();
+			int offset = adjustOffsetForUnitTests((file == null) ? 0 : file.getOffsetForLine(l.getLine()));
+
+			int num = b.getId();
+			FieldFormat.formatLong(sb, num, 3);
+			sb.append(" breakpoint     "); //$NON-NLS-1$
+
+			if (b.isAutoDisable())
+				sb.append("dis  "); //$NON-NLS-1$
+			else if (b.isAutoDelete())
+				sb.append("del  "); //$NON-NLS-1$
+			else
+				sb.append("keep "); //$NON-NLS-1$
+
+			if (b.isEnabled())
+				sb.append("y   "); //$NON-NLS-1$
+			else
+				sb.append("n   "); //$NON-NLS-1$
+
+			sb.append("0x"); //$NON-NLS-1$
+			FieldFormat.formatLongToHex(sb, offset, 8);
+			sb.append(' ');
+
+			if (funcName != null)
+			{
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("functionName", funcName); //$NON-NLS-1$
+				sb.append(getLocalizationManager().getLocalizedTextString("inFunctionAt", args)); //$NON-NLS-1$
+			}
+
+			if (file != null)
+			{
+				sb.append(file.getName());
+				if (isResolved && singleSwf)
+				{
+					sb.append("#"); //$NON-NLS-1$
+					sb.append(file.getId());
+				}
+				sb.append(':');
+				sb.append(l.getLine());
+			}
+			else
+			{
+				String expr = b.getBreakpointExpression();
+				if (expr != null)
+					sb.append(expr);
+			}
+
+			switch (status)
+			{
+			case BreakAction.UNRESOLVED:
+				sb.append(getLocalizationManager().getLocalizedTextString("breakpointNotYetResolved")); //$NON-NLS-1$
+				break;
+			case BreakAction.AMBIGUOUS:
+				sb.append(getLocalizationManager().getLocalizedTextString("breakpointAmbiguous")); //$NON-NLS-1$
+				break;
+			case BreakAction.NOCODE:
+				sb.append(getLocalizationManager().getLocalizedTextString("breakpointNoCode")); //$NON-NLS-1$
+				break;
+			}
+
+			// if a single swf break action then append more info
+			if (singleSwf && isResolved)
+			{
+				try
+				{
+					SwfInfo info = m_fileInfo.swfForFile(file, l.getIsolateId());
+					Map<String, Object> swfArgs = new HashMap<String, Object>();
+					swfArgs.put("swf", FileInfoCache.nameOfSwf(info)); //$NON-NLS-1$
+					sb.append(getLocalizationManager().getLocalizedTextString("inSwf", swfArgs)); //$NON-NLS-1$
+				}
+				catch(NullPointerException npe)
+				{
+					// can't find the swf
+					sb.append(getLocalizationManager().getLocalizedTextString("nonRestorable")); //$NON-NLS-1$
+				}
+			}
+			sb.append(m_newline);
+
+			final String INDENT = "        "; //$NON-NLS-1$
+
+			// state our condition if we have one
+			if (cond != null && cond.length() > 0)
+			{
+				sb.append(INDENT);
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("breakpointCondition", cond ); //$NON-NLS-1$
+				sb.append(getLocalizationManager().getLocalizedTextString(getLocalizationManager().getLocalizedTextString("stopOnlyIfConditionMet", args))); //$NON-NLS-1$
+				sb.append(m_newline);
+			}
+
+			// now if its been hit, lets state the fact
+			if (hits > 0)
+			{
+				sb.append(INDENT);
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("count", Integer.toString(hits)); //$NON-NLS-1$
+				sb.append(getLocalizationManager().getLocalizedTextString("breakpointAlreadyHit", args)); //$NON-NLS-1$
+				sb.append(m_newline);
+			}
+
+			// silent?
+			if (silent)
+			{
+				sb.append(INDENT);
+				sb.append(getLocalizationManager().getLocalizedTextString("silentBreakpoint")+m_newline); //$NON-NLS-1$
+			}
+
+			// now if any commands are trailing then we pump them out
+			for(int j=0; j<cmdCount; j++)
+			{
+				sb.append(INDENT);
+				sb.append(b.commandAt(j));
+				sb.append(m_newline);
+			}
+		}
+//		}
+
+		int wcount = watchpointCount();
+		for(int k = 0; k < wcount; k++)
+		{
+			WatchAction b = watchpointAt(k);
+			int id = b.getId();
+			FieldFormat.formatLong(sb, id, 4);
+
+			int flags = b.getKind();
+			switch(flags)
+			{
+				case WatchKind.READ:
+					sb.append("rd watchpoint  "); //$NON-NLS-1$
+					break;
+				case WatchKind.WRITE:
+					sb.append("wr watchpoint  "); //$NON-NLS-1$
+					break;
+				case WatchKind.READWRITE:
+				default:
+					sb.append("watchpoint     "); //$NON-NLS-1$
+					break;
+			}
+
+			sb.append("keep "); //$NON-NLS-1$
+			sb.append("y   "); //$NON-NLS-1$
+			sb.append("           "); //$NON-NLS-1$
+			sb.append(b.getExpr());
+			sb.append(m_newline);
+		}
+
+		int ccount = catchpointCount();
+		for (int k = 0; k < ccount; k++)
+		{
+			CatchAction c = catchpointAt(k);
+			int id = c.getId();
+			FieldFormat.formatLong(sb, id, 4);
+
+			String typeToCatch = c.getTypeToCatch();
+			if (typeToCatch == null)
+				typeToCatch = "*"; //$NON-NLS-1$
+
+			sb.append("catch          "); //$NON-NLS-1$
+			sb.append("keep "); //$NON-NLS-1$
+			sb.append("y   "); //$NON-NLS-1$
+			sb.append("           "); //$NON-NLS-1$
+			sb.append(typeToCatch);
+			sb.append(m_newline);
+		}
+
+		out(sb.toString());
+	}
+
+	/**
+	 * Dump out the state of the execution, either the fact we are running
+	 * or the breakpoint we hit.
+	 */
+	void dumpHaltState(boolean postStep) throws NotConnectedException
+	{
+		// spit out any event output, if we are to resume after a fault and we're not stepping then we're done.
+		processEvents();
+//		System.out.println("processEvents = "+m_requestResume);
+
+		//if (m_requestResume && !postStep)
+		if (hasAnyPendingResumes() != -1 && !postStep)
+			return;
+
+		if (!m_session.isConnected())
+		{
+			// session is kaput
+			out(getLocalizationManager().getLocalizedTextString("sessionTerminated")); //$NON-NLS-1$
+			exitSession();
+		}
+		else
+		{
+			if (hasAnythingSuspended())
+			{
+				// capture our break location / information
+				StringBuilder sbLine = new StringBuilder();
+				dumpBreakLine(postStep, sbLine);
+
+				// Process our breakpoints.
+				// Since we can have conditional breakpoints, which the
+				// player always breaks for, but we may not want to, the variable
+				// m_requestResume may be set after this call.  Additionally,
+				// silent may be set for one of two reasons; 1) m_requestResume
+				// was set to true in the call or one or more breakpoints that
+				// hit contained the keyword silent in their command list.
+				//
+				StringBuilder sbBreak = new StringBuilder();
+				boolean silent = processBreak(postStep, sbBreak, m_activeIsolate);
+
+				StringBuilder sb = new StringBuilder();
+				if (silent)
+				{
+					// silent means we only spit out our current location
+					dumpBreakLine(postStep, sb);
+				}
+				else
+				{
+					// not silent means we append things like normal
+					sb.append(sbLine);
+					if (sbLine.length() > 0 && sbLine.charAt(sbLine.length()-1) != '\n')
+						sb.append(m_newline);
+					sb.append(sbBreak);
+				}
+
+				// output whatever was generated 
+				if (sb.length() > 0)
+					out( sb.toString() );
+
+//				System.out.println("processbreak = "+m_requestResume+",silent="+silent+",reason="+m_session.suspendReason());
+			}
+			else
+			{
+				// very bad, set stepping so that we don't trigger a continue on a breakpoint or fault
+				out(getLocalizationManager().getLocalizedTextString("playerDidNotStop")); //$NON-NLS-1$
+			}
+		}
+	}
+
+	Location getCurrentLocation()
+	{
+		return getCurrentLocationIsolate(Isolate.DEFAULT_ID);
+	}
+	
+	Location getCurrentLocationIsolate(int isolateId)
+	{
+		Location where = null;
+		try
+		{
+			Frame[] ar = m_session.getWorkerSession(isolateId).getFrames();
+			propertyPut(CURRENT_FRAME_DEPTH, (ar.length > 0) ? ar.length : 0);
+			where = ( (ar.length > 0) ? ar[0].getLocation() : null);
+		}
+		catch(PlayerDebugException pde)
+		{
+			// where == null
+		}
+		return where;
+	}
+
+	void dumpBreakLine(boolean postStep, StringBuilder sb) throws NotConnectedException
+	{
+		int bp = -1;
+		String name = getLocalizationManager().getLocalizedTextString("unknownFilename"); //$NON-NLS-1$
+		int line = -1;
+
+		// clear our current frame display
+		propertyPut(DISPLAY_FRAME_NUMBER, 0);
+		
+		int targetIsolate = getLastStoppedIsolate();
+		boolean activeIsolateChanged = (m_activeIsolate != targetIsolate);
+		m_activeIsolate = targetIsolate;
+		propertyPut(LIST_WORKER, targetIsolate);
+
+		/* dump a context line to the console */
+		Location l = getCurrentLocationIsolate(targetIsolate);
+
+		// figure out why we stopped
+		int reason = SuspendReason.Unknown;
+		try { reason = m_session.getWorkerSession(targetIsolate).suspendReason(); } catch(PlayerDebugException pde) {}
+
+		// then see if it because of a swfloaded event
+		if( reason == SuspendReason.ScriptLoaded)
+		{
+            // since the player takes a long time to provide swf/swd, try 80 * 250ms = ~20s
+            if (propertyGet(METADATA_ATTEMPTS) > 0)
+			    try { waitForMetaData(80); } catch(InProgressException ipe) { }
+
+            m_fileInfo.setDirty();
+            m_fileInfo.getSwfsIsolate(targetIsolate);
+            //propertyPut(LIST_MODULE, m_fileInfo.getFakeId(m_fileInfo.getFile(1, targetIsolate)));
+			processEvents();
+            propagateBreakpoints(targetIsolate);
+            propertyPut(LIST_LINE, 1);
+            propertyPut(LIST_WORKER, targetIsolate);
+            propertyPut(LIST_MODULE, 1);
+            sb.append(getLocalizationManager().getLocalizedTextString("additionalCodeLoaded")); //$NON-NLS-1$
+            if ( activeIsolateChanged ) {
+            	sb.append(m_newline + getLocalizationManager().getLocalizedTextString("workerChanged")+ " " + (targetIsolate - 1) + m_newline); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+            sb.append(m_newline);
+
+			if (resolveBreakpoints(sb))
+				sb.append(getLocalizationManager().getLocalizedTextString("setAdditionalBreakpoints")+m_newline); //$NON-NLS-1$
+			else
+				sb.append(getLocalizationManager().getLocalizedTextString("fixBreakpoints")+m_newline); //$NON-NLS-1$
+			
+			setPromptState(InitialPromptState.SHOWN_ONCE, targetIsolate);
+		}
+		else if ( l == null || l.getFile() == null )
+		{
+			
+			if ( activeIsolateChanged ) {
+				sb.append(m_newline + getLocalizationManager().getLocalizedTextString("workerChanged")+ " " + (targetIsolate - 1) + m_newline); 
+			}
+			
+			// no idea where we are ?!?
+			propertyPut(LAST_FRAME_DEPTH, 0);
+			sb.append(getLocalizationManager().getLocalizedTextString("executionHalted")); //$NON-NLS-1$
+			sb.append(' ');
+
+			/** disable this line (and enable the one after) if implementation Extensions are not provided */
+			appendBreakInfo(sb, m_activeIsolate);
+			//sb.append("unknown location");
+		}
+		else
+		{
+			if ( activeIsolateChanged ) {
+				sb.append(m_newline + getLocalizationManager().getLocalizedTextString("workerChanged")+ " " + (targetIsolate - 1) + m_newline); 
+			}
+			
+			SourceFile file = l.getFile();
+			name = file.getName();
+			line = l.getLine();
+			String funcName = file.getFunctionNameForLine(m_session, line) ;
+
+			// where were we last time
+			int lastModule = propertyGet(LIST_MODULE);
+			int lastDepth = propertyGet(LAST_FRAME_DEPTH);
+
+			int thisModule = file.getId();
+			int thisDepth = propertyGet(CURRENT_FRAME_DEPTH);  // triggered via getCurrentLocation()
+
+			// mark where we stopped
+			propertyPut(LAST_FRAME_DEPTH, thisDepth);
+
+			// if we have changed our context or we are not spitting out source then dump our location
+			if (!postStep || lastModule != thisModule || lastDepth != thisDepth )
+			{
+				// is it a fault?
+				String reasonForHalting;
+				if ( reason == SuspendReason.Fault || reason == SuspendReason.StopRequest)
+				{
+					StringBuilder s = new StringBuilder();
+					appendReason(s, reason);
+					reasonForHalting = s.toString();
+				}
+				// if its a breakpoint add that information
+				else if ( (bp = enabledBreakpointIndexOf(l)) > -1 )
+				{
+					Map<String, Object> args = new HashMap<String, Object>();
+					args.put("breakpointNumber", Integer.toString(breakpointAt(bp).getId())); //$NON-NLS-1$
+					reasonForHalting = getLocalizationManager().getLocalizedTextString("hitBreakpoint", args); //$NON-NLS-1$
+				}
+				else
+				{
+					reasonForHalting = getLocalizationManager().getLocalizedTextString("executionHalted"); //$NON-NLS-1$
+				}
+
+				Map<String, Object> args = new HashMap<String, Object>();
+				args.put("reasonForHalting", reasonForHalting); //$NON-NLS-1$
+				args.put("fileAndLine", name + ':' + line); //$NON-NLS-1$
+				String formatString;
+				if (funcName != null)
+				{
+					args.put("functionName", funcName); //$NON-NLS-1$
+					formatString = "haltedInFunction"; //$NON-NLS-1$
+				}
+				else
+				{
+					formatString = "haltedInFile"; //$NON-NLS-1$
+				}
+				sb.append(getLocalizationManager().getLocalizedTextString(formatString, args));
+
+				if (!m_fullnameOption) 
+					sb.append(m_newline);				
+			}
+
+            // set current listing poistion and emit emacs trigger
+            setListingPosition(thisModule, line, targetIsolate);
+
+			// dump our source line if not in emacs mode
+			if (!m_fullnameOption)
+				appendSource(sb, file.getId(), line, file.getLine(line), false);
+		}
+	}
+
+	private int getLastStoppedIsolate() {
+	int targetIsolate = Isolate.DEFAULT_ID;
+		
+		if (m_breakIsolates.size() > 0) {
+			targetIsolate = m_breakIsolates.get(m_breakIsolates.size() - 1);
+		}
+		return targetIsolate;
+	}
+
+	void appendFullnamePosition(StringBuilder sb, SourceFile file, int lineNbr)
+	{
+        // fullname option means we dump 'path:line:col?:offset', which is used for emacs !
+		String name = file.getFullPath();
+		if (name.startsWith("file:/")) //$NON-NLS-1$
+			name = name.substring(6);
+
+		// Ctrl-Z Ctrl-Z
+		sb.append('\u001a');
+		sb.append('\u001a');
+
+		sb.append(name);
+		sb.append(':');
+		sb.append(lineNbr);
+		sb.append(':');
+		sb.append('0');
+		sb.append(':');
+		sb.append("beg"); //$NON-NLS-1$
+		sb.append(':');
+		sb.append('0');
+	}
+
+	// pretty print a trace statement to the console
+	void dumpTraceLine(String s)
+	{
+		StringBuilder sb = new StringBuilder();
+		sb.append("[trace] "); //$NON-NLS-1$
+		sb.append(s);
+		out(sb.toString());
+	}
+
+	// pretty print a fault statement to the console
+	void dumpFaultLine(FaultEvent e)
+	{
+		StringBuilder sb = new StringBuilder();
+
+		// use a slightly different format for ConsoleErrorFaults
+		if (e instanceof ConsoleErrorFault)
+		{
+			sb.append(getLocalizationManager().getLocalizedTextString("linePrefixWhenDisplayingConsoleError")); //$NON-NLS-1$
+			sb.append(' ');
+			sb.append(e.information);
+		}
+		else
+		{
+			String name = e.name();
+			sb.append(getLocalizationManager().getLocalizedTextString("linePrefixWhenDisplayingFault")); //$NON-NLS-1$
+			sb.append(' ');
+			sb.append(name);
+			if (e.information != null && e.information.length() > 0)
+			{
+				sb.append(getLocalizationManager().getLocalizedTextString("informationAboutFault")); //$NON-NLS-1$
+				sb.append(e.information);
+			}
+		}
+		out( sb.toString() );
+	}
+
+    /**
+     * Called when a swf has been loaded by the player
+     * @param e event documenting the load
+     */
+    void handleSwfLoadedEvent(SwfLoadedEvent e)
+    {
+        // first we dump out a message that displays we have loaded a swf
+        dumpSwfLoadedLine(e);
+    }
+
+	// pretty print a SwfLoaded statement to the console
+	void dumpSwfLoadedLine(SwfLoadedEvent e)
+	{
+		// now rip off any trailing ? options
+		int at = e.path.lastIndexOf('?');
+		String name = (at > -1) ? e.path.substring(0, at) : e.path;
+
+		StringBuilder sb = new StringBuilder();
+		sb.append(getLocalizationManager().getLocalizedTextString("linePrefixWhenSwfLoaded")); //$NON-NLS-1$
+		sb.append(' ');
+		sb.append(name);
+		sb.append(" - "); //$NON-NLS-1$
+
+		Map<String, Object> args = new HashMap<String, Object>();
+		args.put("size", NumberFormat.getInstance().format(e.swfSize)); //$NON-NLS-1$
+		sb.append(getLocalizationManager().getLocalizedTextString("sizeAfterDecompression", args)); //$NON-NLS-1$
+		out(sb.toString());
+	}
+
+    /**
+     * Propagate current breakpoints to the newly loaded swf.
+     */
+    void propagateBreakpoints(int isolateId) throws NotConnectedException
+    {
+		// get the newly added swf, which lands at the end list
+		SwfInfo[] swfs = m_fileInfo.getSwfsIsolate(isolateId);
+		SwfInfo swf = (swfs.length > 1) ? swfs[swfs.length-1] : null;
+
+		// now walk through all breakpoints propagating the 
+		// the break for each source and line number we
+		// find in the new swf
+		int size = m_breakpoints.size();
+		for (int i = 0; (swf != null) && i < size; i++)
+		{
+			// dont do this for single swf breakpoints
+			BreakAction bp = breakpointAt(i);
+			if (bp.isSingleSwf())
+				continue;
+			if (bp.getStatus() != BreakAction.RESOLVED)
+				continue;
+
+			try
+			{
+				Location l = bp.getLocation();
+				int line = l.getLine();
+				SourceFile f = l.getFile();
+				Location newLoc = findAndEnableBreak(swf, f, line);
+				if (newLoc != null)
+					bp.addLocation(newLoc);
+			}
+			catch(InProgressException ipe)
+			{
+				if (breakpointCount() > 0)
+				{
+					Map<String, Object> args = new HashMap<String, Object>();
+					args.put("breakpointNumber", Integer.toString(bp.getId())); //$NON-NLS-1$
+					out(getLocalizationManager().getLocalizedTextString("breakpointNotPropagated", args)); //$NON-NLS-1$
+				}
+			}
+		}
+    }
+
+	/**
+	 * Perform the tasks need for when a swf is unloaded
+	 * the player
+	 */
+	void handleSwfUnloadedEvent(SwfUnloadedEvent e)
+	{
+		// print out the notification
+		dumpSwfUnloadedLine(e);
+	}
+
+	// pretty print a SwfUnloaded statement to the console
+	void dumpSwfUnloadedLine(SwfUnloadedEvent e)
+	{
+		// now rip off any trailing ? options
+		int at = e.path.lastIndexOf('?');
+		String name = (at > -1) ? e.path.substring(0, at) : e.path;
+
+		StringBuilder sb = new StringBuilder();
+		sb.append(getLocalizationManager().getLocalizedTextString("linePrefixWhenSwfUnloaded")); //$NON-NLS-1$
+		sb.append(' ');
+		sb.append(name);
+		out(sb.toString());
+	}
+
+	void doContinue() throws NotConnectedException
+	{
+		//int stoppedIsolate = getLastStoppedIsolate();
+		int stoppedIsolate = m_activeIsolate;
+		waitTilHalted(stoppedIsolate);
+
+		// this will trigger a resume when we get back to the main loop
+		//m_requestResume = true;
+		setRequestResume(true, stoppedIsolate);
+		m_repeatLine = m_currentLine;
+	}
+	
+	boolean hasAnythingSuspended() throws NotConnectedException {
+		boolean hasAnythingSuspended = false;
+		for (Integer id : m_breakIsolates) {
+			if (m_session.getWorkerSession(id).isSuspended()) {
+				hasAnythingSuspended = true;
+				break;
+			}
+		}
+		return hasAnythingSuspended;
+	}
+	
+	int hasAnyPendingResumes() throws NotConnectedException {
+		int rid = -1;
+		if (m_mainState.m_requestResume)
+			return Isolate.DEFAULT_ID;
+		for (Integer id : m_breakIsolates) {
+			if (getIsolateState(id).m_requestResume) {
+				rid = id;
+				break;
+			}
+		}
+		return rid;
+	}
+	
+	/**
+	 * Returns the first isolate's id for which we need to keep showing prompts.
+	 * 
+	 * @return The isolate id
+	 * @throws NotConnectedException
+	 */
+	int hasPendingInitialPrompts() throws NotConnectedException {
+		int rid = -1;
+		for (Integer id : m_breakIsolates) {
+			if (getPromptState(id) != InitialPromptState.DONE) {
+				rid = id;
+				break;
+			}
+		}
+		return rid;
+	}
+
+	/**
+	 * Our main loop when the player is off running
+	 */
+	public void runningLoop() throws NoResponseException, NotConnectedException
+	{
+		int update = propertyGet(UPDATE_DELAY);
+		boolean nowait = (propertyGet(NO_WAITING) == 1) ? true : false;  // DEBUG ONLY; do not document
+		boolean stop = false;
+		boolean noConnection = !haveConnection();
+		boolean hasAnythingSuspended = false;
+		int targetIsolate = Isolate.DEFAULT_ID;
+		if (!noConnection) {
+			hasAnythingSuspended = hasAnythingSuspended();
+		}
+
+		if (hasAnythingSuspended) {
+			if (m_breakIsolates.size() > 0) {
+				targetIsolate = m_breakIsolates.get(m_breakIsolates.size() - 1);
+			}
+		}
+		// not there, not connected or already halted and no pending resume requests => we are done
+		//if (noConnection || (hasAnythingSuspended && !m_requestResume) )
+		if (noConnection || (hasAnythingSuspended && hasAnyPendingResumes() == -1) )
+		{
+			processEvents();
+			stop = true;
+			
+			if(!noConnection) {
+				/** At this point, some isolate is in suspended state and will be until a resume 
+				 *  is requested via the prompt. We thus check for any pending prompts to be displayed 
+				 *  for freshly loaded swfs. If any, we switch to that worker and prompt the user to set 
+				 *  any break points.  */
+				int pendingPromptIsolate = -1;
+				if ( m_lastPromptIsolate != -1 && ( getPromptState(m_lastPromptIsolate) != InitialPromptState.DONE ) ) {
+					pendingPromptIsolate = m_lastPromptIsolate;
+				} else {
+					pendingPromptIsolate = hasPendingInitialPrompts();
+				}
+				if ( pendingPromptIsolate != -1) {
+					dumpInitialPrompt(pendingPromptIsolate);
+				}
+			}
+		}
+
+	    while(!stop)
+		{
+			// allow keyboard input
+			if (!nowait)
+				m_keyboardReadRequest = true;
+			int pendingResumeId = hasAnyPendingResumes();
+			if (pendingResumeId != -1)
+			{
+				// resume execution (request fulfilled) and look for keyboard input
+				try
+				{
+					IsolateSession workerSession = m_session.getWorkerSession(pendingResumeId);
+					//if (m_stepResume)
+					if (getStepResume(pendingResumeId))
+						workerSession.stepContinue();
+					else {
+						workerSession.resume();
+					}
+					/** The user is done setting initial breakpoints for this isolate,
+					 *  clear any pending initial prompts */
+					setPromptState(InitialPromptState.DONE, pendingResumeId);
+					removeBreakIsolate(pendingResumeId);
+				}
+				catch(NotSuspendedException nse)
+				{
+					err(getLocalizationManager().getLocalizedTextString("playerAlreadyRunning")); //$NON-NLS-1$
+				}
+
+				setRequestResume(false, pendingResumeId);
+				setRequestHalt(false, pendingResumeId);
+				setStepResume(false, pendingResumeId);
+//				m_requestResume = false;
+//				m_requestHalt = false;
+//				m_stepResume = false;
+			}
+
+			// sleep for a bit, then process our events.
+			try { Thread.sleep(update); } catch(InterruptedException ie) {}
+			processEvents();
+
+			// lost connection?
+			if (!haveConnection())
+			{
+				stop = true;
+				dumpHaltState(false);
+			}
+			else if (hasAnythingSuspended())
+			{
+				/**
+				 * We have stopped for some reason.  Now for all cases, but conditional
+				 * breakpoints, we should be done.  For conditional breakpoints it
+				 * may be that the condition has turned out to be false and thus
+				 * we need to continue
+				 */
+
+				/**
+				 * Now before we do this see, if we have a valid break reason, since
+				 * we could be still receiving incoming messages, even though we have halted.
+				 * This is definately the case with loading of multiple SWFs.  After the load
+				 * we get info on the swf.
+				 */
+				if (m_breakIsolates.size() > 0) {
+					targetIsolate = m_breakIsolates.get(m_breakIsolates.size() - 1);
+				}
+				else {
+					targetIsolate = Isolate.DEFAULT_ID;
+				}
+				int tries = 3;
+				IsolateSession workerSession = m_session.getWorkerSession(targetIsolate);
+				while (tries-- > 0 && workerSession.suspendReason() == SuspendReason.Unknown)
+					try { Thread.sleep(100); processEvents(); } catch(InterruptedException ie) {}
+
+				dumpHaltState(false);
+				//if (!m_requestResume)
+				if (!getRequestResume(targetIsolate))
+					stop = true;
+			}
+			else if (nowait)
+			{
+				stop = true;  // for DEBUG only
+			}
+			else
+			{
+				/**
+				 * We are still running which is fine.  But let's see if the user has
+				 * tried to enter something on the keyboard.  If so, then we need to
+				 * stop
+				 */
+				if (!m_keyboardInput.isEmpty() && System.getProperty("fdbunit")==null) //$NON-NLS-1$
+				{
+					// flush the queue and prompt the user if they want us to halt
+					m_keyboardInput.clear();
+					try
+					{
+						if (yesNoQuery(getLocalizationManager().getLocalizedTextString("doYouWantToHalt"))) //$NON-NLS-1$
+						{
+							out(getLocalizationManager().getLocalizedTextString("attemptingToHalt")); //$NON-NLS-1$
+							IsolateSession workerSession = m_session.getWorkerSession(m_activeIsolate);
+							workerSession.suspend();
+//							m_session.suspend();
+							getIsolateState(m_activeIsolate).m_requestHalt = true;
+
+							// no connection => dump state and end
+							if (!haveConnection())
+							{
+								dumpHaltState(false);
+								stop = true;
+							}
+							else if (!workerSession.isSuspended()

<TRUNCATED>